For example, consider a travel agent application. The client application needs to arrange for a journey to a distant location; for example, from Strasbourg, France, to Alice Springs, Australia. Such a journey would inevitably require multiple individual flight reservations. The client application works by reserving each individual segment of the journey in sequential order; for example, Strasbourg to Paris, Paris to New York, New York to Los Angeles. However, if any individual flight reservation cannot be made, the client application needs a way to cancel all the flight reservations made so far. For example, if the client application cannot book a flight from Los Angeles to Honolulu on a given date, the client application needs to cancel the flight reservations made up to that point.
b.
|
Invokes the register_for_courses() operation on the Registrar object, passing a list of courses
|
•
|
The register_for_courses() operation on the Registrar object processes the registration request by executing a loop that does the following iteratively for each course in the list:
|
The Registrar object checks for the following potential problems, which prevent the transaction from being committed:
If the NotRegisteredList value is empty, the client application commits the transaction.
If the NotRegisteredList value contains any courses, the client application queries the student to indicate whether he or she wants to complete the registration process for the courses for which the registration succeeded. If the user chooses to complete the registration, the client application commits the transaction. If the user chooses to cancel the registration, the client application rolls back the transaction.
The Registrar object registers the student for the courses for which it can, and then returns a list of courses for which the registration process was unsuccessful. The client application can choose to commit the transaction or roll it back. The transaction encapsulates this conversation between the client and the server application.
•
|
The register_for_courses() operation performs multiple checks of the University database. If any one of those checks fail, the transaction can be rolled back.
|
Because the Registrar object is being used for database transactions, a good design choice for this object is to make it transactional; that is, assign the
always transaction policy to this object’s interface. If a transaction has not already been scoped when this object is invoked, the Oracle Tuxedo system will start a transaction automatically.
By making the Registrar object automatically transactional, all database write operations performed by this object will always be done within the scope of a transaction, regardless of whether the client application starts one. Since the server application uses an XA resource manager, and since the object is guaranteed to be in a transaction when the object writes to a database, the object does not have any rollback or commit responsibilities because the XA resource manager takes responsibility for these database operations on behalf of the object.
The RegistrarFactory object, however, can be excluded from transactions because this object does not manage data that is used during the course of a transaction. By excluding this object from transactions, you minimize the processing overhead implied by transactions.
To make the Registrar object transactional, the ICF file specifies the
always transaction policy for the
Registrar interface. Therefore, in the Transaction sample application, the ICF file specifies the following object policies for the
Registrar interface:
To exclude the RegistrarFactory object from transactions, the ICF file specifies the
ignore transaction policy for the
Registrar interface. Therefore, in the Transaction sample application, the ICF file specifies the following object policies for the
RegistrarFactory interface:
The Oracle Tuxedo system provides the always transactional policy, which you can define on an object’s interface to have the Oracle Tuxedo system start a transaction automatically when that object is invoked and a transaction has not already been scoped. When an invocation on that object is completed, the Oracle Tuxedo system commits or rolls back the transaction automatically. Neither the server application, nor the object implementation, needs to invoke the TransactionCurrent object in this situation; the Oracle Tuxedo system automatically invokes the TransactionCurrent object on behalf of the server application.
Assigning the always transactional policy to an object’s interface is appropriate when:
Note:
|
Database cursors cannot span transactions. The CourseSynopsisEnumerator object in the CORBA University sample applications uses a database cursor to find matching course synopses from the University database. Because database cursors cannot span transactions, the activate_object() operation on the CourseSynopsisEnumerator object reads all matching course synopses into memory. Note that the cursor is managed by an iterator class and is thus not visible to the CourseSynopsisEnumerator object.
|
If the object does perform database write operations, and you want the object to be able to participate in a transaction, assigning the always transactional policy is generally a better choice. However, if you prefer, you can use the
optional policy and encapsulate any write operations within invocations on the TransactionCurrent object. That is, within your operations that write data, scope a transaction around the write statements by invoking the TransactionCurrent object to, respectively, begin and commit or roll back the transaction, if the object is not already scoped within a transaction. This ensures that any database write operations are handled transactionally. This also introduces a performance efficiency: if the object is not invoked within the scope of a transaction, all the database read operations are nontransactional, and therefore more streamlined.
The ignore transaction policy may be appropriate for an object such as a factory that typically does not write data to disk. By excluding the factory from the transaction, the factory can be available to other client invocations during the course of a transaction. In addition, using this policy can introduce an efficiency into your server application because it minimizes the overhead of invoking objects transactionally.
If an object’s interface has the always or
optional transaction policy, you must invoke the
TP::open_xa_rm() operation in the
Server::initialize() operation in the Server object. The resource manager is opened using the information provided in the
OPENINFO parameter, which is in the
GROUPS section of the
UBBCONFIG file. Note that the default version of the
Server::initialize() operation automatically opens the resource manager.
If your Server object’s Server::initialize() operation opens an XA resource manager, you must include the following invocation in the
Server::release() operation:
The transaction activation policy is a good choice for objects that maintain state in memory that you do not want written, or that cannot be written, to disk until the transaction work is complete. When you assign the
transaction activation policy to an object, the object:
Assigning the transaction activation policy to an object may be appropriate in the following situations:
If the Oracle Tuxedo system passes the reason DR_TRANS_COMMITTING, the object can, if necessary, invoke the
rollback_only() operation on the TransactionCurrent object. Note that if you do make an invocation to the
rollback_only() operation from within the
Tobj_ServantBase::deactivate_object() operation, the
Tobj_ServantBase::deactivate_object() operation is not invoked again.
•
|
If an object with the always transaction policy is involved in a transaction that is started by the Oracle Tuxedo system, and not the client application, note the following:
|
If the TP::deactivateEnable method is invoked during a transaction, the object is deactivated
when the transaction ends. However, if any methods are invoked on the object between the time that the
TP::deactivateEnable method is called and the time that the transaction is committed, the object is never deactivated.
The Transactions sample application includes an instance of a user-defined exception, TooManyCredits. This exception is thrown by the server application when the client application tries to register a student for a course, and the student has exceeded the maximum number of courses for which he or she can register. When the client application catches this exception, the client application rolls back the transaction that registers a student for a course. This section explains how you can define and implement user-defined exceptions in your CORBA client/server application, using the
TooManyCredits exception as an example.