![]() | ![]() | JetNet/BEA Tuxedo Guide |
In JetNet and BEA Tuxedo applications, events occur during the processing of service requests. These middleware events are one of several categories of events that occur in a Prolifics 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. Prolifics 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 Prolifics recognizes in JetNet and BEA Tuxedo applications:
Event Sequence | ![]() |
During the typical lifespan of a Prolifics 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, Prolifics looks for its handler at the most specific scope that is valid for the event. If no handler is installed at that scope, Prolifics 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 unload handler at application scope, set the You can deinstall a handler from application scope by setting the correspond ing property to an empty string. For example:
hdl_unload property:
@app()->hdl_unload = "user_unload"
@app()->hdl_unload = ""
xa_begin command for exception and unload events that occur within a transaction. If installed, these handlers are used during the transaction, and are deinstalled when the transaction ends.
For example, an unload handler can be installed at any scope. When an unload event occurs, Prolifics 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, Prolifics looks for a handler installed at application scope. If no application-scope handler is set, Prolifics uses the default unload handler.
If Prolifics cannot find the specified handler, a 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 Prolifics 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(car *cmdStr, char *serviceName,
char *groupName, char *serviceContainer, int cacheScreen )
unadvertise_handler(char *cmdStr, char *serviceName,
char *groupName, char *serviceContainer, int cacheScreen )
cmdStr
The advertise or unadvertise command and its arguments.
advertise or unadvertise command. If none is specified, this argument is set to null string.
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.
Prolifics 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.
Prolifics 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 . For exception severity codes refer to page .
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, Prolifics 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.
For example, the following exception handler alerts the user of an error condition whose severity level is equal to or greater than The handler should store the value of If an exception handler generates its own exception events, Prolifics ignores them and does not call any handlers for them, and the Exception events can occur on clients and servers. Exception handlers can be installed at all scopes.
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
tp_severity property remains unchanged. To catch exceptions within an exception handler, check the tp_se verity 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
Contract
exc_hdl( char *cmdStr, char *cmdName, char *callid, int severity )
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 .
Warning:
If a JPL procedure omits a return statement, it returns a value of 0. Exception event 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 event 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
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
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.
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
client_exit command. If no connection applies, the severity is reduced to the next severity level that is applicable, usually 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.
Prolifics 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_change 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 JIF_changed event is available to clients and servers. A JIF_changed handler can only be installed at application scope
A negative return code causes the Two built-in JIF_changed handlers are provided:
if ( @app()->tp_return == TP_JIF_NEWER )
jif_read Scope
Contract
JIF_changed_handler() Returns
jif_check command to abort by raising a TP_USER_ABORT exception of severity TP_COMMAND.
Built-in Handlers
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 Prolifics. 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 )
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 )
service_call command and its arguments that issued the service request.
Ignored; a 0 return value is suggested.
One default handler is provided for each event type:
sm_tp_pre_request_ignore ignores pre_request events.
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 Prolifics 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 Prolifics 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 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 ).
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.
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 Prolifics 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_exithandler()
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 API's 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 handler allows continued execution of the service. A negative return code aborts the service: 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.
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 post_service handler:
Four pre_service handlers are provided:
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
}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
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 ).
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 ).
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 Prolifics variables. Message data can be unloaded for these reasons:
service_call command.
All service requests generate an 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.
An unload handler is responsible for unloading data into Prolifics variables through the
Note:
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.
Unload events are available to both servers and clients, and handlers can be installed at application, transaction, and request scopes.
Unload Handlers
unload_data command, and setting conditions for performing the unload.
Scope
Contract
unload_handler( char *callid, int msgSource,int receiptMethod )
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 .
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.sm_tp_unload_immediate unloads the message data to the active screen, regardless of whether the message data originated from it.