JetNet/Oracle Tuxedo Guide


Chapter 8. Oracle Tuxedo Features

If you are using Panther Oracle Tuxedo Edition, you can take advantage of several enhanced features provided by Oracle Tuxedo. This chapter describes these features:

This chapter also provides information on initializing and booting servers in the Oracle Tuxedo environment, including a debuggable server.


Service Data Buffer Types

Data is passed between agents—clients and servers—in data buffers. These data buffers are sometimes referred to as message buffers, or simply messages.

Within the JetNet middleware adapter, these data buffers can contain information in a JAMFLEX buffer. In the case of service call operations, up to two buffers can be passed, one for data incoming to the service, and one for data returned from the service to the calling agent.

Within the Oracle Tuxedo middleware adapter, in addition to the JAMFLEX buffer type, you can use FML, FML32 and STRING buffer types to transport data/messages between agents. The commands that use data transport are service_call, service_forward, service_return, receive, enqueue, dequeue, post, notify, and broadcast.

FML and FML32 Buffers

Oracle Tuxedo provides FML buffers (both FML and FML32) as a medium for handling collections of data fields. FML32 differs from FML in that certain identifiers permit larger sizes—allowing for 32-bit values as opposed to 16-bit values. For example, the maximum number of fields in an FML buffer is 8,191, and for FML32 about 30 million. Differences also apply to individual field sizes and total fielded buffer size. In general, in this documentation, references to FML apply to both types; differences in behavior are noted accordingly.

When you use FML buffers, fields are listed in an FML file. In the file, each field has a name, number, and type, either short, long, float, double or carray. For more information on FML buffers within JPL, refer to page 5-17.

When you use transaction manager defined services with FML buffers, you must define the following FML fields:

FML field Type

smTmData

carray

smTmRowCount

long

SmTmTv

string

Oracle Tuxedo-specific variables are used by Oracle Tuxedo to locate FML and FML32 files:

For more information on FML buffers and variables, refer to the Oracle Tuxedo documentation.

STRING Buffers

With the Oracle Tuxedo middleware adapter, Panther supports Oracle Tuxedo STRING type buffers. Either a string constant or a variable can be passed. Refer to page 5-18 for more information on these buffer types. Also, refer to the Oracle Tuxedo documentation.


XA Transaction Management

In a Oracle Tuxedo application, you can use the XA protocol to provide transactional control in addition to native database transaction support. Database and queuing operations can be grouped together and executed such that either all of them are completed or none of them are.

JPL commands which support the XA protocol are listed in Table 8-1.

Table 8-1 JPL commands providing XA transactional control

JPL command Description

xa_begin

Begin a transaction.

xa_commit

Commit a transaction.

xa_end

End a transaction.

xa_rollback

Abort a transaction.

You want to use XA transactional control when operations that must be executed together span more than one service, or when more than one resource manager is being accessed. However, if the database operation is contained within one service call, and only one resource manager is being accessed, it is more efficient to use native database transaction support.

For example, a bank account transfer operation can be coded so that two service calls are required to debit one account and credit another. Both services comprise a single transaction as shown in the following example:

xa_begin
service_call withdraw ( .... )
...
service_call deposit ( .... )
...
xa_end

An alternative approach is to write a transfer service that incorporates the code from both procedures withdraw and deposit. Then, a transaction would not have to be used when calling this service. However, you would still need to use database transaction control around the database operations within the service, that is, the dbms begin, dbms rollback and dbms commit commands, to ensure the integrity of the database.

For more information about transactional support in each Panther database driver, refer to Database Drivers.

Note: You cannot mix native database transaction control and XA-transaction control in the same server. If there is an XA connection to the database, all transactional control must be performed with the XA protocol.


Message Forwarding

You can use the service_forward command to forward service request data from one service to another. A service_forward differs from a service_call in that no reply is expected by the agent executing service_forward. The responsibility of replying to the initial client agent is handed over to the service that receives the forward request.


Event Brokering

With the Oracle Tuxedo middleware adapter, Panther provides access to Oracle Tuxedo's Event Broker/Monitor. This feature allows clients and servers to generate application-wide events that can be subscribed to by any agent on an individual basis. The Oracle Tuxedo event broker system of event processing is distinct from the other layers of Panther event processing: database event processing, request broker event processing, transaction manager event processing, and screen/widget event processing.

Event posting and subscribing provides another method of communication between agents, one that is more flexible than simple service calling. Communication is not restricted to a one-to-one relationship between a client agent and a server; any agent can post an event that can be received by any number of other interested agents.

