JetNet/Oracle Tuxedo Guide |
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
.
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 |
---|---|
|
|
|
|
|
|
Oracle Tuxedo-specific variables are used by Oracle Tuxedo to locate FML and FML32 files:
FLDTBLDIR
and FLDTBLDIR32
—List of directories where FML
and FML32
files, respectively, can be found.
For more information on FML buffers and variables, refer to the Oracle Tuxedo documentation.
With the Oracle Tuxedo middleware adapter, Panther supports Oracle Tuxedo STRING Buffers
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.
JPL command | Description |
---|---|
Begin a transaction. | |
Commit a transaction. | |
End a transaction. | |
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.
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.
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.
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:
|
|
|
|
|
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.
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.
stock_change
event as follows:
subscribe EVENT "stock_change"
This notifies the user when any stock changes.
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.*"
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 ()
}
The following steps describe the process involved in posting and subscribing to a event.
post
command or subscribes to an event with the subscribe
command. The name of the event is passed as an argument to both commands.FILTER
expression where they are provided—and how subscribers should be notified. 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.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.
Your application configuration must include running the Oracle Tuxedo-provided The queue management server, The Agents can specify and keep track of enqueued messages by either their:
To use reliable queues:
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.
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
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.
Enqueuing agents can also specify:
The Dequeuing agents identify the message to dequeue by one the following:
Dequeuing a Message
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.
enqueue
executes successfully.
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.
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.
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 are associated with a particular service and are invoked to process message data. To use service queues, the Defining Reliable Queues
To identify and access queues (and their queuespaces):
Service Queues
TMQFORWARD
server must be running and configured to monitor your queues. Define service queues in the JIF by providing the following information:
An independent queue does not have prescribed service call behavior. Independent queue definitions in the JIF require the following:
Independent Queues
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 To initiate the mailing, the New Customer Mailing List screen, The service, Example
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
}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})
}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
devel
—Valid for servers that use either the proserv
or prodserv
executables, this option establishes the default event handlers on a server for an application that is undergoing development.
For information on handlers for development and production servers, refer to page 3-24.
dbms
connectString
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.