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.