Using Request-Reply
Overview
This chapter describes the IBM webMethods Broker API for implementing applications that use the request-reply event processing model. Reading this chapter will help you to understand:
- The use of event tag fields to match request events that are sent with reply events that are received.
- The various types of reply events.
- Using get-event, callback, and the awPublishRequestAndWait approaches in implementing a requestor application.
- Using the reply functions in implementing a request server application.
The Request-Reply Model
You can use the request-reply model for applications that publish or deliver a request event to a server application which is expected to return a reply event. The reply event may contain data or may simply be an acknowledgment with no data.

Request Events and the Tag Field
A tag envelope field is set by your requestor application to identify the request event that it is sending. When a server application receives the request event and prepares the reply event, it ensures that the same tag field is set for the reply as was received on the request event. If your requestor sends several different request events, it should set each with a different tag field. When your requestor receives a reply event, it can check the tag field to determine the original request with which the reply is associated.
Getting and Setting the Tag
| To... | Use this method... |
|---|---|
Obtain the tag field from an
event |
awGetEventTag |
Set an event's tag field |
awSetEventTag |
Using the trackId Field
The trackId envelope
field can be set by a publishing client application to a unique
identifier that will allow the event to be tracked. The use of this
envelope field allows an event that is received and then re-published
to still be tracked. This envelope field also allows you to track
several events that may be associated with a single logical transaction.
trackId envelope
field is not set, any of the IBM webMethods Broker functions for delivering reply events
will automatically set it to the value contained the pubId envelope field.Reply Events
The content of a reply event can vary, depending on the design of the requestor and server applications. The request event's infoset defines the reply event that is expected.
A reply event may take one of the following forms:
- A null event that has no data.
- An acknowledgment that indicates the operation was successful.
- A single reply event containing application-defined data.
- A series of reply events containing application-defined data.
- An error reply.
If a series of reply events are returned,
the appSeqn and appLastSeqn envelope
fields may be accessed to determine the event's sequence position.
See Envelope Fields for
more information.
Determining a Reply Event's Type
The following functions are provided to help your client application determine what type of reply event has been received.
| To... | Use this function... |
|---|---|
| Determine if an event is an acknowledgment reply | awIsAckReplyEvent |
| Determine if an event is an error reply. | awIsErrorReplyEvent |
| Determine if an event is the last reply in a sequence | awIsLastReplyEvent |
| Determine if an event is an null reply | awIsNullReplyEvent |
The Requestor
You have several processing models to choose from when designing a requestor application. These design alternatives include:
- Use awPublishEvent to send the request event, use awGetEvent to receive possible reply events, and check each event received for a matching tag.
- Create a callback function for the response event and register it with awRegisterCallbackWithTag, specifying the tag you will use. Use awPublishEvent to send the request event and then use one of the IBM webMethods Broker dispatching functions to dispatch received events.
- Use awPublishRequestAndWait to send the request event and wait until a reply event is received.
The following example shows the code that implements the preliminary processing for requestor applications. It follows these steps:
- Create a
BrokerClient. - Check for publication permission for the request event type.
- Check for subscription permission for the reply event type. This is done even though the reply event will be delivered because it indicates whether or not the requestor's client group will allow it to receive the reply event type.
- Create a request
BrokerEvent. - Create a tag for the request event using the awMakeTag function.
- Set the request event's tag field using the awSetEventTag function.
. . .
BrokerClient c;
BrokerEvent e;
BrokerBoolean b;
int request_tag;
. . .
/* Create a client */
err = awNewBrokerClient(broker_host, broker_name, NULL
"default", "Reqestor", NULL, &c);
/* Check for errors */
. . .
/* Check if can publish */
err = awCanPublish(c, "Sample::Request", &b);
/* Check for errors */
. . .
/* Check if can subscribe */
err = awCanSubscribe(c, "Sample::Reply", &b);
/* Check for errors */
. . .
/* Create the request event */
err = awNewBrokerEvent(c, "Sample::Request", &e);
/* Check for errors */
. . .
/* Create tag and set tag field */
request_tag = awMakeTag(c);
err = awSetEventTag(e, request_tag);
/* Check for errors */
. . .
Using the Get-event Approach
After the preliminary processing described in The Requestor has been completed, the get-event design involves these steps:
- Use awPublishEvent to publish the request.
- Enter a processing loop and receive events with awGetEvent.
- Use awGetEventTag to check each received event for a tag that matches the request event's tag.
The following example shows how the awGetEvent function could be used to receive a reply event.
. . .
BrokerClient c;
BrokerEvent e;
BrokerBoolean b;
int request_tag;
. . .
/* Create a client */
err = awNewBrokerClient(broker_host, broker_name, NULL
"default", "R
eqestor", NULL, &c);
/* Check for errors */
. . .
/* Check if can publish */
err = awCanPublish(c, "Sample::Request", &b);
/* Check for errors */
. . .
/* Check if can subscribe */
err = awCanSubscribe(c, "Sample::Reply", &b);
/* Check for errors */
. . .
/* Create the request event */
err = awNewBrokerEvent(c, "Sample::Request", &e);
/* Check for errors */
. . .
/* Create tag and set tag field */
request_tag = awMakeTag(c);
err = awSetEventTag(e, request_tag);
/* Check for errors */
. . .BrokerClient c;BrokerEvent e;BrokerBoolean done;
long received_tag, request_tag;
. . .
/* Create BrokerClient, check subscription and publish permissions,
* create request BrokerEvent, create tag, set tag field
*/
. . .
/* Publish the request */
err = awPublishEvent(c, e);
/* check for errors ... */
. . .
/* Loop getting events */
done = 0;
while(!done) {
err = awGetEvent(c,AW_INFINITE,&e);
if (err != AW_NO_ERROR) {
printf(" Error on awGetEvent\n");
return 0;
}
err = awGetEventTag(e,&received_tag);
if (err != AW_NO_ERROR) {
printf(" Error on awGetEventTag\n");
} else if (request_tag == received_tag) {
if (awIsNullReplyEvent(e)) {
printf("Null reply received.\n");
}else if (awIsAckReplyEvent(e)) {
printf("Ack reply received.\n");
}else if ( awIsErrorReplyEvent(e)) {
printf("Error reply received.\n");
} else {
/* process the event */
. . .
}
done = awIsLastReplyEvent(e);
}
awDeleteEvent(e);
}
. . .
Other Reply Event Functions
Procedure
- Use awIsLastReplyEvent to determine if a reply event is the last in a sequence.
-
Use awIsNullReplyEvent to determine if a reply
event is null reply event. This is indicated by the envelope fields
appSeqnandappLastSeqnboth being equal to -1.
Callback Functions with Tags
After the preliminary processing described in The Requestor has been completed, the callback design involves these steps:
- Use awPublishEvent to publish the request.
- Use awRegisterCallback to register a general callback.
- Use awRegisterCallbackForTag to register a specific callback for the reply event with the request event's tag.
- Use one of the callback dispatching functions, described on Dispatching Callback Functions, to receive events and dispatch the appropriate callback function.
The following example shows how you could use the callback function to receive a reply event with a callback function:
. . .
BrokerBoolean test_callback1(BrokerClient c, BrokerEvent e,void *data);
int main(int argc, char **argv)
{
BrokerClient c;
BrokerEvent e;
long request_tag;
BrokerBoolean done = 0;
. . .
/* Publish request */
err = awPublishEvent(c,e);
/* check for errors ... */
/* Register general callback */
err = awRegisterCallback(c,test_callback1,"general");
if (err != AW_NO_ERROR) {
printf("Error on awRegisterCallback\n");
return 0;
}
err = awRegisterCallbackForTag(c,request_tag,1,test_callback1,
"tag matched");
if (err != AW_NO_ERROR) {
printf("Error on awRegisterCallback #2\n");
return 0;
}
/* Dispatch loop */
while(!done) {
err = awDispatch(AW_INFINITE);
if (err != AW_NO_ERROR) {
printf(" Error on awDispatch\n");
return 0;
}
}
. . .
}
BrokerBoolean test_callback1(BrokerClient c, BrokerEvent e,void *data)
{
char *st;
if (awIsNullReplyEvent(e)) {
printf("Null reply received.\n");
} else if (awIsErrorReplyEvent(e)) {
printf("Error reply received.\n");
} else {
/* process the event */
. . .
}
return 1;
}
Using awPublishRequestAndWait
After the preliminary processing described in The Requestor has been completed, the callback approach involves the following steps:
- Use awRegisterCallback to register a general callback.
- Use awPublishRequestAndWait to
publish the request and wait for the reply.Note: No event subscription is necessary in this model because the awPublishRequestAndWait function requires that the reply event be delivered, not published
The following example shows how you can awPublishRequestAndWait:
. . .
BrokerBoolean test_callback1(BrokerClient c, BrokerEvent e,void *data);
int main(int argc, char **argv)
{
BrokerClient c;
BrokerEvent e;
BrokerEvent *events;
long n;
. . .
/* Register general callback */
err = awRegisterCallback(c,test_callback1,"general");
/* check for errors */
. . .
err = awPublishRequestAndWait(c, e, 6000, &n, &events);
/* check for errors */
. . .
/* Process received events */
for( i = 0; i < n; i++) {
if (awIsNullReplyEvent(events[n])) {
printf("Null reply received.\n");
} else if (awIsErrorReplyEvent(events[n])) {
printf("Error reply received.\n");
} else {
/* process the event */
. . .
}
awDeleteEvent(events[n]);
}
free(events);
. . .
Delivering Request Events
You can use theawDeliverRequestAndWait function if you wish
to send a request event to a single Broker client. This function creates a
value for the tag envelope
field using awMakeTag function and blocks until
all reply events are received or until the requested time-out interval expires.
The Server
Server applications must be allowed to subscribe to all of the event types that are to be processed. In response to a request event, servers must also be prepared to deliver a reply event of the expected type. Generally, your server application should follow these steps:
- Check for permission to subscribe to the request event type(s).
- Check for the appropriate reply event publishing permissions.
- Retrieve an event and process it.
- Deliver the appropriate reply event(s).
Checking Subscription and Publishing Permissions
The server shown in the example below checks to see if it has permission to subscribe to the request event and to deliver the appropriate reply event. The awCanPublish function is used to determine if the Broker client has the necessary permissions to deliver the various reply events. In the following example, the application expects that it might have to deliver the following event types:
| Event Type | Description |
|---|---|
Adapter::error
|
Used to indicate that an exception occurred in the processing of the event. |
Adapter::ack
|
Used if the infoset
for Sample::Request specifies
that a simple success or failure indication is all that is expected. |
Sample::Reply
|
Used if the infoset
for Sample::Request defines a
specific event type as a response. |
The following example shows how the awCanPublish function is used to check event publishing and subscription permissions:
BrokerBoolean b;
BrokerClient c;
. . .
/* Create a client */
. . .
/* Check if can publish */
err = awCanPublish(c,"Sample::Reply",&b);
if (err != AW_NO_ERROR) {
printf("Error on awCanPublish\n");
return 0;
}
if (b == 0) {
printf("got false on awCanPublish for Sample::Reply\n");
return 0;
}
err = awCanPublish(c,"Adapter::error",&b);
if (err != AW_NO_ERROR) {
printf("Error on awCanPublish\n");
return 0;
}
if (b == 0) {
printf("got false on awCanPublish for Adapter::error\n");
return 0;
}
err = awCanPublish(c,"Adapter::ack",&b);
if (err != AW_NO_ERROR) {
printf("Error on awCanPublish\n");
return 0;
}
if (b == 0) {
printf("got false on awCanPublish for Adapter::ack\n");
return 0;
}
/* Check if can subscribe to the request event */
err = awCanSubscribe(c,"Sample::Request",&b);
if (err != AW_NO_ERROR) {
printf("Error on awCanSubscribe\n");
return 0;
}
if (b == 0) {
printf("got false on awCanSubscribe\n");
return 0;
}
/* Subscribe to the request event */
err = awNewSubscription(c,"Sample::Request",NULL);
if (err != AW_NO_ERROR) {
printf("Error on awNewSubscription\n");
return 0;
}
. . .
Processing Request Events
Your server application has all of the usual options for receiving and processing events. It can use the awGetEvent function to receive events within a manually coded loop, described in Using Request-Reply. If your server subscribes to several request event types, it can use the callback model described in Using the Callback Model.
The server application may also associate an identifier with each of the subscriptions that it registers. When an event is received, the server application can easily determine how to process the request event. See Subscription Identifiers for more information.
The following example below shows an excerpt of a server application that uses the awGetEvent function to receive an event and determines if it is a request event:
. . .
/* Loop getting events */
n = 1;
while(n < count) {
err = awGetEvent(c,AW_INFINITE,&e);
if (err != AW_NO_ERROR) {
printf("Error on awGetEvent\n"); return 0;
}
/* Check if it is a request */
event_type_name = awGetEventTypeName(e);
if ((event_type_name != NULL) &&
(strcmp(event_type_name,"Sample::Request")==0)) {
/* Process the request (see excerpts that follow) */
. . .
}
free(event_type_name);
}
. . .
Delivering Replies
Once you have processed a request event, you can use one of several functions to deliver the appropriate type of reply event.
pubId field of the
original request event. None of these functions will return an error
if the destination identifier refers to a Broker client that no longer exists.Delivering Acknowledgment Replies
Your server application may deliver an acknowledgment reply if the infoset for the request event type defines that a simple success or failure indication is all that is required. When invoking the awDeliverAckReplyEvent function, you may either specify a valid publish sequence number or specify a value of zero if you do not wish to use publish sequence numbers. For more information, see Using Sequence Numbers.
The following example illustrates how to use awDeliverAckReplyEvent to deliver an acknowledgment reply:
. . .
err = awDeliverAckReplyEvent(c,e,0);
if (err != AW_NO_ERROR) {
printf("Error on awDeliverAckReplyEvent\n");
return 0;
}
. . .
Delivering Error Replies
The server application delivers an error reply to indicate that some sort of exception occurred while attempting to process the request event, as illustrated in the following example:
. . .
/* Make error reply event */
err = awNewBrokerEvent(c,"Adapter::error",
&err_event);
if (err != AW_NO_ERROR) {
printf("Error on awNewBrokerEvent\n");
return 0;
}
err = awDeliverErrorReplyEvent(c,e,err_event);
if (err != AW_NO_ERROR) {
printf(" Error on awDeliverErrorReplyEvent\n");
return 0;
}
awDeleteEvent(err_event);
. . .
Delivering Null Replies
The server application may deliver a null reply if the request was successfully processed and there are no data to be returned. When invoking the awDeliverNullReplyEvent function, you may either specify a valid publish sequence number or specify a value of zero if you do not wish to use publish sequence numbers. For more information, see Using Sequence Numbers.
The following example shows the delivery of a null reply:
. . .
printf("Delivering null reply to requestor\n");
err = awDeliverNullReplyEvent(c,e,"Sample::Reply",0);
if (err != AW_NO_ERROR) {
printf("Error on awDeliverNullReplyEvent\n");
return 0;
}
. . .
Delivering One or More Reply Events
Your server application may deliver one or more reply events in response to a single request event by calling the awDeliverReplyEvent or awDeliverReplyEvents function. The following example shows how to send multiple reply events using awDeliverReplyEvents:
. . .
long num;
BrokerEvent *reply_events;
. . .
/* prepare the reply events */
. . .
/* deliver the replies */
err = awDeliverReplyEvents(c,e,num, reply_events);
if (err != AW_NO_ERROR) {
printf("Error on awDeliverReplyEvents\n");
return 0;
}
. . .
Delivering Partial Replies
Your server application may need to deliver multiple reply events to satisfy a request event that it receives. If all of the reply event data cannot be read into memory or is not immediately available, the server may choose to send the reply events in batches rather than all at once.
The awDeliverPartialReplyEvents function
can be used in these cases. You must set the flag parameter to AW_REPLY_FLAG_START, AW_REPLY_FLAG_CONTINUE,
or AW_REPLY_FLAG_END to
indicate the start, continuation, and end of the reply event sequence.
If all of the replies can be sent in one batch, simply set the flag to AW_REPLY_FLAG_START_AND_END.
The following example shows the delivery of partial replies:
. . .
flag = AW_REPLY_FLAG_START;
while(!done) {
/* Send the replies */
err = awDeliverPartialReplyEvents(c,e,num,
reply_events,flag,&token);
if (err != AW_NO_ERROR) {
printf("Error on awDeliverPartialReplyEvents\n");
return 0;
}
flag = AW_REPLY_FLAG_CONTINUE;
}
flag = AW_REPLY_FLAG_END;
/* prepare the last event */
. . .
/* Send the last reply */
err = awDeliverPartialReplyEvents(c,e,num,
reply_events,flag,&token);
if (err != AW_NO_ERROR) {
printf("Error on awDeliverPartialReplyEvents\n");
return 0;
}
. . .