Using the Callback Model

Overview

This chapter describes the IBM webMethods Broker callback API for receiving and processing events. Reading this chapter will help you to understand:

  • How to register general and specific callback functions.
  • How to define a callback function.
  • How to retrieve and process events from the Broker using callback functions.

Understanding Callbacks

The callback model for processing event types allows your client application to register one or more callback functions to process event types for a Broker client.Unlike the get-events model, which can only process event types for one Broker client at a time, the callback model can receive any event type for any of your client application's Broker clients and then dispatch it to the appropriate callback function. If your client application creates several Broker clients, using the callback model frees your application from making separate calls to one of the IBM webMethods Broker get-event functions for each Broker client.

Using Callbacks

About this task

Follow these steps to use the callback processing model:

Procedure

  1. Use awCanSubscribe to verify that the desired subscriptions are allowed.
  2. Use one or more of the following to register the subscriptions:
    • awNewSubscription
    • awNewSubscriptionWithId
    • awNewSubscriptionFromStruct
    • awNewSubscriptionsFromStructs
  3. Use awRegisterCallback to register a general callback function.
  4. Next, you can optionally register any specific callback functions you desire, using:
    • awRegisterCallbackForSubId
    • awRegisterCallbackForTag
  5. Process events using one of the following:
    • awDispatch
    • awMainLoop
    • awThreadedCallbacks
  6. Cancel all the callbacks using:
    • awCancelCallbacks
    • awCancellCallbackForSubId
    • awCancelCallbackForTag
  7. Cancel all the subscriptions using:
    • awCancelSubscription
    • awCancelSubscriptionFromStruct
    • awCancelSubscriptionsFromStructs

Defining a Callback Function

All callback functions that you register must use the following function prototype:

BrokerBoolean <your_function_name_goes_here>(  
  BrokerClient client,  
  BrokerEvent event,  
  void *client_data);
Value Description
client The client for which the event has been received.
event The event that is being dispatched to this function.
client_data A pointer to any data that you wish to be passed to this function when it is invoked.

Your function should return 1 (true) if its processing was successful or 0 (false) if a failure occurred. If 1 (true) is returned, the event will be acknowledged automatically. For information on acknowledging events, see Using Sequence Numbers.

Important: Any event that is passed to a callback function will be automatically deleted after the callback returns. Your callback function should not call awDeleteEvent. If you wish to save a copy of the event, your callback must use the awCopyEvent function.

Passing Arguments to Callback Functions

When you register your callback function, you may specify a client_data pointer to any user-defined data that may be necessary for the function to complete its processing. The client_data parameter might be used to point to state information that the callback function must access and update each time it is invoked.

Assume that you want to count the number of events that your application processes. When you register your callback function, you could use the client_data pointer to point to the counter variable. When the callback is invoked, it can increment the counter.

The following example illustrates how to set up an argument for a callback function.