Use event brokering for important, infrequent events. The application's performance can be affected if there is an overload of event notifications.

How to Use the Event Broker

Your application configuration must include running the Oracle Tuxedo-provided event broker server TMUSREVT. To take advantage of Oracle Tuxedo system-specific events, your configuration must also run the server, TMSYSEVT, which process the predefined events.

For information on configuring these servers, refer to your Oracle Tuxedo Administrator's Guide.

Accessing the Event Broker

Three commands are used to access event brokering: post, subscribe, and unsubscribe.

There is no formal mechanism for defining application-wide events in your application code. The events are determined as part of the design process of the application, and exist as part of the application specification. Essentially, the events are defined at the time they are posted or subscribed to.

A subscriber can subscribe to an event that might not occur, for instance a stock-changed event when a price exceeds a certain value. When an agent subscribes to an event with the subscribe command, the Oracle Tuxedo middleware adapter does not verify that the event named has been defined elsewhere.

For clients, event notification is done via an unsolicited message. For servers, there are two methods: notification by a service call and notification by message queuing. These methods, and more information about event brokering, can be found in the descriptions for the post, subscribe, and unsubscribe commands.

Example: Stock-change Event

An event is a logical condition, defined by the agent that is either posting or subscribing. An event which registers the change in a stock price could be defined in several ways. This example illustrates different ways which this can be done. Assume that the FML fields defined for the stock.* events are:

source

event_name

stock_name

price_change

price

A message handler designed to handle these event notifications unloads data from the FML fields into Panther variables:

proc msg_handler(type, subtype)
vars source, event_name, stock_name, price_change, price
{
receive message ({source})
if (source == "post")
receive message ({event_name, stock_name, \
price_change, price})
else if (source == "notify")
...
else if (source == "broadcast")
...
return
}

In the msg_handler procedure, the FML field named source is set by all agents that generate unsolicited messages, including users of broadcast and notify. Messages sent by these commands would have different FML fields, and hence, a different receive statement.

Note: It is important that a standard method of identifying the source of unsolicited messages be established for the entire application. The handler has no knowledge of where the message originated, it simply has a buffer of data. The handler must know how to interpret message data. For more information on implementing an application-wide message handler, refer to page 6-3.

Posting a change event
If the price of a cola stock changes, the event posting could look like this:
post EVENT "stock_change" ({source="post", \
event_name="stock_change", stock_name="cola",\
price_change="+0.50", price="23.00"}) \
TYPE FML

When posting an event, the event name (argument for EVENT) must not begin with a "."—this is reserved for Oracle Tuxedo predefined events.

Subscribing to any change event
An agent could subscribe to a stock_change event as follows:
subscribe EVENT "stock_change"

This notifies the user when any stock changes.

Subscribing to a specific change event
An agent can seek notification only when cola stock changes:
subscribe EVENT "stock_change" \
FILTER "stock_name == 'cola'"

In this case, the logical event subscribed to is cola-change, though this is implemented by subscribing to the stock_change event using the FILTER option of the command to exclude all stock_change events that are not for the cola stock.

When subscribing to an event, the event name can be any Oracle Tuxedo regular expression (refer to the Oracle Tuxedo Reference Manual for a description of the syntax), for instance:

subscribe EVENT "stock.*"

Example: Enterprise Bank

The Enterprise Bank sample application makes use of the event broker. When a customer attempts to login to the ATM client, three failures to enter a PIN correctly result in disconnection. A security message is posted to the log file. The event broker posts the security event, which the server picks up. Event notification is done via a service call and the service logs the message to the log file.

The following code fragment from a procedure init_atm shows how the event is posted when a login failure condition occurs:

vars failed_pin_attempts=0

proc init_atm ()
{
vars message
...
/* validate PIN given by the customer */
service_call "VAL_PIN" ({last_name, pin}, \
{message, owner_ssn = user_info})
	/* check if validation was not successful */
	if ((@app()->tp_severity > TP_WARNING) || \
(@app()->tp_svc_outcome == TP_FAILURE))
{
msg quiet message
client_exit
if (failed_pin_attempts < 2)
{
failed_pin_attempts = failed_pin_attempts + 1
}
else
{
post event "ATM_SECURITY" (last_name)
failed_pin_attempts = 0
}
call sm_n_gofield("pin")
}
...
return 0
}

The ATM_SECURITY event is subscribed to at server initialization. The server initialization routine, jdbinit.jpl, loads the public module server.jpl, and calls the following procedure server_subscribe:

