Example 2: Publisher to a variable topic

A Websphere MQ program to illustrate publishing to a programmatically defined topic.

Note: The compact coding style is intended for readability not production use.
Figure 1. Simple WebSphere MQ publisher to a variable topic.

See the output in Figure 2.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <cmqc.h>
int main(int argc, char **argv)
{
    char     topicNameDefault[]   = "STOCKS";
    char     topicStringDefault[] = "IBM/PRICE";
    char     publicationDefault[] = "130";
    MQCHAR48 qmName = "";

    MQHCONN  Hconn = MQHC_UNUSABLE_HCONN; /* connection handle       	*/
    MQHOBJ   Hobj     = MQHO_NONE;   /* object handle sub queue      	*/
    MQLONG   CompCode = MQCC_OK;     /* completion code              	*/
    MQLONG   Reason   = MQRC_NONE;   /* reason code                  	*/
    MQOD     td = {MQOD_DEFAULT};    /* Object descriptor            	*/
    MQMD     md = {MQMD_DEFAULT};    /* Message Descriptor           	*/
    MQPMO   pmo = {MQPMO_DEFAULT};   /* put message options          	*/
    MQCHAR   resTopicStr[151];       /* Returned value of topic string */
    char *   topicName   = topicNameDefault;   
    char *   topicString = topicStringDefault;
    char *   publication = publicationDefault;
    memset   (resTopicStr, 0 , sizeof(resTopicStr));

    switch(argc){            /* Replace defaults with args if provided */
        default:
            publication = argv[3];
        case(3):
            topicString = argv[2];
        case(2):
            if (strcmp(argv[1],"/"))  /* "/" invalid = No topic object  */
                topicName = argv[1];
            else
                *topicName = '\0';
        case(1):
            printf("Provide parameters:  TopicObject TopicString Publication\n");
    }

    printf("Publish \"%s\" to topic \"%-.48s\" and topic string \"%s\"\n", publication, topicName, topicString);
    do {
        MQCONN(qmName, &Hconn, &CompCode, &Reason);
        if (CompCode != MQCC_OK) break;
        td.ObjectType = MQOT_TOPIC;    /* Object is a topic             */
        td.Version = MQOD_VERSION_4;   /* Descriptor needs to be V4     */
        strncpy(td.ObjectName, topicName,  MQ_TOPIC_NAME_LENGTH);
        td.ObjectString.VSPtr = topicString;
        td.ObjectString.VSLength = (MQLONG)strlen(topicString);
        td.ResObjectString.VSPtr = resTopicStr;
        td.ResObjectString.VSBufSize = sizeof(resTopicStr)-1;
        MQOPEN(Hconn, &td, MQOO_OUTPUT | MQOO_FAIL_IF_QUIESCING, &Hobj, &CompCode, &Reason);
        if (CompCode != MQCC_OK) break;
        pmo.Options = MQPMO_FAIL_IF_QUIESCING | MQPMO_RETAIN;
        MQPUT(Hconn, Hobj, &md, &pmo, (MQLONG)strlen(publication)+1, publication, &CompCode, &Reason); 
        if (CompCode != MQCC_OK) break;
        MQCLOSE(Hconn, &Hobj, MQCO_NONE, &CompCode, &Reason);
        if (CompCode != MQCC_OK) break;
        MQDISC(&Hconn, &CompCode, &Reason);
    } while (0);
    if (CompCode == MQCC_OK)
        printf("Published \"%s\" to topic string \"%s\"\n",  publication, resTopicStr);
    printf("Completion code %d and Return code %d\n", CompCode, Reason);
}
Figure 2. Sample output from second publisher example
X:\Publish2\Debug>PublishStock
Provide parameters:  TopicObject TopicString Publication
Publish "130" to topic "STOCKS" and topic string "IBM/PRICE"
Published "130" to topic string "NYSE/IBM/PRICE"
Completion code 0 and Return code 0

X:\Publish2\Debug>PublishStock / NYSE/IBM/PRICE 131
Provide parameters:  TopicObject TopicString Publication
Publish "131" to topic "" and topic string "NYSE/IBM/PRICE"
Published "131" to topic string "NYSE/IBM/PRICE"
Completion code 0 and Return code 0
There are a few points to note about this example.
char topicNameDefault[] = "STOCKS";
The default topic name STOCKS defines part of the topic string. You can override this topic name by providing it as the first argument to the program, or eliminate the use of the topic name by supplying / as the first parameter.
char topicString[101] = "IBM/PRICE";
IBM/PRICE is the default topic string. You can override this topic string by providing it as the second argument to the program.
The queue manager combines the topic string provided by the STOCKS topic object, "NYSE", with the topic string provided by the program "IBM/PRICE" and inserts a "/" between the two topic strings. The result is the resolved topic string "NYSE/IBM/PRICE". The resulting topic string is the same as the one defined in the IBMSTOCKPRICE topic object, and has precisely the same effect.
The administrative topic object associated with the resolved topic string is not necessarily the same topic object as passed to MQOPEN by the publisher. WebSphere MQ uses the tree implicit in the resolved topic string to work out which administrative topic object defines the attributes associated with the publication.
Suppose there are two topic objects A and B, and A defines topic "a", and B defines topic "a/b" (Figure 3). If the publisher program refers to topic object A and provides topic string "b", resolving the topic to the topic string "a/b", then the publication inherits its properties from topic object B because the topic matches the topic string "a/b" defined for B.
if (strcmp(argv[1],"/"))
argv[1] is the optionally provided topicName. "/" is invalid as a topic name; here it signifies that there is no topic name, and the topic string is provided entirely by the program. The output in Figure 2 shows the whole topic string being supplied dynamically by the program.
strncpy(td.ObjectName, topicName, MQ_OBJECT_NAME_LENGTH);
For the default case, the optional topicName needs to be created beforehand, using WebSphere MQ Explorer or this MQSC command:
DEFINE TOPIC(STOCKS) TOPICSTR(NYSE) REPLACE;
td.ObjectString.VSPtr = topicString;
The topic string is a MQCHARV field in the topic descriptor
Figure 3. Topic object associations
Topic object A and topic object B define topic string "a" and topic string "a/b" respectively. Topic B has subscribe inhibited. Creating a topic in a program using topic object A and topic string "b" results an association to topic object B, and thus although the program can subscribe to the topic defined by topic object A it cannot subscribe to the topic it defined using topic object A and topic string "b", because the resulting topic string is associated with topic object B, and not topic object A which was used to refer to the topic.

What does the second example demonstrate? Although the code is very similar to the first example - effectively there are only two lines difference - the result is a significantly different program to the first. The programmer controls the destinations to which publications are sent. In conjunction with minimal administrator input used to design subscriber applications, no topics or queues need to be predefined to route publications from publishers to subscribers.

In the point-to-point messaging paradigm, queues have to be defined before messages are able to flow. For publish/subscribe, they do not, although WebSphere MQ implements publish/subscribe using its underlying queuing system; the benefits of guaranteed delivery, transactionality and loose coupling associated with messaging and queueing are inherited by publish/subscribe applications.

A designer has to decide whether publisher, and subscriber, programs are to be aware of the underlying topic tree or not, and also whether subscriber programs are aware of queueing or not. Study the subscriber example applications next. They are designed to be used with the publisher examples, typically publishing and subscribing to NYSE/IBM/PRICE.