![]() | JetNet/Oracle Tuxedo Guide | ![]() |
In JetNet and Oracle Tuxedo applications, events occur during the processing of service requests. These middleware events are one of several categories of events that occur in a Panther application. For information about the different types of application events, refer to Chapter 17, "Understanding Application Events," in Application Development Guide.
When middleware events occur, they are forwarded to handlers for processing. Panther provides built-in event handlers for all request broker event types. You can also write and install your own handlers in JPL or C. These handlers can perform all required processing on their own, or they can call the built-in handlers and overlay these with desired enhancements.
Table 6-1 lists all middleware event types that Panther recognizes in JetNet and Oracle Tuxedo applications:
Event Sequence | ![]() |
During the typical life span of a Panther enterprise application, most or all middleware events occur. Some of these, such as advertise events, happen independently of other events. For example, in an multi-server enterprise, servers can be activated and deactivated in a running application, thereby generating advertise and unadvertise events. In the meantime, clients continue to issue service requests, and those servers that are available process them; these actions spawn their own set of service-related events, such as request_received and unload.
Of all middleware events, only those that are connected to service requests are dependent on each other, and always occur in this sequence:
Handler Scope and Installation | ![]() |
All middleware event handlers are installed at one of several scopes, which are hierarchically ordered from most general (default scope) to most specific (request scope). A handler can be installed at one or more scopes, depending on its event type. When a request broker event occurs, Panther looks for its handler at the most specific scope that is valid for the event. If no handler is installed at that scope, Panther continues to search for the event's handler among other valid scopes, each more general than the last, until it finds one.
Event handlers can be installed at four scopes, listed here in ascending order of precedence (general to specific):
For example, to install an You can uninstall a handler from application scope by setting the corresponding property to an empty string. For example:
unload handler at application scope, set the hdl_unload property:
@app()->hdl_unload = "user_unload"
@app()->hdl_unload = ""
For example, an unload handler can be installed at any scope. When an If Panther cannot find the specified handler, a unload event occurs, Panther first checks whether an unload handler exists for the applicable service. If no request handler is found and the unload event occurred within a transaction, it checks whether an unload handler is installed for that transaction. If no transaction handler is found, Panther looks for a handler installed at application scope. If no application-scope handler is set, Panther uses the default unload handler.
TP_HANDLER_MISSING exception of severity TP_ERROR occurs.
Writing Event Handlers | ![]() |
You can write a middleware event handler in JPL or C. Handlers written in JPL can be stored in screen or library modules; handlers written in C must be installed as prototyped functions. (For more information, refer to "Prototyped Functions" in Application Development Guide.)
Request broker event handlers that are written in JPL should be accessible to the application either as library modules that are made public (via the public command) or as screen modules (via the screen's JPL Procedures property):
Handlers for a request broker event type must conform to a contract which is specific to the event type, and specifies the handler's implementation. A handler contract specifies the number and type of parameters, and how to interpret its return integer value. For information about handler contracts, refer to event type descriptions later in this chapter.
An event handler should avoid generating events of its own type as this can create an infinite loop. Because pre_request, post_request and unload events are necessary to make service requests, these events can be generated recursively. Handlers for these events should guard against generating events of the same type.
When a handler is invoked for an event, the following changes to normal processing occur:
Events Generated within Handlers
Built-in Handlers | ![]() |
The Panther distribution provides a number of built-in handlers that are internally installed. All handlers at default scope are built-in handlers. A number of the built-in handlers are not used as defaults; these are available for installation at other scopes. For example, two built-in handlers are available for jif_changed events: the default handler sm_tp_jif_changed_read, responds to any change in the JIF and readvertises its services; sm_tp_jif_changed_ignore ignores all changes. You might want temporarily to install sm_tp_jif_changed_ignore for a deployed application so it is unaffected by updates to the JIF, such as addition of new services that are undergoing development.
Some event types use different built-in handlers as the defaults for production and development environments. Default development handlers are called by standard servers that are configured for development; default production handlers are called by standard servers that are configured for production. For example, sm_tp_advertise_cond_winopen is the default handler for advertise events on a server that is configured for production; this handler conditionally caches in memory the service components of advertised services. A server that is configured for development uses sm_tp_advertise_log; this handler never caches service components, and also posts success messages to the request broker's log file.
Table 6-2 lists all built-in handlers and indicates which ones are used as defaults for development (dev) and production (prd). Descriptions of these handlers can be found in the event type descriptions that follow.
Advertise and Unadvertise Events | ![]() |
advertise and unadvertise events occur on the successful return of the advertise and unadvertise commands, respectively. Both events occur only on servers.
advertise and unadvertise can specify a single service, a group of services, or all services. Each service generates its own set of advertise and unadvertise events.
advertise handlers are used to perform service initialization. unadvertise handlers are used to perform service cleanup.
advertise and unadvertise handlers can only be installed at application scope.
advertise_handler(char *cmdStr, char *serviceName,
char *groupName, char *serviceContainer, int cacheScreen)
unadvertise_handler(char *cmdStr, char *serviceName,
char *groupName, char *serviceContainer, int cacheScreen)
cmdStr
The advertise and unadvertise handler arguments.
TP_ONADVERTISE—The service component is opened and cached in memory when the service is first advertised.
The return codes from advertise and unadvertise handlers are ignored; a 0 return value is suggested.
Panther provides four built-in advertise handlers:
sm_tp_advertise_cond_winopen (default production handler) opens the service component of the advertised service and caches it in memory only if the JIF's service definition sets Cache Service Component attribute to TP_ONADVERTISE.
sm_tp_advertise_winopen opens the service component that is associated with the advertised service.
Panther provides four built-in unadvertise handlers:
sm_tp_unadvertise_cond_winclose (default production handler) closes the service component of the advertised service only if the JIF's service definition sets Cache Service Component to TP_ONADVERTISE.
sm_tp_unadvertise_winclose closes the service component associated with the unadvertised service.
Exception Events | ![]() |
An exception event occurs while the middleware API is performing work on behalf of the application. All request broker commands can generate one or more exception events. Not all exception events are errors; however, all request broker errors are exception events.
Each exception event is associated with an integer code, string constant, and message, which are set in application properties tp_exc_code, tp_exc_names and tp_exc_msg, respectively. tp_exc_names is an array of all exception event type constants that are indexed by the corresponding exception codes. tp_exc_msg contains a string that describes the latest exception event.
For example, this JPL statement displays a message that describes the latest exception event to the user:
msg emsg "Error: " ## @app()->tp_exc_names[tp_exc_code] \
## "%NMessage: " ## @app()->tp_exc_msg
Each exception event sets tp_severity to a severity code, which is also supplied as an argument to the exception handler function.
For a complete list of exception event type constants, refer to page D-1. For exception severity codes refer to page 6-13.
When an exception event occurs, its handler performs the required processing. This processing might include displaying a message to the user, cancelling a request, or rolling back a transaction.
On entering an exception handler, Panther sets these application properties:
tp_exc_code, tp_exc_names, and tp_exc_msg identify and describe the exception event that triggered execution of this handler.
tp_severity is set to the default severity code for this exception event. The severity level is also supplied as an argument to the handler function (refer to page 6-12).
For example, the following The handler should store the value of If an exception handler alerts the user of an error condition whose severity level is equal to or greater than TP_ERROR:
proc err_print (cmdStr, cmdName, callid, severity)
if ( severity >= TP_ERROR )
msg emsg "Error: " @app()->tp_exc_code \
"Message: " @app()->tp_exc_msg return severity
tp_exc_code and/or tp_exc_names before it calls any other middleware API-related functions; otherwise these properties are liable to be reset before control returns to the handler. Similar precautions are unnecessary for the handler's severity code, because the severity level is already locally available as a handler parameter.
Exceptions within an Exception Handler
exception handler generates its own exception events, Panther ignores them and does not call any handlers for them, and the tp_severity property remains unchanged. To catch exceptions within an exception handler, check the tp_severity property after each command in the handler. The original handler then decides whether errors within the handler should affect the severity that it returns.
Scope
exception events can occur on clients and servers. exception handlers can be installed at all scopes.
Contract
exc_hdl(char *cmdStr, char *cmdName, char *callid, int severity)
exception event.
exception event.
An exception handler must return a valid severity code. This code is written to the tp_severity property, and determines how the application responds to the exception event. If the handler returns an invalid return code, tp_severity is restored to the severity level it had on entry to the handler. For a description of all exception severity codes, refer to page 6-13.
Warning:
If a JPL procedure omits a return statement, it returns a value of 0. exception handlers that are written in JPL should always explicitly return with the appropriate severity code.
All exception event handlers must return a severity code. Each exception event has a default severity, and the tp_severity property is set to the corresponding code on entry to the exception handler. The default severity code is also supplied as an argument to the handler function. If a request broker event generates multiple exceptions, the exception with the highest severity has precedence and sets tp_severity.
The following sections lists severity codes in ascending (lowest to highest) order and describes what action the application takes when a handler returns one of them.
TP_NONE
exception event is ignored. Processing of the command or request continues and the tp_exc_code property remains unchanged. The status of an enclosing transaction is unaffected.
TP_INFORMATION
TP_WARNING
TP_ERROR
TP_WILL_ABORT.
TP_MESSAGE
exception events of this severity are only raised during the process of exchanging data between clients and servers. An exception of this severity level causes the send/receive process to abort any further attempt to send/receive that message. Any other processing associated with that message is also aborted. If the exception occurs within a transaction, the transaction's status is set to TP_WILL_ABORT.
TP_COMMAND
TP_WILL_ABORT.
TP_REQUEST
TP_REQUEST severity is reduced to a TP_COMMAND severity. For a client, all processing associated with the request is terminated.
post_request event occurs. The value of the tp_exc_code property is set to the exception code. The status of an enclosing transaction is set to TP_WILL_ABORT. If an exception of severity TP_REQUEST is generated within a server and is related to its servicing of a client, then the service is terminated with an error status.
TP_TRANSACTION
xa_rollback command.
TP_CONNECTION
TP_COMMAND.
If associated with a server exception, the server aborts its current service and shuts down.
TP_PANIC
Operation of the agent, client or server, stops. A client process rolls back all outstanding transactions (via xa_rollback), aborts if possible all outstanding service requests, closes all open connections, and terminates. A server aborts its current service as if the severity were TP_REQUEST. and shuts down. The connection to the middleware API is severed.
Panther provides four exception handlers:
sm_tp_exception_promote_error (default production handler) promotes all exceptions of a TP_ERROR severity to TP_COMMAND. Thus, all TP_ERROR exceptions cause command termination. For other exceptions of severity TP_WARNING or higher, this handler displays a windowed exception message.
sm_tp_exception_no_change does nothing other than accept the initial severity.
Jif_changed Events | ![]() |
jif_changed events occur when the jif_check command detects changes in the JIF since application startup or the last time the JIF was read. Each time the JIF is accessed, jif_check examines it for changes.
A jif_changed handler should call the jif_read command to reread the JIF, then readvertise services through calls to unadvertise and advertise. If necessary, this handler can also unload public JPL modules that contain service definitions, then reissue the public command on them.
For example, the following handler rereads the JIF and readvertises all services:
proc jif_changed_hdlr()
unadvertise all
jif_read
advertise all
return 0
The jif_changed event handler can conditionally reread the JIF by checking the tp_return property, which tells how the JIF changed with one of these values:
TP_JIF_OLD—Version number decreased, indicating an older version of the JIF is now in place.
TP_JIF_NEWER—Version number increased, indicating a newer version of the JIF is in place.
TP_JIF_NOACCESS—The JIF file or its library cannot be accessed.
For example, the following JPL rereads the JIF only if it the current version is more recent than the last:
The A negative return code causes the jif_check command to abort by raising a Two built-in if ( @app()->tp_return == TP_JIF_NEWER )
jif_read Scope
jif_changed event is available to clients and servers. A jif_changed handler can only be installed at application scope
Contract
jif_changed_handler() Returns
TP_USER_ABORT exception of severity TP_COMMAND.
Built-in Handlers
jif_changed handlers are provided:
sm_tp_jif_changed_read (default) rereads the JIF through the jif_read command, and readvertises services as specified by a given server's configuration. If the severity after executing jif_read is greater than TP_WARNING, this handler returns -1; otherwise it returns 0.
sm_tp_jif_changed_ignore ignores jif_changed events and does not reread the JIF.
Message Events | ![]() |
message events occur when a client receives an unsolicited message, including those generated by the broadcast, and notify commands, or when a subscribed event is posted with the post command.
A message handler decides what to do with unsolicited messages received by Panther. Typically, an application logs messages to a file or displays them immediately to the user.
If a client needs to process or save a message, the message handler must do so before it returns. Use the receive command with the MESSAGE keyword to access message contents.
To ensure that unsolicited messages are received and interpreted correctly, install an application-wide message handler that relies on a common protocol for identifying message sources. For example, the protocol might establish that all agents of unsolicited messages use the same field in their message data to identify the message source. On receiving unsolicited messages, the message handler then checks this field to determine the nature of the message and how to respond.
In the following example, an unsolicited message is broadcast to a supervisor client to report a security violation. In this application, the first field of an unsolicited message is always named source, whose value indicates the message type. The message handler first issues the receive command to get the contents of source; subsequent processing depends on the contents of source:
broadcast CLIENT "supervisor" TYPE JAMFLEX \
({source="bcast_security", ACCOUNT=acct, DATE=date,\
SECURITY=code, MSG=message})
// Message handler for all unsolicited messages
proc msg_handler(type, subtype)
vars source, account, date, security, message
vars companyNews, teamNews, stock, stock_quote
vars fileStream, acctMsg
// Identify message sender.
receive MESSAGE ({source})
if (source == "bcast_security")
{
// receive security violation data
receive MESSAGE ({account, date, security, message})
// Alert the supervisor
msg emsg "%A004Security alert: " ## message ## \
"%NDate: " ## date ## \
"%NAccount No. " ## account ## \
"%NCode: " ## code
}
else if (source == "bcast_acct_data")
{
// receive account data
receive MESSAGE ({account, date, message})
acctMsg = account##" "##date##" "##message
// write message data to log file
fileStream = sm_fio_open("/u/acct/logfile", "a")
if fileStream > 0
{
call sm_fio_puts (acctMsg, fileStream)
call sm_fio_close(fileStream)
}
}
...
else if (source == "post_comp_news")
{
// receive posted company news message data
receive MESSAGE ({ companyNews })
msg emsg "Latest company news: " ## companyNews
}
...
return 0
message events are restricted to clients, and a message handler can only be installed at application scope.
message_handler(char *msgType, char *msgSubType)
broadcast or notify command, either JAMFLEX, FML, FML32, or STRING. If the application is likely to broadcast different message data types, the message handler should evaluate the contents of this parameter and branch execution accordingly.
Ignored; a 0 return value is suggested.
Two message handlers are provided:
sm_tp_message_print_string (default) displays any STRING-type messages to the user as a windowed message that requires acknowledgment. Messages of other data types are ignored.
Pre_request and Post_request Events | ![]() |
pre_request and post_request events occur when a client or server issues a service request. A pre_request event occurs just before the actual service request is initiated. A post_request event occurs when the service returns, whether or not the service completes normally. Each service request generates a pre_request and post_request event.
pre_request and post_request events are typically used to track the number of service requests, and how long they take to return.
A pre_request handler is responsible for aborting the service request if execution is inappropriate.
A non-negative (>=0) return code from a pre_request handler allows service request processing to continue. A negative return code aborts the request by generating a USER_ABORT exception of severity TP_REQUEST; a post_request event follows immediately follows.
pre_request and post_request events are available to clients and to servers acting as clients—that is, wherever service requests can occur (refer to service_call). pre_request and post_request handlers can only be installed at application scope.
pre_request_handler(char *callid, char *serviceName, HR>
char *cmdStr)
post_request_handler(char *callid, char *serviceName, HR>
char *cmdStr)
Ignored; a 0 return value is suggested.
One default handler is provided for each event type:
pre_request handler sm_tp_pre_request_ignore ignores pre_request events.
post_request handler sm_tp_post_request_ignore ignores post_request events.
Request_received Events | ![]() |
request_received events are generated on a server when it receives service requests. The request_received event occurs before Panther verifies that the service is defined in the JIF.
The request_received handler performs any processing that is related to receipt of a service request. Because a request_received event occurs before Panther verifies a service definition, its handler typically calls jif_check to determine whether the JIF has changed.
A request_received handler typically works together with a jif_changed handler to ensure that all changes to the JIF are known to the server before it processes a service request. For example, if the request_received handler calls jif_check, this command detects any changes to the JIF and generates a jif_changed event. The jif_changed handler can then readvertise the services configured for this server (refer to page 6-16).
For example:
// Check whether JIF has changed. If it has, a jif_changed
// event is raised and jif_read executes
proc request_received_hdlr (callid, serviceName)
jif_check
return 0
request_received handlers abort a service request if it is inappropriate to proceed.
request_received events are executed only on servers. request_received handlers can only be installed at application scope.
request_received_handler(char *callid, char *serviceName)
A non-negative return code from a request_received handler allows continued processing of the service request. A negative return value aborts the service request.
Two request_received handlers are provided:
sm_tp_request_received_ignore (default production handler) ignores request_received events.
sm_tp_request_received_jif_check (default development handler) calls the jif_check command. If the severity after executing the jif_check command is greater than TP_WARNING, the handler returns -1 and the request is cancelled. Otherwise, 0 is returned. The jif_check command raises a jif_changed event if the JIF has changed.
Server_exit Events | ![]() |
A server_exit event is generated when a server deactivates in an orderly fashion. It is usually the last event that user-written code handles before server deactivation.
The server_exit handler should clean up any resources allocated while the server was active that the middleware API nor Panther are unaware of. It can also log a message that the server is deactivating. For example:
// Implementation of a "log_down" server_exit handler
proc server_exit
log "Server has been brought down."
return 0
server_exit events are restricted to servers, and the handler can only be installed at application scope.
server_exit_handler()
Ignored; a zero return is recommended.
Two server_exit handlers are provided:
sm_tp_server_exit_log_down (default) posts a message to the middleware APIs log file indicating that the server is being deactivated.
Pre_service and Post_service Events | ![]() |
The pre_service and post_service events occur every time a server receives a service request:
pre_service event follows the request_received event and verification of the service's JIF's definition, and precedes execution of the service routine.
post_service event occurs after the service routine completes execution.
The A non-negative return code from a pre_service and post_service events are paired events—each pre_service event is eventually matched by a post_service event for that same service. Both events are enabled or disabled together.
Pre_service and Post_service Handlers
pre_service handler should abort the service if execution is inappropriate. pre_service and post_service handlers typically keep track of the number of requests to a service and how much time a service requires to process. These handlers also can associate a service component with the service: the pre_service handler opens the service component, while the post_service handler closes it.
pre_service handler allows continued execution of the service. A negative return code aborts the service: a TP_USER_ABORT exception of severity TP_REQUEST is generated, and the middleware API informs the client that the service has been aborted with a failure status. A post_service event is then generated.
Scope
pre_service and post_service events are restricted to servers. pre_service and post_service event handlers can only be installed at application scope.
Contract
pre_service_handler(char *callid, char *serviceName,
char *serviceContainer, int cacheScreen)post_service_handler(char *callid, char *serviceName,
char *serviceContainer, int cacheScreen)
TP_ONADVERTISE—The service component is opened and cached in memory when the service is first advertised.
Ignored.
The following is an example of a The following is an example of a Four Returns
Example
pre_service handler:
proc pre_service_hdlr(callid, srvcName, srvcContainer, cacheFlag)
vars rcode, log_msg
{
// if there is no service component, do nothing
if (cacheFlag == TP_NOCACHE)
{
rcode = sm_jwindow(srvcContainer)
}
else
{
rcode = sm_n_wswlwct(srvcContainer)
if (rcode < 0)
{
// if select failed & ONFIRSTCALL, try to open
if (cacheFlag == TP_ONFIRSTCALL)
{
rcode = sm_jwindow("&&" ## srvcContainer)
}
}
}if (rcode < 0)
{
log_msg = "Error opening " ## srvcContainer
log log_msg
return -1
}
return 0
}post_service handler:
proc post_service_hdlr(callid, srvcName, srvcContainer, cacheFlag)
//if there is no service component, do nothing
if (srvcContainer == ""
return 0
{
if (cacheFlag == TP_NOCACHE)
{
call sm_close_window()
}
else
{
// handle as TP_ONFIRSTCALL and/or TP_ONADVERTISE
call sm_wdeslect()
}
} Built-in Handlers
pre_service handlers are provided:
sm_tp_pre_service_winopen_or_select (default production handler) selects or opens the specified service component depending on whether it is already cached, as specified by the cacheScreen parameter (refer to page 6-26).
Four post_service handlers are provided:
sm_tp_post_service_winclose_or_deselect (default production handler) deselects or closes the specified service component depending on whether caching is specified by the cacheScreen parameter (refer to page 6-26).
sm_tp_post_service_winclose (default development handler) closes the specified service component.
If a standard server is configured for debugging or development, then a Service %s completed message is logged.
sm_tp_post_service_windeselect restores the specified service component identified by serviceContainer to its original position in the window hierarchy.
Unload Events | ![]() |
An unload event occurs when message data is received from an external source whose contents can be written to Panther variables. Message data can be unloaded for these reasons:
unload handler implements the mapping of reply message data to client variables as specified earlier by the service_call command.
unload handler implements the mapping of unloaded data as specified by the receive command.
unload handler implements the mapping of unloaded data to service variables, as specified by the receive command.
All service requests generate an An
Note:
unload event on the client even if an error occurs and no data unloads. The application can then decide whether to write to the specified variables, possibly only clearing them of old data.
Unload Handlers
unload handler is responsible for unloading data into Panther variables through the unload_data command, and setting conditions for performing the unload.
unload handlers can be triggered anywhere, including within another unload handler. Therefore, unload handlers should not raise another unload event, and thus give rise to an infinite loop condition. For instance, if a service call is issued from within an unload handler, an unload event occurs for that service when it returns. The handler is called again to handle the event, and so on.
Scope
unload events are available to both servers and clients, and handlers can be installed at application, transaction, and request scopes.
Contract
unload_handler(char *callid, int msgSource, int receiptMethod)
unload event, indicated by one of the following constants:
The severity code that an unload handler returns indicates whether it successfully processed the unload event. TP_NONE indicates success. Return any other severity code to indicate failure. A failed unload event generates a TP_UNLOAD_FAILED exception at the specified severity. If the return code is not a valid severity, a TP_UNLOAD_FAILED exception occurs at the TP_WARNING severity level. For a description of severity codes, refer to page 6-13.
The following unload handler unloads message data only if the service request is successful:
proc unload_hdlr (callid, msgSource, msgRcptMethod)
{
if (@app()->tp_svc_outcome == 0)
{
// unload the arguments
unload_data
}
else
{
log "Unsuccessful return from service--no arguments \
unloaded"
}
return TP_NONE
}
Two unload handlers are provided.
sm_tp_unload_call_origin (default) unloads the service message data to the screen where the service call originated. If the screen is no longer active, this handler unloads the message data to the active screen. This handler ensures that results are written to the original screen when application processing has proceeded to a different screen.