proc server_subscribe()
{
vars message ret
// Subscribe to ATM security events (3 failed pin
// entry attempts)
message = "Server subscribing to event: ATM_SECURITY"
log message

subscribe event "ATM_SECURITY" \
notification service "LOG_SEC_EVENT"
	// Subscribe to withdrawal limit exceeded events
message = "Server subscribing to event: WITHD_LIM_EXC"
log message

subscribe event "WITHD_LIM_EXC" \
notification enqueue qspace "BANKQSPACE" \
name "WITHD_EXC_Q"
return 0
}

The subscription to the ATM_SECURITY event directs the event broker to perform notification of the event (if it occurs) via a service call to LOG_SEC_EVENT, which is implemented as screen-level JPL in the cust.scr service component. The log_security_event procedure logs the message:

proc log_security_event()
{
vars message
receive args (last_name)
message = "ATM SECURITY event logged for " ## last_name
log message
service_return ()
}

Posting and Subscribing

The following steps describe the process involved in posting and subscribing to a event.

  1. A client or server posts an event with the post command or subscribes to an event with the subscribe command. The name of the event is passed as an argument to both commands.
  2. Once an event is posted, the event broker determines who has subscribed to the event—applying the rules of a FILTER expression where they are provided—and how subscribers should be notified.
  3. Clients or servers that have subscribed to the event are notified of the event in the manner specified by the arguments used in subscribe. Clients are notified via an unsolicited message; a message handler must be provided that recognizes the posted events. Servers receive notification either by a service call or message queuing.

Unsubscribing

Agents unsubscribe from event notification with the unsubscribe command. Events can be unsubscribed from either collectively—using the ALL option—or individually—using the event's subscription ID. The subscription ID is required when unsubscribing from a specific event.

You can ascertain the subscription ID immediately after the initial subscribe by obtaining the value of the tp_return property. The following example shows how to obtain the event's subscription ID:

vars sub_id
...
subscribe "stock_fall"
sub_id = @all()->tp_return
...
unsubscribe SID sub_id

Reliable Queues

Message queuing to reliable queues provides an alternative mechanism for interprocess communication between clients and servers. With the Oracle Tuxedo middleware adapter, Panther uses the

Oracle Tuxedo System/Q facility, a system of queue management which includes:

The queuing system provides a location where messages can be stored. These messages can be intended for a variety of purposes—for instance, an agent might want to store a message that contains data intended for another agent. The agent providing the data can enqueue the information onto a queue, where it is available for another agent (or even the same agent) to obtain by dequeuing.

Reliable queues give a three-tier application greater flexibility in client/server communication, providing more methods of controlling the message enqueue/de queue process than it does controlling service calls. Also, if

Oracle Tuxedo goes down, any uncompleted service calls are lost, but enqueued messages are still available when the system comes back up.