BrokerBoolean sample_callback(BrokerClient c, BrokerEvent e, void *counter);  
long count = 0;  
. . .  
int main(int argc, char **argv)  
{  
  BrokerClient c;  
  long n;  
  . . .  
  /* Check if can subscribe */  
  . . .  
  /* Register callback */  
  err = awRegisterCallbackForSubId(c, 1, sample_callback, &n);  
  if (err != AW_NO_ERROR) {  
  printf("Error on registering callback\n%s\n", awErrorToString(err));  
  return 0;  
  }  
. . .

The following example illustrates how to use the client data parameter in a callback function:

BrokerBoolean sample_callback(BrokerClient c, BrokerEvent e,  
        void *counter)  
{  
  /* increment counter */  
  (*(long*)counter)++;  
  /* perform rest of event processing */  
  . . .  
}

General Callback Functions

When using the callback model, you must register a general callback function for each Broker client by calling the awRegisterCallback function. When an event is received, if there are no specific callback functions registered which match the event's subscription identifier or tag, the general callback function will be invoked to handle the event.

You may have a single callback function process all of your application's events by making a separate awRegisterCallback call for each BrokerClient that your application uses, specifying the same callback function each time.

Depending on the complexity of your design, you may find that a single, general callback function is all that your client application requires.

Note: You must register a general callback function before registering any specific callback function.

Using General Callbacks

The example below illustrates the use of the awRegisterCallback function to register a general callback function.

The following example illustrates how to process events with a general callback function.

. . .  
BrokerBoolean sample_callback(BrokerClient c, BrokerEvent e, void *data);  
. . .  
/* Create a client */  
. . .  
/* Check if can subscribe */  
. . .  
/* Register a general callback */  
err = awRegisterCallback(c, sample_callback, NULL);  
if (err != AW_NO_ERROR) {  
  printf("Error on registering callback\n%s\n", awErrorToString(err));  
  return 0;  
}  
/* Open the subscription */  
err = awNewSubscription(c,"Sample::SimpleEvent",NULL);  
. . .  
/* Do the main loop */  
err = awMainLoop();  
if (err != AW_NO_ERROR) {  
  printf("Error in main loop\n%s\n",awErrorToString(err));  
  return 0;  
}  
. . .

Specific Callback Functions

Depending on the complexity of your design, you may find that a single, general callback function is all that your client application requires. More complicated designs may need to make use of specific callback functions.

A specific callback function is only invoked to process an event with a particular subscription identifier or event tag for a particular Broker client. You may register a specific callback function by calling either the awRegisterCallbackForSubId or awRegisterCallbackForTag.

Event tag fields are part of the request-reply model, described in Using Request-Reply.

Note: If a received event matches the criteria for more than one callback, each callback function will be invoked to handle the event. The event will be automatically deleted after the last callback function returns.

Using Specific Callbacks

The example below illustrates the use of the awRegisterCallbackForSubId function to register a specific callback function.

. . .  
BrokerBoolean general_callback(BrokerClient c, BrokerEvent e,  
        void *data);  
BrokerBoolean specific_callback(BrokerClient c, BrokerEvent e,  
        void *data);  
/* Check if can subscribe */  
. . .  
/* Register a general callback */  
err = awRegisterCallback(c, general_callback, NULL);  
if (err != AW_NO_ERROR) {  
  printf("Error on registering callback\n%s\n", awErrorToString(err));  
  return 0;  
}  
/* Register a specific callback */  
err = awRegisterCallbackForSubId(c, 1, specific_callback, NULL);  
if (err != AW_NO_ERROR) {  
  printf("Error on registering callback\n%s\n", awErrorToString(err));  
  return 0;  
}  
/* Open the subscription with the ID of 1 */  
err = awNewSubscriptionWithId(c, 1, "Sample::SimpleEvent",NULL);  
. . .  
/* Do the main loop */  
err = awMainLoop();  
if (err != AW_NO_ERROR) {  
  printf("Error in main loop\n%s\n",awErrorToString(err));  
  return 0;  
}  
. . .

Dispatching Callback Functions

After registering your subscription's callback functions, your client application should then call one of the IBM webMethods Broker dispatching functions to receive events and dispatch the appropriate callback function to process them. Only one of the following dispatching functions should be used.

Using awDispatch

The awDispatch function may be used to wait to receive a single event for any Broker client, dispatch the event to the appropriate callback function, and then return. The subscribe2.c and subscribe4.c sample applications provide examples of how to use awDispatch.

Using awMainLoop

The awMainLoop function is similar to awDispatch, except that it enters an event loop that will continue to receive and dispatch events until awStopMainLoop is called. The subscribe3.c sample application provides an example of how to use awMainLoop.

Using awThreadedCallbacks

In a multi-threaded environment, the awThreadedCallbacks function will spawn a thread that then invokes awMainLoop. This function simplifies your client application code by handling the thread creation for you.

Invoking awThreadedCallbacks(1) is identical to creating a thread and then invoking the awMainLoop method on that thread.

Invoking awThreadedCallbacks(0) is identical to invoking the awStopMainLoop method.

Event Dispatching Rules

When an event is received in the callback model, the following rules are used to dispatch the event.

  1. If the received event has a tag field and the tag matches a registered callback, the received event is dispatched to that callback function.
  2. If the received event has a subscription identifier, the event is dispatched once to each callback that matches the subscription identifier. If the event matches two event subscriptions with the same subscription identifier, the event will be dispatched twice to the callback function for that identifier.
  3. The received event will be dispatched to the general callback function if the tag did not match any callback and:
    1. At least one subscription identifier did not match a specific callback.
    2. No subscription identifiers were matched because the event was delivered.