This section describes how you use the C-API to complete the following tasks:
Compose a message
Send a message
Receive a message
Process a message
You can create either a text message or a bytes message. A message, whether text or bytes, is composed of a header, properties, and a body. You can also create a message type which has no body.
Table 2–6 lists the functions you use to construct messages.
Table 2–6 Functions Used to Construct Messages
Function |
Description |
---|---|
Creates an MQ_MESSAGE type message. |
|
Creates an MQ_BYTES_MESSAGE message. |
|
Creates an MQ_TEXT_MESSAGE message. |
|
Sets message header properties. (Optional) |
|
Sets user-defined message properties. |
|
Sets the body of an MQ_TEXT_MESSAGE message. |
|
Sets the body of an MQ_BYTES_MESSAGE message. |
|
Specifies the destination where replies to this message should be sent. |
A header is required of every message. Header fields contain values used for routing and identifying messages.
Some header field values are set automatically by Message Queue during the process of producing and delivering a message, some depend on settings specified when message producers send a message, and others are set on a message-by-message basis by the client using the MQSetMessageHeader function. Table 2–7 lists the header fields defined (and required) by JMS and their corresponding names, as defined by the C-API.
Table 2–7 JMS-defined Message Header
For additional information about each property type and who sets it, see MQSetMessageHeaders.
JMS specifies six classes (or types) of messages. The C-API supports only three of these types, as described in Table 2–8. If a Message Queue C client expects to receive messages from a Message Queue Java client, it will be unable to process messages whose body types are other than those described in the table. It will also be unable to process messages that are compressed by the Message Queue Java client runtime.
Table 2–8 C-API Message Body Types
Create a message using either the MQCreateBytesMessage() function or the MQCreateTextMessage() function. Either of these functions returns a message handle that you can then pass to the functions you use to set the message body, header, and properties (listed in Composing Messages()). You can also use the MQCreateMessage() function to create a message that has a header and properties but no message body.
Use the MQSetTextMessageText() function to define the body of a text message; use the MQSetBytesMessageBytes() function to define the body of a bytes message.
Use the MQSetMessageHeaders() to set any message header properties.
The message header can specify up to eight properties; most of these are set by the client runtime when sending the message or are set by the broker. The client can set MQ_CORRELATION_ID_HEADER_PROPERTY and MQ_MESSAGE_TYPE_HEADER_PROPERTY for sending a message.
Use the MQSetMessageProperties() function to set any user-defined properties for this message.
When you set message header properties or when you set additional user-defined properties, you must pass a handle to a properties object that you have created using the MQCreateProperties() function. For more information, see Working With Properties.
You can use the MQSetMessageReplyTo() function to associate a message with a destination that recipients can use for replies. To do this, you must first create a destination that will serve as your reply-to destination. Then, pass a handle to that destination when you call the MQSetMessageReplyTo() function. The receiver of a message can use the MQGetMessageReplyTo() function to determine whether a sender has set up a destination where replies are to be sent.
Messages are sent by a message producer within the context of a connection and a session. Once you have obtained a connection, created a session, and composed your message, you can use the functions listed in Table 2–9to create a message producer and to send the message.
Which function you choose to send a message depends on the following factors:
Whether you want the send function to override certain message header properties
Send functions whose names end in Ext allow you to override default values for priority, time-to-live, and delivery mode header properties.
Whether you want to send the message to the destination associated with the message producer
If you created a message producer with no specified destination, you must used one of the ...ToDestination send functions. If you created a message producer with a specified destination, you must use one of the other send functions.
Function |
Action |
Creates a message producer with no specified destination. |
|
Creates a message producer with a specified destination. |
|
Sends a message for the specified producer. |
|
Sends a message for the specified producer and allows you to set priority, time-to-live, and delivery mode. |
|
Sends a message to the specified destination. |
|
Sends a message to the specified destination and allows you to set priority, time-to-live, and delivery mode. |
If you send a message using one of the functions that does not allow you to override header properties, the following message header fields are set to default values by the send function.
MQ_PERSISTENT_HEADER_PROPERTY will be set to MQ_PERSISTENT_DELIVERY.
MQ_EXPIRATION_HEADER_PROPERTY will be set to 0, which means that the message will never expire.
To override these values, use one of the extended send functions. For a complete list of message header properties, see MQGetMessageHeaders .
Message headers also contain fields that can be set by the sending client; in addition, you can set user-defined message properties as well. For more information, see Composing Messages.
You can set the connection property MQ_ACK_ON_PRODUCE_PROPERTY when you create the connection to make sure that the message has reached its destination on the broker:
By default, the broker acknowledges receiving persistent messages only.
If you set the property to MQ_TRUE, the broker acknowledges receipt of all messages (persistent and non-persistent) from the producing client.
If you set the property to MQ_FALSE, the broker does not acknowledge receipt of any message (persistent or non-persistent) from the producing client.
Note that “acknowledgement” in this case is not programmatic but internally implemented. That is, the client thread is blocked and does not return until the broker acknowledges messages it receives.
An administrator can set a broker limit, REJECT_NEWEST, which allows the broker to avert memory problems by rejecting the newest incoming message. If the incoming message is persistent, then an error is returned which the sending client should handle, perhaps by retrying the send a bit later. If the incoming message is not persistent, the client has no way of knowing that the broker rejected it. The broker might also reject a message if it exceeds a specified limit.
Messages are received by a message consumer in the context of a connection and a session. In order to receive messages, you must explicitly start the connection by calling the MQStartConnection function.
Table 2–10 lists the functions you use to create message consumers and to receive messages.
Table 2–10 Functions Used to Receive Messages
Function |
Description |
---|---|
Creates the specified synchronous consumer and passes back a handle to it. |
|
Creates a durable synchronous message consumer for the specified destination. |
|
Creates an asynchronous message consumer for the specified destination. |
|
Creates a durable asynchronous message consumer for the specified destination. |
|
Unsubscribes the specified durable message consumer. |
|
Passes a handle back to a message delivered to the specified consumer if a message is available; otherwise it returns an error. |
|
Passes a handle back to a message delivered to the specified consumer if a message is available; otherwise it blocks until a message becomes available. |
|
Passes a handle back to a message delivered to the specified consumer if a message is available within the specified amount of time. |
|
Acknowledges the specified message and all messages received before it on the same session |
|
Closes the specified consumer. |
When you create a consumer, you need to make several decisions:
Do you want to receive messages synchronously or asynchronously?
If you create a synchronous consumer, you can call one of three kinds of receive functions to receive your messages. If you create an asynchronous consumer, you must specify the name of a callback function that the client runtime can call when a message is delivered to the destination for that consumer. For information about the callback function signature, see Callback Type for Asynchronous Messaging .
If you are consuming messages from a topic, do you want to use a durable or a nondurable consumer?
A durable consumer receives all the messages published to a topic, including the ones published while the subscriber is inactive. A nondurable consumer only receives messages while the subscriber is active.
The broker retains a record of this durable subscription and makes sure that all messages from the publishers to this topic are retained until they are either acknowledged by this durable subscriber or until they have expired. Sessions with durable subscribers must always provide the same client identifier. In addition, each consumer must specify a durable name using the durableName parameter, which uniquely identifies (for each client identifier) each durable subscription it creates.
A session’s consumers are automatically closed when you close the session or connection to which they belong. However, messages will be routed to the durable subscriber while it is inactive and delivered when a new durable consumer is recreated. To close a consumer without closing the session or connection to which it belongs, use the MQCloseMessageConsumer() function. If you want to close a durable consumer permanently, you should call the function MQUnsubscribeDurableMessageConsumer after closing it, to delete state information maintained by the broker on behalf of the durable consumer.
If you have created a synchronous consumer, you can use one of three receive functions: MQReceiveMessageNoWait, MQReceiveMessageWait , or MQReceiveMessagewithTimeOut. In order to use any of these functions, you must have specified MQ_SESSION_SYNC_RECEIVE for the receive mode when you created the session.
When you create a session you must specify one of several acknowledge modes for that session. If you specify MQ_CLIENT_ACKNOWLEDGE as the acknowledge mode for the session, you must explicitly call the MQAcknowledgeMessages function to acknowledge messages that you have received. If the session is transacted, the acknowledge mode parameter is ignored.
When the receiving function returns, it gives you a handle to the delivered message. You can pass that handle to the functions described in Processing a Message, in order to read message properties and information stored in the header and body of the message.
It is possible that a message can be lost for synchronous consumers in a session using AUTO_ACKNOWLEDGE mode if the provider fails. To prevent this possibility, you should either use a transacted session or a session in CLIENT_ACKNOWLEDGE mode.
Because distributed applications involve greater processing time, such an application might not behave as expected if it were run locally. For example, calling the MQReceiveMessageNoWait function might return MQ_NO_MESSAGE even when there is a message available to be retrieved on the broker. See the usage notes provided in the section MQReceiveMessageNoWait for more information.
To receive a message asynchronously, you must create an asynchronous message consumer and pass the name of an MQMessageListenerFunc type callback function. (Therefore, you must set up the callback function before you create the asynchronous consumer that will use it.) You should start the connection only after creating an asynchronous consumer. If the connection is already started, you should stop the connection before creating an asynchronous consumer.
You are also responsible for writing the message listener function. Mainly, the function needs to process the incoming message by examining its header, body, and properties, or it needs to pass control to a function that can do this processing. The client is also responsible for freeing the message handle (either from within the listener or from outside of the listener) by calling the MQFreeMessage function.
When you create a session you must specify one of several acknowledge modes for that session. If you specify MQ_CLIENT_ACKNOWLEDGE as the acknowledge mode for the session, you must explicitly call the MQAcknowledgeMessages function to acknowledge messages that you have received.
For more information about the signature and content of a call back function, see Callback Type for Asynchronous Messaging.
When the callback function is called by the session delivery of a message, it gives you a handle to the delivered message. You can pass that handle to the functions described in Processing a Message, in order to read message properties and information stored in the header and body of the message.
When a message is delivered to you, you can examine the message’s properties, type, headers, and body. The functions used to process a message are described in Processing a Message.
Table 2–11 Functions Used to Process Messages
Function |
Description |
Gets message header properties. |
|
Gets user-defined message properties. |
|
Gets the message type: MQ_TEXT_MESSAGE or MQ_BYTES_MESSAGE |
|
Gets the body of an MQ_TEXT_MESSAGE message. |
|
Gets the body of an MQ_BYTES_MESSAGE message. |
|
Gets the destination where replies to this message should be sent. |
If you are interested in a message’s header information, you need to call the MQGetMessageHeaders function. If you need to read or check any user-defined properties, you need to call the MQGetMessageProperties function. Each of these functions passes back a properties handle. For information on how you can read property values, see Getting Message Properties.
Before you can examine the message body, you can call the MQGetMessageType function to determine whether the message is a text or bytes message. You can then call the MQGetTextMessageText, or the MQGetBytesMessageBytes function to get the contents of the message.
Some message senders specify a reply destination for their message. Use the MQGetMessageReplyTo function to determine that destination.