For example, an enqueue request can be used to "batch-up" non-time-critical service calls. By choosing a queue that is associated with a service (described below), the enqueuing agent can invoke the service indirectly, independent of its (the client's) execution. Later, at a convenient time, the client or any other agent, can obtain the results by dequeuing from a reply queue—after the original enqueued message has been dequeued and processed by a server.

To use reliable queues:

Your application configuration must include running the Oracle Tuxedo-provided TMQUEUE and, possibly, TMQFORWARD servers. For information on configuring these servers, refer to the Oracle Tuxedo Administrator's Guide. Oracle Tuxedo must be configured for queuing, and for the creation of the application's queues and the queuespaces in which they are grouped.

The queue management server, TMQUEUE, is used by the reliable queuing facility to enqueue and dequeue messages. The TMQFORWARD server is responsible for dequeuing messages, forwarding them to application services, and enqueuing the reply from the service onto a reply or failure queue.

Enqueuing a Message

The enqueue command places a message on a queue. In order to enqueue the message, the names of the queue and its corresponding queuespace are required. In addition, the message data must be in on of the following forms—JAMFLEX, STRING, FML or FML32—and match what is defined in the JIF.

Agents can specify and keep track of enqueued messages by either their:

Enqueuing agents can also specify:

Dequeuing a Message

The dequeue command removes a message from a queue. To dequeue a message, the names of the queue and its corresponding queuespace are required. The arguments—JAMFLEX, STRING, FML or FML32—to receive the message are also required and must match what is defined in the JIF.

Dequeuing agents identify the message to dequeue by one the following:

A dequeuing agent can obtain the following information about the message:

The dequeuing agent can specify that the dequeue operation be unaffected by normal blocking timeouts, and that it be executed outside of the current transaction. It can also indicate that the dequeue should wait for a message if the queue is empty; otherwise dequeue returns immediately.

Defining Reliable Queues

Reliable queues are uniquely identified by their name and the name of the queuespace to which they belong. They can be either independent or service queues.

To identify and access queues (and their queuespaces):

Define them in the JIF using the JIF editor. Refer to page 24-15 in the Using the Editors for instructions on using the JIF editor to define a queue.

Note: The creation of queues is done independently of Panther software; it is part of your Oracle Tuxedo configuration.

Service Queues

Service queues are associated with a particular service and are invoked to process message data. To use service queues, the TMQFORWARD server must be running and configured to monitor your queues. Define service queues in the JIF by providing the following information:

Independent Queues

An independent queue does not have prescribed service call behavior. Independent queue definitions in the JIF require the following:

Example

The Enterprise Bank sample application uses reliable queues to queue up new accounts for batch processing of a generic bank information mailing.

The Customer Maintenance screen cust_mnt.scr has an event function attached to the customer table view. The Function property identifies the function tm_cust. Part of the tm_cust. event function is reproduced here, showing how the customer information is enqueued to NEW_CUST_Q when a transaction manager insert event is encountered.

proc tm_cust (event)
{
vars cust_ssn, message

if (event == TM_VIEW || event == TM_SELECT)
{
...
}
...
else if (event == TM_INSERT_EXEC)
{
/* this is a new customer */
...
	// Queue a notice to send a BANK info packet
// to this new customer

enqueue qspace "BANKQSPACE" name "NEW_CUST_Q" \
({ owner_ssn, \
last_name, \
first_name, \
mid_ini, \
cust_address1, \
cust_address2}) NOREPLYQ NOFAILUREQ
	msg emsg "Saved records of customer :first_name \
:last_name"
return TM_CHECK
}

To initiate the mailing, the New Customer Mailing List screen, custmail.scr, calls the service get_newcust. This service is coded as screen-level JPL on the service component, get_cust. The following procedure is the service call code on the client screen:

proc get_mail_list()
{
service_call "GET_NEWCUST" ({owner_ssn, last_name, \
first_name})
}

The service, get_newcust, on the service component, dequeues all the new customer entries on the queue:

proc get_newcust()
{
/* service GET_NEWCUST */

vars NumQEntries = 0
vars DeQueueStatus = TP_NONE
vars ssn fname lname initial address1 address2

while (DeQueueStatus == TP_NONE)
{
dequeue qspace "BANKQSPACE" name "NEW_CUST_Q" \\
({ owner_ssn=ssn, \\
last_name=lname, \\
first_name=fname, \\
mid_ini=initial, \\
cust_address1=address1, \\
cust_address2=address2})
		if (@jam->tp_severity == TP_NONE)
{
NumQEntries = NumQEntries + 1
owner_ssn[NumQEntries] = ssn
last_name[NumQEntries] = lname
first_name[NumQEntries] = fname
}
else
{
DeQueueStatus = @jam->tp_severity
}
}
service_return ({owner_ssn, last_name, first_name})
}

Initializing Servers

When Oracle Tuxedo boots a server, it can read one or more user-supplied server arguments that are supported by Panther. These arguments let you associate a service group with the server, specify its database connection, and so on. For example, the following CLOPT entry specifies to initialize a production server that advertises services from the usr_svcs service group and connects to database entbank:

CLOPT="-- -group usr_svcs -production
	dbms declare dbsession connection for database "entbank""

Supply these arguments at the end of the server's CLOPT string with the following format:

-- [ -all | -group serviceGroup] [ -rw ] serverOption ]
	 [ dbms connectString ] initRoutine [ args ]
-all | group serviceGroup

Advertises all services or the specified services in the named service group at startup.

-rw
Advertises the default report service for the server is responsible for generating reports. Refer to page 9-23 in the Reports for more information on the default report service.

serverOption
Specify one of the following server configuration options:

For information on handlers for development and production servers, refer to page 3-24.

dbms connectString
Specifies a database connection through a DBMS DECLARE CONNECTION command (refer to page 8-3 for information on connecting to a database). The string must be enclosed in quotes. The command is executed after default handlers are established and before the initialization routine executes.

initRoutine [ args ]
The initialization routine and any arguments it might use for server initialization. Enter the function name and, optionally, any arguments that it requires, supplied as constant values. The routine is called after default event handlers are established and the database connection is made.