JBoss.orgCommunity Documentation

JBossJTS Development Guide

Developing distributed transactional applications with JBossJTS

by Mark Little, Jonathan Halliday, Andrew Dinn, and Kevin Connor
edited by Misty Stanley-Jones

Preface
1. Audience
2. Prerequisites
3. Document Conventions
3.1. Typographic Conventions
3.2. Pull-quote Conventions
3.3. Notes and Warnings
4. We Need Feedback!
1. Transaction Processing Overview
1.1. Defining a transaction
1.2. Commit protocol
1.3. Transactional proxies
1.4. Nested transactions
1.5. The Object Transaction Service (OTS)
2. JBossTS Basics
2.1. Introduction
2.1.1. Raw OTS
2.1.2. Enhanced OTS functionality
2.1.3. Advanced API
2.2. JBossTS and the OTS implementation
2.3. Thread class
2.4. ORB portability issues
3. Introduction to the OTS
3.1. Defining the OTS
3.2. Action programming models
3.3. Interfaces
3.4. Transaction factory
3.4.1. OTS configuration file
3.4.2. Name service
3.4.3. resolve_initial_references
3.4.4. Overriding the default location mechanisms
3.5. Transaction timeouts
3.6. Transaction contexts
3.6.1. Nested transactions
3.6.2. Transaction propagation
3.6.3. Examples
3.7. Transaction controls
3.7.1. JBossTS specifics
3.8. The Terminator interface
3.8.1. JBossTS specifics
3.9. The Coordinator interface
3.9.1. JBossTS specifics
3.10. Heuristics
3.11. Current
3.11.1. JBossTS specifics
3.12. Resource
3.13. SubtransactionAwareResource
3.13.1. JBossTS specifics
3.14. The Synchronization interface
3.14.1. JBossTS specifics
3.15. Transactions and registered resources
3.16. The TransactionalObject interface
3.17. Interposition
3.18. RecoveryCoordinator
3.19. Checked transaction behavior
3.19.1. JBossTS specifics
3.20. Summary of JBossTS implementation decisions
4. Constructing an OTS application
4.1. Important notes for JBossTS
4.1.1. Initialization
4.1.2. Implicit context propagation and interposition
4.2. Writing applications using the raw OTS interfaces
4.3. Transaction context management
4.3.1. A transaction originator: indirect and implicit
4.3.2. Transaction originator: direct and explicit
4.4. Implementing a transactional client
4.5. Implementing a recoverable server
4.5.1. Transactional object
4.5.2. Resource object
4.5.3. Reliable servers
4.5.4. Examples
4.6. Failure models
4.6.1. Transaction originator
4.6.2. Transactional server
4.7. Summary
5. JBossTS interfaces for extending the OTS
5.1. Nested transactions
5.2. Extended resources
5.3. AtomicTransaction
5.4. Context propagation issues
6. Example
6.1. The basic example
6.1.1. Example implementation of the interface
6.2. Default settings
7. Trail map
7.1. Introduction
7.2. Overview of the X/Open DTP model
7.3. Interface between functional components
7.4. Overview of the Distributed Transaction Processing
7.5. Example
7.5.1. Transactional Concepts
7.5.2. Transaction Components
7.5.3. Application Programs
7.5.4. Standards
7.5.5. Overview of the OMG Object Transaction Service
7.5.6. Application programming models
7.5.7. Examples
7.6. OTS Interfaces
7.7. Managing Transactions in Java EE
7.7.1. JTA/JTS Architecture
7.7.2. Java Transaction API
7.7.3. Java Transaction API - Usage
7.8. Managing Transactions in EJB
7.8.1. An Application Server Model - The Enterprise Java Beans
7.9. JDBC and Transactions
7.10. Configuring the JBoss Transaction Service
7.10.1. Properties File
7.10.2. ObjectStore management
7.10.3. Configuring Output
7.11. ORB Portability
7.11.1. Introduction
7.11.2. The ORB Portability API
7.11.3. Using the ORB
7.11.4. Using the Object Adapater (OA)
7.11.5. Example
7.11.6. Specifying the ORB to use
7.11.7. JBossTS Failure Recovery
7.11.8. The Recovery Manager
7.11.9. Configuring the Recovery Manager
7.11.10. Periodic Recovery
7.11.11. Expired entry removal
7.12. Installation Content
7.12.1. Verifying Installation
7.12.2. Testing your installation
7.12.3. Setting properties
7.13. Specifying the ORB to use
7.14. Overview of the Distributed Transaction Processing
7.15. Example
7.15.1. What is a Transaction?
7.15.2. Transactional Concepts
7.16. JBossTS Overview
7.16.1. Key features
7.17. The Sample Application
7.17.1. The Banking Application
7.17.2. Deploying and Testing The Banking Application
7.18. Making the Banking Application Persistent
7.19. What is Transactional Object For Java
7.19.1. Recovery and Persistency
7.19.2. The concurrency controller
7.19.3. Further Reading
7.19.4. Making the Banking Application Persistent with Transactional Object For Java
7.19.5. Developing applications with JDBC and JBossTS JTS
7.20. Recovery From Failure Examples
7.20.1. Introduction
7.20.2. Running the Recovery Manager
7.20.3. The Recovery Process and XAResources
8. Failure Recovery
8.1. Configuring the failure recovery subsystem for your ORB
8.2. JTS specific recovery
8.2.1. XA resource recovery
8.2.2. Recovery behavior
8.2.3. Expired entry removal
8.2.4. Recovery domains
8.3. Transaction status and replay_comparison
9. JTA and JTS
9.1. Distributed JTA
10. ORB-specific configuration
10.1. JacORB
A. IDL definitions
References
B. Revision History

This manual uses several conventions to highlight certain words and phrases and draw attention to specific pieces of information.

In PDF and paper editions, this manual uses typefaces drawn from the Liberation Fonts set. The Liberation Fonts set is also used in HTML editions if the set is installed on your system. If not, alternative but equivalent typefaces are displayed. Note: Red Hat Enterprise Linux 5 and later includes the Liberation Fonts set by default.

Four typographic conventions are used to call attention to specific words and phrases. These conventions, and the circumstances they apply to, are as follows.

Mono-spaced Bold

Used to highlight system input, including shell commands, file names and paths. Also used to highlight keycaps and key combinations. For example:

The above includes a file name, a shell command and a keycap, all presented in mono-spaced bold and all distinguishable thanks to context.

Key combinations can be distinguished from keycaps by the hyphen connecting each part of a key combination. For example:

The first paragraph highlights the particular keycap to press. The second highlights two key combinations (each a set of three keycaps with each set pressed simultaneously).

If source code is discussed, class names, methods, functions, variable names and returned values mentioned within a paragraph will be presented as above, in mono-spaced bold. For example:

Proportional Bold

This denotes words or phrases encountered on a system, including application names; dialog box text; labeled buttons; check-box and radio button labels; menu titles and sub-menu titles. For example:

The above text includes application names; system-wide menu names and items; application-specific menu names; and buttons and text found within a GUI interface, all presented in proportional bold and all distinguishable by context.

Mono-spaced Bold Italic or Proportional Bold Italic

Whether mono-spaced bold or proportional bold, the addition of italics indicates replaceable or variable text. Italics denotes text you do not input literally or displayed text that changes depending on circumstance. For example:

Note the words in bold italics above — username, domain.name, file-system, package, version and release. Each word is a placeholder, either for text you enter when issuing a command or for text displayed by the system.

Aside from standard usage for presenting the title of a work, italics denotes the first use of a new and important term. For example:

A transaction is a unit of work that encapsulates multiple database actions such that that either all the encapsulated actions fail or all succeed.

Transactions ensure data integrity when an application interacts with multiple datasources.

Practical Example

If you subscribe to a newspaper using a credit card, you are using a transactional system. Multiple systems are involved, and each of the systems needs the ability to roll back its work, and cause the entire transaction to roll back if necessary. For instance, if the newspaper's subscription system goes offline halfway through your transaction, you don't want your credit card to be charged. If the credit card is over its limit, the newspaper doesn't want your subscription to go through. In either of these cases, the entire transaction should fail of any part of it fails. Neither you as the customer, nor the newspaper, nor the credit card processor, wants an unpredictable (indeterminate) outcome to the transaction.

This ability to roll back an operation if any part of it fails is what JBoss Transactions is all about. This guide assists you in writing transactional applications to protect your data.

"Transactions" in this guide refers to atomic transactions, and embody the "all-or-nothing" concept outlined above. Transactions are used to guarantee the consistency of data in the presence of failures. Transactions fulfill the requirements of ACID: Atomicity, Consistency, Isolation, Durability.

A transaction can be terminated in two ways: committed or aborted (rolled back). When a transaction is committed, all changes made within it are made durable (forced on to stable storage, e.g., disk). When a transaction is aborted, all of the changes are undone. Atomic actions can also be nested; the effects of a nested action are provisional upon the commit/abort of the outermost (top-level) atomic action.

A two-phase commit protocol guarantees that all of the transaction participants either commit or abort any changes made. Figure 1.1, “Two-Phase Commit” illustrates the main aspects of the commit protocol.

Figure 1.1. Two-Phase Commit


Given a system that provides transactions for certain operations, you can combine them to form another operation, which is also required to be a transaction. The resulting transaction’s effects are a combination of the effects of its constituent transactions. This paradigm creates the concept of nested subtransactions, and the resulting combined transaction is called the enclosing transaction. The enclosing transaction is sometimes referred to as the parent of a nested (or child) transaction. It can also be viewed as a hierarchical relationship, with a top-level transaction consisting of several subordinate transactions.

An important difference exists between nested and top-level transactions.

The effect of a nested transaction is provisional upon the commit/roll back of its enclosing transactions. The effects are recovered if the enclosing transaction aborts, even if the nested transaction has committed.

Subtransactions are a useful mechanism for two reasons:

The CORBA architecture, as defined by the OMG, is a standard which promotes the construction of interoperable applications that are based upon the concepts of distributed objects. The architecture principally contains the following components:

The CORBA architecture allows both implementation and integration of a wide variety of object systems. In particular, applications are independent of the location of an object and the language in which an object is implemented, unless the interface the object explicitly supports reveals such details. As defined in the OMG CORBA Services documentation, object services are defined as a collection of services (interfaces and objects) that support the basic functions for using and implementing objects. These services are necessary to construct distributed application, and are always independent of an application domain. The standards specify several core services including naming, event management, persistence, concurrency control and transactions.

The transaction service provides interfaces that allow multiple distributed objects to cooperate in a transaction, committing or rolling back their changes as a group. However, the OTS does not require all objects to have transactional behavior. An object's support of transactions can be none at all, for some operations, or fully. Transaction information may be propagated between client and server explicitly, or implicitly. You have fine-grained control over an object's support of transactions. If your objects supports partial or complete transactional behavior, it needs interfaces derived from interface TransactionalObject.

The Transaction Service specification also distinguishes between recoverable objects and transactional objects. Recoverable objects are those that contain the actual state that may be changed by a transaction and must therefore be informed when the transaction commits or aborts to ensure the consistency of the state changes. This is achieved be registering appropriate objects that support the Resource interface (or the derived SubtransactionAwareResource interface) with the current transaction. Recoverable objects are also by definition transactional objects.

In contrast, a simple transactional object does not necessarily need to be recoverable if its state is actually implemented using other recoverable objects. A simple transactional object does not need to participate the commit protocol used to determine the outcome of the transaction since it maintains no state information of its own.

The OTS is a protocol engine that guarantees obedience to transactional behavior. It does not directly support all of the transaction properties, but relies on some cooperating services:

Persistence/Recovery Service

Supports properties of atomicity and durability.

Concurrency Control Service

Supports the isolation properties.

You are responsible for using the appropriate services to ensure that transactional objects have the necessary ACID properties.

JBossTS is based upon the original Arjuna system developed at the University of Newcastle between 1986 and 1995. Arjuna predates the OTS specification and includes many features not found in the OTS. JBossTS is a superset of the OTS. Applications written using the standard OTS interfaces are portable across OTS implementations.

You can use JBossTS in three different levels, which correspond to the sections in this chapter, and are each explored in their own chapters as well.

Because of differences in ORB implementations, JBossTS uses a separate ORB Portability library which acts as an abstraction later. Many of the examples used throughout this manual use this library. Refer to the ORB Portability Manual for more details.

The OTS does not provide any Resource implementations. You are responsible for implementing these interfaces. The interfaces defined within the OTS specification are too low-level for most application programmers. Therefore, JBossTS includes Transactional Objects for Java (TXOJ), which makes use of the raw Common Object Services interfaces but provides a higher-level API for building transactional applications and frameworks. This API automates much of the activities concerned with participating in an OTS transaction, freeing you to concentrate on application development, rather than transactions.

The architecture of the system is shown in Figure 2. The API interacts with the concurrency control and persistence services, and automatically registers appropriate resources for transactional objects. These resources may also use the persistence and concurrency services.

JBossTS exploits object-oriented techniques to provide you with a toolkit of Java classes which are inheritable by application classes, to obtain transactional properties. These classes form a hierarchy, illustrated in Figure 2.1, “JBossTS class hierarchy”.

Figure 2.1. JBossTS class hierarchy


Your main responsibilities are specifying the scope of transactions and setting appropriate locks within objects. JBossTS guarantees that transactional objects will be registered with, and be driven by, the appropriate transactions. Crash recovery mechanisms are invoked automatically in the event of failures. When using the provided interfaces, you do not need to create or register Resource objects or call services controlling persistence or recovery. If a transaction is nested, resources are automatically propagated to the transaction’s parent upon commit.

The design and implementation goal of JBossTS was to provide a programming system for constructing fault-tolerant distributed applications. Three system properties were considered highly important:

Integration of Mechanisms

Fault-tolerant distributed systems require a variety of system functions for naming, locating and invoking operations upon objects, as well as for concurrency control, error detection and recovery from failures. These mechanisms are integrated in a way that is easy for you to use.

Flexibility

Mechanisms must be flexible, permitting implementation of application-specific enhancements, such as type-specific concurrency and recovery control, using system defaults.

Portability

You need to be able to run JBossTS on any ORB.

JBossTS is implemented in Java and extensively uses the type-inheritance facilities provided by the language to provide user-defined objects with characteristics such as persistence and recoverability.

The OTS specification is written with flexibility in mind, to cope with different application requirements for transactions. JBossTS supports all optional parts of the OTS specification. In addition, if the specification allows functionality to be implemented in a variety of different ways, JBossTS supports all possible implementations.

Table 2.1. JBossTS implementation of OTS specifications

OTS specificationJBossTS default implementation

If the transaction service chooses to restrict the availability of the transaction context, then it should raise the Unavailable exception.

JBossTS does not restrict the availability of the transaction context.

An implementation of the transaction service need not initialize the transaction context for every request.

JBossTS only initializes the transaction context if the interface supported by the target object extends the TransactionalObject interface.

An implementation of the transaction service may restrict the ability for the Coordinator, Terminator, and Control objects to be transmitted or used in other execution environments to enable it to guarantee transaction integrity.

JBossTS does not impose restrictions on the propagation of these objects.

The transaction service may restrict the termination of a transaction to the client that started it.

JBossTS allows the termination of a transaction by any client that uses the Terminator interface. In addition, JBossTS does not impose restrictions when clients use the Current interface.

A TransactionFactory is located using the FactoryFinder interface of the life-cycle service.

JBossTS provides multiple ways in which the TransactionFactory can be located.

A transaction service implementation may use the Event Service to report heuristic decisions.

JBossTS does not use the Event Service to report heuristic decisions.

An implementation of the transaction service does not need to support nested transactions.

JBossTS supports nested transactions.

Synchronization objects must be called whenever the transaction commits.

JBossTS allows Synchronizations to be called no matter what state the transaction terminates with.

A transaction service implementation is not required to support interposition.

JBossTS supports various types of interposition.


Basic JBossTS programming involves using the OTS interfaces provided in the CosTransactions module, which is specified in CosTransactions.idl. This chapter is based on the OTS Specification1, specifically with the aspects of OTS that are valuable for developing OTS applications using JBossTS. Where relevant, each section describes JBossTS implementation decisions and runtime choices available to you. These choices are also summarized at the end of this chapter. Subsequent chapters illustrate using these interfaces to construct transactional applications.

A client application program can manage a transaction using direct or indirect context management.

An object may require transactions to be either explicitly or implicitly propagated to its operations.

A client may use one or both forms of context management, and may communicate with objects that use either method of transaction propagation. This results in four ways in which client applications may communicate with transactional objects:

Direct Context Management/Explicit Propagation

The client application directly accesses the Control object, and the other objects which describe the state of the transaction. To propagate the transaction to an object, the client must include the appropriate Transaction Service object as an explicit parameter of an operation. Typically, the object is the PropagationContext structure.

Indirect Context Management/Implicit Propagation

The client application uses operations on the Current pseudo-object to create and control its transactions. When it issues requests on transactional objects, the transaction context associated with the current thread is implicitly propagated to the object.

Indirect Context Management/Explicit Propagation

for an implicit model application to use explicit propagation, it can get access to the Control using the get_control operation on the Current pseudo object. It can then use a Transaction Service object as an explicit parameter to a transactional object; for efficiency reasons this should be the PropagationContext structure, obtained by calling get_txcontext on the appropriate Coordinator reference. This is explicit propagation.

Direct Context Management/Implicit Propagation

A client that accesses the Transaction Service objects directly can use the resume pseudo-object operation to set the implicit transaction context associated with its thread. This way, the client can invoke operations of an object that requires implicit propagation of the transaction context.

The main difference between direct and indirect context management is the effect on the invoking thread’s transaction context. Indirect context management causes the thread’s transaction context to be modified automatically by the OTS. For instance, if method begin is called, the thread’s notion of the current transaction is modified to the newly-created transaction. When the transaction is terminated, the transaction previously associated with the thread, if one existed, is restored as the thread’s context. This assumes that subtransactions are supported by the OTS implementation.

If you use direct management, no changes to the thread's transaction context are made by the OTS, leaving the responsibility to you.

The TransactionFactory interface allows the transaction originator to begin a top-level transaction. Subtransactions must be created using the begin method of Current, or the create_subtransaction method of the parent’s Coordinator.) Operations on the factory and Coordinator to create new transactions use direct context management, and therefore do not modify the calling thread’s transaction context.

The create operation creates a new top-level transaction and returns its Control object, which you can use to manage or control participation in the new transaction. Method create takes a parameter that is is an application-specific timeout value, in seconds. If the transaction does not complete before this timeout elapses, it is rolled back. If the parameter is 0, no application-specific timeout is established.

The Transaction Service implementation allows the TransactionFactory to be a separate server from the application, shared by transactions clients, and which manages transactions on their behalf. However, the specification also allows the TransactionFactory to be implemented by an object within each transactional client. This is the default implementation used by JBossTS, because it removes the need for a separate service to be available in order for transactional applications to execute, and therefore reduces a point of failure.

If your applications require a separate transaction manager, set the OTS_TRANSACTION_MANAGER environment variable to the value YES. The system locates the transaction manager server in a manner specific to the ORB being used. The server can be located in a number of ways.

You can override the default location mechanism with the RESOLVE_SERVICE property variable, which can have any of three possible values.

CONFIGURATION_FILE

This is the default option, and directs the system to use the CosServices.cfg file.

NAME_SERVICE

JBossTS tries to use a name service to locate the transaction factory. If the ORB does not support the name service mechanism, JBossTS throws an exception.

BIND_CONNECT

JBossTS uses the ORB-specific bind mechanism. If the ORB does not support such a mechanism, JBossTS throws an exception.

If RESOLVE_SERVICE is specified when running the transaction factory, the factory registers itself with the specified resolution mechanism.

Transaction contexts are fundamental to the OTS architecture. Each thread is associated with a context in one of three ways.

Null

The thread has no associated transaction.

A transaction IDThe thread is associated with a transaction.

Contexts may be shared across multiple threads. In the presence of nested transactions, a context remembers the stack of transactions started within the environment, so that the context of the thread can be restored to the state before the nested transaction started, when the nested transaction ends. Threads most commonly use object Current to manipulate transactional information, which is represented by Control objects. Current is the broker between a transaction and Control objects.

Your application can manage transaction contexts either directly or indirectly. In the direct approach, the transaction originator issues a request to a TransactionFactory to begin a new top-level transaction. The factory returns a Control object that enables both a Terminator interface and a Coordinator interface. Terminator ends a transaction. Coordinator associates a thread with a transaction, or begins a nested transaction. You need to pass each interface as an explicit parameter in invocations of operations, because creating a transaction with them does not change a thread's current context. If you use the factory, and need to set the current context for a thread to the context which its control object returns, use the resume method of interface Current.


When the factory creates a transaction, you can specify a timeout value in seconds. If the transaction times out, it is subject to possible roll-back. Set the timeout to 0 to disable application-specific timeout.

The Current interface handles implicit context management. Implicit context management provides simplified transaction management functionality, and automatically creates nested transactions as required. Transactions created using Current do not alter a thread’s current transaction context.


Subtransactions are a useful mechanism for two reasons:

The outermost transaction of the hierarchy formed by nested transactions is called the top-level transaction. The inner components are called subtransactions. Unlike top-level transactions, the commits of subtransactions depend upon the commit/rollback of the enclosing transactions. Resources acquired within a subtransaction should be inherited by parent transactions when the top-level transaction completes. If a subtransaction rolls back, it can release its resources and undo any changes to its inherited resources.

In the OTS, subtransactions behave differently from top-level transactions at commit time. Top-level transactions undergo a two-phase commit protocol, but nested transactions do not actually perform a commit protocol themselves. When a program commits a nested transaction, it only informs registered resources of its outcome. If a resource cannot commit, an exception is thrown, and the OTS implementation can ignore the exception or roll back the subtransaction. You cannot roll back a subtransaction if any resources have been informed that the transaction committed.

The OTS supports both implicit and explicit propagation of transactional behavior.

Transaction context management and transaction propagation are different things that may be controlled independently of each other. Mixing of direct and indirect context management with implicit and explicit transaction propagation is supported. Using implicit propagation requires cooperation from the ORB. The client must send current context associated with the thread with any operation invocations, and the server must extract them before calling the targeted operation.

If you need implicit context propagation, ensure that JBossTS is correctly initialized before you create objects. Both client and server must agree to use implicit propagation. To use implicit context propagation, your ORB needs to support filters or interceptors, or the CosTSPortability interface.

Implicit context propagation

Property variable OTS_CONTEXT_PROP_MODE set to CONTEXT.

Interposition

Property variable OTS_CONTEXT_PROP_MODE set to INTERPOSITION.


The next example rewrites the same program to use indirect context management and implicit propagation. This example is considerably simpler, because the application only needs to start and either commit or abort actions.


The last example illustrates the flexibility of OTS by using both direct and indirect context management in conjunction with explicit and implicit transaction propagation.


The Control interface allows a program to explicitly manage or propagate a transaction context. An object supporting the Control interface is associated with one specific transaction. The Control interface supports two operations: get_terminator and get_coordinator. get_terminator returns an instance of the Terminator interface. get_coordinator returns an instance of the Coordinator interface. Both of these methods throw the Unavailable exception if the Control cannot provide the requested object. The OTS implementation can restrict the ability to use the Terminator and Coordinator in other execution environments or threads. At a minimum, the creator must be able to use them.

Obtain the Control object for a transaction when it is created either by using either the TransactionFactory or create_subtransaction methods defined by the Coordinator interface. Obtain a Control for the transaction associated with the current thread using the get_control or suspend methods defined by the Current interface.

The Terminator interface supports commit and rollback operations. Typically, the transaction originator uses these operations. Each object supporting the Terminator interface is associated with a single transaction. Direct context management via the Terminator interface does not change the client thread’s notion of the current transaction.

The commit operation attempts to commit the transaction. To successfully commit, the transaction must not be marked rollback only, and all of its must participants agree to commit. Otherwise, the TRANSACTION_ROLLEDBACK exception is thrown. If the report_heuristics parameter is true, the Transaction Service reports inconsistent results using the HeuristicMixed and HeuristicHazard exceptions.

When a transaction is committed, the coordinator drives any registered Resources using their prepare or commit methods. These Resources are responsible to ensure that any state changes to recoverable objects are made permanent, to guarantee the ACID properties.

When rollback is called, the registered Resources need to guarantee that all changes to recoverable objects made within the scope of the transaction, and its descendants, is undone. All resources locked by the transaction are made available to other transactions, as appropriate to the degree of isolation the resources enforce.

See Section 3.7.1, “JBossTS specifics” for how long Terminator references remain valid after a transaction terminates.

When a transaction is committing, it must make certain state changes persistent, so that it can recover if a failure occurs, and continue to commit, or rollback. To guarantee ACID properties, flush these state changes to the persistence store implementation before the transaction proceeds to commit. Otherwise, the application may assume that the transaction has committed, when the state changes may still volatile storage, and may be lost by a subsequent hardware failure. By default, JBossTS makes sure that such state changes are flushed. However, these flushes can impose a significant performance penalty to the application. To prevent transaction state flushes, set the TRANSACTION_SYNC variable to OFF. Obviously, do this at your own risk.

When a transaction commits, if only a single resource is registered, the transaction manager does not need to perform the two-phase protocol. A single phase commit is possible, and the outcome of the transaction is determined by the resource. In a distributed environment, this optimization represents a significant performance improvement. As such, JBossTS defaults to performing single phase commit in this situation. Override this behavior at runtime by setting the COMMIT_ONE_PHASE property variable to NO.

The Coordinator interface is returned by the get_coordinator method of the Control interface. It supports the operations resources need to participate in a transaction. These participants are usually either recoverable objects or agents of recoverable objects, such as subordinate coordinators. Each object supporting the Coordinator interface is associated with a single transaction. Direct context management via the Coordinator interface does not change the client thread’s notion of the current transaction. You can terminate transaction directly, through the Terminator interface. In that case, trying to terminate the transaction a second time using Current causes an exception to be thrown for the second termination attempt.

The operations supported by the Coordinator interface of interest to application programmers are:

Table 3.2. Operations supported by the Coordinator interface

get_status

get_parent_status

get_top_level_status

Return the status of the associated transaction. At any given time a transaction can have one of the following status values representing its progress:

StatusActive

The transaction is currently running, and has not been asked to prepare or marked for rollback.

StatusMarkedRollback

The transaction is marked for rollback.

StatusPrepared

The transaction has been prepared, which means that all subordinates have responded VoteCommit.

StatusCommitted

The transaction has committed. It is likely that heuristics exist. Otherwise, the transaction would have been destroyed and StatusNoTransaction returned.

StatusRolledBack

The transaction has rolled back. It is likely that heuristics exist. Otherwise. the transaction would have been destroyed and StatusNoTransaction returned.

StatusUnknown

The Transaction Service cannot determine the current status of the transaction. This is a transient condition, and a subsequent invocation should return a different status.

StatusNoTransaction

No transaction is currently associated with the target object. This occurs after a transaction completes.

StatusPreparing

The transaction is in the process of preparing and the final outcome is not known.

StatusCommitting

The transaction is in the process of committing.

StatusRollingBack

The transaction is in the process of rolling back.

is_same_transaction and others

You can use these operations for transaction comparison. Resources may use these various operations to guarantee that they are registered only once with a specific transaction.

hash_transaction

hash_top_level_tran

Returns a hash code for the specified transaction.

register_resource

Registers the specified Resource as a participant in the transaction. The Inactive exception is raised if the transaction is already prepared. The TRANSACTION_ROLLEDBACK exception is raised if the transaction is marked rollback only. If the Resource is a SubtransactionAwareResource and the transaction is a subtransaction, this operation registers the resource with this transaction and indirectly with the top-level transaction when the subtransaction’s ancestors commit. Otherwise, the resource is only registered with the current transaction. This operation returns a RecoveryCoordinator which this Resource can use during recovery. No ordering of registered Resources is implied by this operation. If A is registered after B, the OTS can operate on them in any order when the transaction terminates. Therefore, do not assume such an ordering exists in your implementation.

register_subtran_aware

Registers the specified subtransaction-aware resource with the current transaction, so that it know when the subtransaction commits or rolls back. This method cannot register the resource as a participant in the top-level transaction. The NotSubtransaction exception is raised if the current transaction is not a subtransaction. As with register_resource, no ordering is implied by this operation.

register_synchronization

Registers the Synchronization object with the transaction so that will be invoked before prepare and after the transaction completes. Synchronizations can only be associated with top-level transactions, and the SynchronizationsUnavailable exception is raised if you try to register a Synchronization with a subtransaction. As with register_resource, no ordering is implied by this operation.

rollback_only

Marks the transaction so that the only possible outcome is for it to rollback. The Inactive exception is raised if the transaction has already been prepared/completed.

create_subtransaction

A new subtransaction is created. Its parent is the current transaction. The Inactive exception is raised if the current transaction has already been prepared or completed. If you configure the Transaction Service without subtransaction support, the SubtransactionsUnavailable exception is raised.


See Section 3.7.1, “JBossTS specifics” to control how long Coordinator references remain valid after a transaction terminates.

Note

To disable subtransactions, set set the OTS_SUPPORT_SUBTRANSACTIONS property variable to NO.

The Current interface defines operations that allow a client to explicitly manage the association between threads and transactions, using indirect context management. It defines operations that simplify the use of the Transaction Service.

Table 3.4. Methods of Current

begin

Creates a new transaction and associates it with the current thread. If the client thread is currently associated with a transaction, and the OTS implementation supported nested transactions, the new transaction becomes a subtransaction of that transaction. Otherwise, the new transaction is a top-level transaction. If the OTS implementation does not support nested transactions, the SubtransactionsUnavailable exception is thrown. The thread’s notion of the current context is modified to be this transaction.

commit

Commits the transaction. If the client thread does not have permission to commit the transaction, the standard exception NO_PERMISSION is raised. The effect is the same as performing the commit operation on the corresponding Terminator object. The client thread's transaction context is returned to its state before the begin request was initiated.

rollback

Rolls back the transaction. If the client thread does not have permission to terminate the transaction, the standard exception NO_PERMISSION is raised. The effect is the same as performing the rollback operation on the corresponding Terminator object. The client thread's transaction context is returned to its state before the begin request was initiated.

rollback_only

Limits the transaction's outcome to rollback only. If the transaction has already been terminated, or is in the process of terminating, an appropriate exception is thrown.

get_status

Returns the status of the current transaction, or exception StatusNoTransaction if no transaction is associated with the thread.

set_timeout

Modifies the timeout associated with top-level transactions for subsequent begin requests, for this thread only. Subsequent transactions are subject to being rolled back if they do not complete before the specified number of seconds elapses. Default timeout values for transactions without explicitly-set timeouts are implementation-dependent. JBossTS uses a value of 0, which results in transactions never timing out. There is no interface in the OTS for obtaining the current timeout associated with a thread. However, JBossTS provides additional support for this. See Section 3.11.1, “JBossTS specifics”.

get_control

Obtains a Control object representing the current transaction. If the client thread is not associated with a transaction, a null object reference is returned. The operation is not dependent on the state of the transaction. It does not raise the TRANSACTION_ROLLEDBACK exception.

suspend

Obtains an object representing a transaction's context. If the client thread is not associated with a transaction, a null object reference is returned. You can pass this object to the resume operation to re-establish this context in a thread. The operation is not dependent on the state of the transaction. It does not raise the TRANSACTION_ROLLEDBACK exception. When this call returns, the current thread has no transaction context associated with it.

resume

Associates the client thread with a transaction. If the parameter is a null object reference, the client thread becomes associated with no transaction. The thread loses association with any previous transactions.


Figure 3.2. Creation of a top-level transaction using Current


Figure 3.3. Creation of a transaction using Current


Ideally, you should Obtain Current by using the life-cycle service factory finder. However, very few ORBs support this. JBossTS provides method get_current of Current for this purpose. This class hides any ORB-specific mechanisms required for obtaining Current.

If no timeout value is associated with Current, JBossTS associates no timeout with the transaction. The current OTS specification does not provide a means whereby the timeout associated with transaction creation can be obtained. However, JBossTS Current supports a get_timeout method.

By default, the JBossTS implementation of Current does not use a separate TransactionFactory server when creating new top-level transactions. Each transactional client has a TransactionFactory co-located with it. Override this by setting the OTS_TRANSACTION_MANAGER variable to YES.

The transaction factory is located in the bin/ directory of the JBossTS distribution. Start it by executing the OTS script. Current locates the factory in a manner specific to the ORB: using the name service, through resolve_initial_references, or via the CosServices.cfg file. The CosServices.cfg file is similar to resolve_initial_references, and is automatically updated when the transaction factory is started on a particular machine. Copy the file to each JBossTS instance which needs to share the same transaction factory.

If you do not need subtransaction support, set the OTS_SUPPORT_SUBTRANSACTIONS property variable to NO. The setCheckedAction method overrides the CheckedAction implementation associated with each transaction created by the thread.

The Transaction Service uses a two-phase commit protocol to complete a top-level transaction with each registered resource.


The Resource interface defines the operations invoked by the transaction service. Each Resource object is implicitly associated with a single top-level transaction. Do not register a Resource with the same transaction more than once. When you tell a Resource to prepare, commit, or abort, it must do so on behalf of a specific transaction. However, the Resource methods do not specify the transaction identity. It is implicit, since a Resource can only be registered with a single transaction.

Transactional objects must use the register_resource method to register objects supporting the Resource interface with the current transaction. An object supporting the Coordinator interface is either passed as a parameter in the case of explicit propagation, or retrieved using operations on the Current interface in the case of implicit propagation. If the transaction is nested, the Resource is not informed of the subtransaction’s completion, and is registered with its parent upon commit.

This example assumes that transactions are only nested two levels deep, for simplicity.

Figure 3.4. Resource and nested transactions


Do not register a given Resource with the same transaction more than once, or it will receive multiple termination calls. When a Resource is directed to prepare, commit, or abort, it needs to link these actions to a specific transaction. Because Resource methods do not specify the transaction identity, but can only be associated with a single transaction, you can infer the identity.

A single Resource or group of Resources guarantees the ACID properties for the recoverable object they represent. A Resource's work depends on the phase of its transaction.

prepare

If none of the persistent data associated with the resource is modified by the transaction, the Resource can return VoteReadOnly and forget about the transaction. It does not need to know the outcome of the second phase of the commit protocol, since it hasn't made any changes.

If the resource can write, or has already written, all the data needed to commit the transaction to stable storage, as well as an indication that it has prepared the transaction, it can return VoteCommit. After receiving this response, the Transaction Service either commits or rolls back. To support recovery, the resource should store the RecoveryCoordinator reference in stable storage.

The resource can return VoteRollback under any circumstances. After returning this response, the resource can forget the transaction.

The Resource reports inconsistent outcomes using the HeuristicMixed and HeuristicHazard exceptions. One example is that a Resource reports that it can commit and later decides to roll back. Heuristic decisions must be made persistent and remembered by the Resource until the transaction coordinator issues the forget method. This method tells the Resource that the heuristic decision has been noted, and possibly resolved.

rollback

The resource should undo any changes made as part of the transaction. Heuristic exceptions can be used to report heuristic decisions related to the resource. If a heuristic exception is raised, the resource must remember this outcome until the forget operation is performed so that it can return the same outcome in case rollback is performed again. Otherwise, the resource can forget the transaction.

commit

If necessary, the resource should commit all changes made as part of this transaction. As with rollback, it can raise heuristic exceptions. The NotPrepared exception is raised if the resource has not been prepared.

commit_one_phase

Since there can be only a single resource, the HeuristicHazard exception reports heuristic decisions related to that resource.

forget

Performed after the resource raises a heuristic exception. After the coordinator determines that the heuristic situation is addressed, it issues forget on the resource. The resource can forget all knowledge of the transaction.

Recoverable objects that need to participate within a nested transaction may support the SubtransactionAwareResource interface, a specialization of the Resource interface.


A recoverable object is only informed of the completion of a nested transaction if it registers a SubtransactionAwareResource. Register the object with either the register_resource of the Coordinator interface, or the register_subtran_aware method of the Current interface. A recoverable object registers Resources to participate within the completion of top-level transactions, and SubtransactionAwareResources keep track of the completion of subtransactions. The commit_subtransaction method uses a reference to the parent transaction to allow subtransaction resources to register with these transactions.

SubtransactionAwareResources find out about the completion of a transaction after it terminates. They cannot affect the outcome of the transaction. Different OTS implementations deal with exceptions raised by SubtransactionAwareResources in implementation-specific ways.

Use method register_resource or method register_subtran_aware to register a SubtransactionAwareResource with a transaction using.

register_resource

If the transaction is a subtransaction, the resource is informed of its completion, and automatically registered with the subtransaction’s parent if the parent commits.

register_subtran_aware

If the transaction is not a subtransaction, an exception is thrown. Otherwise, the resource is informed when the subtransaction completes. Unlike register_resource, the resource is not propagated to the subtransaction’s parent if the transaction commits. If you need this propagation, re-register using the supplied parent parameter.

Figure 3.5. Method register_subtran_aware


Figure 3.6. Method register_resource


In either case, the resource cannot affect the outcome of the transaction completion. It can only act on the transaction's decision, after the decision is made. However, if the resource cannot respond appropriately, it can raise an exception. Thee OTS handles these exceptions in an implementation-specific way.

If an object needs notification before a transaction commits, it can register an object which is an implements the Synchronization interface, using the register_synchronization operation of the Coordinator interface. Synchronizations flush volatile state data to a recoverable object or database before the transaction commits. You can only associate Synchronizations with top-level transactions. If you try to associate a Synchronization to a nested transaction, an exception is thrown. Each object supporting the Synchronization interface is associated with a single top-level transaction.


The method before_completion is called before the two-phase commit protocol starts, and after_completion is called after the protocol completes. The final status of the transaction is given as a parameter to after_completion. If before_completion raises an exception, the transaction rolls back. Any exceptions thrown by after_completion do not affect the transaction outcome.

The OTS only requires Synchronizations to be invoked if the transaction commits. If it rolls back, registered Synchronizations are not informed.

Given the previous description of Control, Resource, SubtransactionAwareResource, and Synchronization, the following UML relationship diagram can be drawn:

Figure 3.7. Relationship between Control, Resource, SubtransactionAwareResource, and Synchronization


Synchronizations must be called before the top-level transaction commit protocol starts, and after it completes. By default, if the transaction is instructed to roll back, the Synchronizations associated with the transaction is not contacted. To override this, and call Synchronizations regardless of the transaction's outcome, set the OTS_SUPPORT_ROLLBACK_SYNC property variable to YES.

If you use distributed transactions and interposition, a local proxy for the top-level transaction coordinator is created for any recipient of the transaction context. The proxy looks like a Resource or SubtransactionAwareResource, and registers itself as such with the actual top-level transaction coordinator. The local recipient uses it to register Resources and Synchronizations locally.

The local proxy can affect how Synchronizations are invoked during top-level transaction commit. Without the proxy, all Synchronizations are invoked before any Resource or SubtransactionAwareResource objects are processed. However, with interposition, only those Synchronizations registered locally to the transaction coordinator are called. Synchronizations registered with remote participants are only called when the interposed proxy is invoked. The local proxy may only be invoked after locally-registered Resource or SubtransactionAwareResource objects are invoked. With the OTS_SUPPORT_INTERPOSED_SYNCHRONIZATION property variable set to YES, all Synchronizations are invoked before any Resource or SubtransactionAwareResource, no matter where they are registered.

Figure 3.8. Relationship between a transaction Control and the resources registered with it


In Figure 3.9, “Subtransaction commit”, a subtransaction with both Resource and SubtransactionAwareResource objects commits. The SubtransactionAwareResources were registered using register_subtran_aware. The Resources do not know the subtransaction terminated, but the SubtransactionAwareResources do. Only the Resources are automatically propagated to the parent transaction.

Figure 3.9. Subtransaction commit


Figure 3.10, “Subtransaction rollback” illustrates the impact of a subtransaction rolling back. Any registered resources are discarded, and all SubtransactionAwareResources are informed of the transaction outcome.

Figure 3.10. Subtransaction rollback


Figure 3.11, “Top-level commit” shows the activity diagram for committing a top-level transaction. Subtransactions within the top-level transaction which have also successfully committed propagate SubtransactionAwareResources to the top-level transaction. These SubtransactionAwareResources then participate within the two-phase commit protocol. Any registered Synchronizations are contacted before prepare is called. Because of indirect context management, when the transaction commits, the transaction service changes the invoking thread’s transaction context.

Figure 3.11. Top-level commit


Figure 3.12. Top-level rollback


The TransactionalObject interface indicates to an object that it is transactional. By supporting this interface, an object indicates that it wants to associate the transaction context associated with the client thread with all operations on its interface. The TransactionalObject interface defines no operations.

OTS specifications do not require an OTS to initialize the transaction context of every request handler. It is only a requirement if the interface supported by the target object is derived from TransactionalObject. Otherwise, the initial transaction context of the thread is undefined. A transaction service implementation can raise the TRANSACTION_REQUIRED exception if a TransactionalObject is invoked outside the scope of a transaction.

In a single-address space application, transaction contexts are implicitly shared between clients and objects, regardless of whether or not the objects support the TransactionalObject interface. To preserve distribution transparency, where implicit transaction propagation is supported, you can direct JBossTS to always propagate transaction contexts to objects. The default is only to propagate if the object is a TransactionalObject. Set the OTS_ALWAYS_PROPAGATE_CONTEXT property variable to NO to override this behavior.

By default, JBossTS does not require objects which support the TransactionalObject interface to invoked within the scope of a transaction. The object determines whether it should be invoked within a transaction. If so, it must throw the TransactionRequired exception. Override this default by setting the OTS_NEED_TRAN_CONTEXT shell environment variable to YES.

OTS objects supporting interfaces such as the Control interface are standard CORBA objects. When an interface is passed as a parameter in an operation call to a remote server, only an object reference is passed. This ensures that any operations that the remote server performs on the interface are correctly performed on the real object. However, this can have substantial penalties for the application, because of the overhead of remote invocation. For example, when the server registers a Resource with the current transaction, the invocation might be remote to the originator of the transaction.

To avoid this overhead, your OTS may support interposition. This permits a server to create a local control object which acts as a local coordinator, and fields registration requests that would normally be passed back to the originator. This coordinator must register itself with the original coordinator, so that it can correctly participate in the commit protocol. Interposed coordinators form a tree structure with their parent coordinators.

To use interposition, ensure that JBossTS is correctly initialized before creating objects. Also, the client and server must both use interposition. Your ORB must support filters or interceptors, or the CosTSPortability interface, since interposition requires the use of implicit transaction propagation. To use interposition, set the OTS_CONTEXT_PROP_MODE property variable to INTERPOSITION.

The OTS supports both checked and unchecked transaction behavior.

Checked transactional behavior is typical transaction behavior, and is widely implemented. Checked behavior requires implicit propagation, because explicit propagation prevents the OTS from tracking which objects are involved in the transaction.

Unchecked behavior allows you to implement relaxed models of atomicity. Any use of explicit propagation implies the possibility of unchecked behavior, since you as the programmer are in control of the behavior. Even if you use implicit propagation, a server may unilaterally abort or commit the transaction using the Current interface, causing unchecked behavior.

Some OTS implementations enforce checked behavior for the transactions they support, to provide an extra level of transaction integrity. The checks ensure that all transactional requests made by the application complete their processing before the transaction is committed. A checked Transaction Service guarantees that commit fails unless all transactional objects involved in the transaction complete the processing of their transactional requests. Rolling back the transaction does not require such as check, since all outstanding transactional activities will eventually roll back if they are not directed to commit.

There are many possible implementations of checking in a Transaction Service. One provides equivalent function to that provided by the request and response inter-process communication models defined by X/Open. The X/Open Transaction Service model of checking widely implemented. It describes the transaction integrity guarantees provided by many existing transaction systems. These transaction systems provide the same level of transaction integrity for object-based applications, by providing a Transaction Service interface that implements the X/Open checks.

In X/Open, completion of the processing of a request means that the object has completed execution of its method and replied to the request. The level of transaction integrity provided by a Transaction Service implementing the X/Open model provides equivalent function to that provided by the XATMI and TxRPC interfaces defined by X/Open for transactional applications. X/Open DTP Transaction Managers are examples of transaction management functions that implement checked transaction behavior.

This implementation of checked behavior depends on implicit transaction propagation. When implicit propagation is used, the objects involved in a transaction at any given time form a tree, called the request tree for the transaction. The beginner of the transaction is the root of the tree. Requests add nodes to the tree, and replies remove the replying node from the tree. Synchronous requests, or the checks described below for deferred synchronous requests, ensure that the tree collapses to a single node before commit is issued.

If a transaction uses explicit propagation, the Transaction Service has no way to know which objects are or will be involved in the transaction. Therefore, the use of explicit propagation is not permitted by a Transaction Service implementation that enforces X/Open-style checked behavior.

Applications that use synchronous requests exhibit checked behavior. If your application uses deferred synchronous requests, all clients and objects need to be under the control of a checking Transaction Service. In that case, the Transaction Service can enforce checked behavior, by applying a reply check and a committed check. The Transaction Service must also apply a resume check, so that the transaction is only resumed by applications in the correct part of the request tree.

reply check

Before an object replies to a transactional request, a check is made to ensure that the object has received replies to all the deferred synchronous requests that propagated the transaction in the original request. If this condition is not met, an exception is raised and the transaction is marked as rollback-only. A Transaction Service may check that a reply is issued within the context of the transaction associated with the request.

commit check

Before a commit can proceed, a check is made to ensure that the commit request for the transaction is being issued from the same execution environment that created the transaction, and that the client issuing commit has received replies to all the deferred synchronous requests it made that propagated the transaction.

resume check

Before a client or object associates a transaction context with its thread of control, a check is made to ensure that this transaction context was previously associated with the execution environment of the thread. This association would exist if the thread either created the transaction or received it in a transactional operation.

Where support from the ORB is available, JBossTS supports X/Open checked transaction behavior. However, unless the OTS_CHECKED_TRANSACTIONS property variable is set to YES, checked transactions are disabled. This is the default setting.

In a multi-threaded application, multiple threads may be associated with a transaction during its lifetime, sharing the context. In addition, if one thread terminates a transaction, other threads may still be active within it. In a distributed environment, it can be difficult to guarantee that all threads have finished with a transaction when it terminates. By default, JBossTS issues a warning if a thread terminates a transaction when other threads are still active within it, but allow the transaction termination to continue. You can choose to block the thread which is terminating the transaction until all other threads have disassociated themselves from its context, or use other methods to solve the problem. JBossTS provides the com.arjuna.ats.arjuna.coordinator.CheckedAction class, which allows you to override the thread and transaction termination policy. Each transaction has an instance of this class associated with it, and you can implement the class on a per-transaction basis.


When a thread attempts to terminate the transaction and there active threads exist within it, the system invokes the check method on the transaction’s CheckedAction object. The parameters to the check method are:

isCommit

Indicates whether the transaction is in the process of committing or rolling back.

actUid

The transaction identifier.

list

A list of all of the threads currently marked as active within this transaction.

When check returns, the transaction termination continues. Obviously the state of the transaction at this point may be different from that when check was called.

Set the CheckedAction instance associated with a given transaction with the setCheckedAction method of Current.

The OTS does not provide any Resource implementations. You need to provide these implementations. The interfaces defined within the OTS specification are too low-level for most situations. JBossTS is designed to make use of raw Common Object Services (COS) interfaces, but provides a higher-level API for building transactional applications and framework. This API automates much of the work involved with participating in an OTS transaction.

If you use implicit transaction propagation, ensure that appropriate objects support the TransactionalObject interface. Otherwise, you need to pass the transaction contexts as parameters to the relevant operations.

A Recoverable Server includes at least one transactional object and one resource object, each of which have distinct responsibilities.

Example 4.3. Reliable server

/* 

  BankAccount1 is an object with internal resources. It inherits from both the TransactionalObject and the Resource interfaces:
*/
interface BankAccount1:
                    CosTransactions::TransactionalObject, CosTransactions::Resource
{
    ...
    void makeDeposit (in float amt);
    ...
};
/* The corresponding Java class is: */
public class BankAccount1
{
public void makeDeposit(float amt);
    ...
};
/*
  Upon entering, the context of the transaction is implicitly associated with the objects thread. The pseudo object
  supporting the Current interface is used to retrieve the Coordinator object associated with the transaction.
*/
void makeDeposit (float amt)
{
    org.omg.CosTransactions.Control c;
    org.omg.CosTransactions.Coordinator co;
    c = txn_crt.get_control();
    co = c.get_coordinator();
    ...
/*
  Before registering the resource the object should check whether it has already been registered for the same
  transaction. This is done using the hash_transaction and is_same_transaction operations.  that this object registers
  itself as a resource. This imposes the restriction that the object may only be involved in one transaction at a
  time. This is not the recommended way for recoverable objects to participate within transactions, and is only used as an
  example.  If more parallelism is required, separate resource objects should be registered for involvement in the same
  transaction.
*/
    RecoveryCoordinator r;
    r = co.register_resource(this);
    // performs some transactional activity locally
    balance = balance + f;
    num_transactions++;
    ...
    // end of transactional operation
};


The Transaction Service provides atomic outcomes for transactions in the presence of application, system or communication failures. From the viewpoint of each user object role, two types of failure are relevant:

The transaction originator and transactional server handle these failures in different ways.

Local failure

If a Transaction originator fails before the originator issues commit, the transaction is rolled back. If the originator fails after issuing commit and before the outcome is reported, the transaction can either commit or roll back, depending on timing. In this case, the transaction completes without regard to the failure of the originator.

External failure

Any external failure which affects the transaction before the originator issues commit causes the transaction to roll back. The standard exception TransactionRolledBack is raised in the originator when it issues commit.

If a failure occurs after commit and before the outcome is reported, the client may not be informed of the outcome of the transaction. This depends on the nature of the failure, and the use of the report_heuristics option of commit. For example, the transaction outcome is not reported to the client if communication between the client and the Coordinator fails.

A client can determine the outcome of the transaction by using method get_status on the Coordinator. However, this is not reliable because it may return the status NoTransaction, which is ambiguous. The transaction could have committed and been forgotten, or it could have rolled back and been forgotten.

An originator is only guaranteed to know the transaction outcome in one of two ways.

This chapter contains a description of the use of the JBossTS classes you can use to extend the OTS interfaces. These advanced interfaces are all written on top of the basic OTS engine described previously, and applications which use them run on other OTS implementations, only without the added functionality.

Features

AtomicTransaction

Provides a more manageable interface to the OTS transaction than CosTransactions::Current. It automatically keeps track of transaction scope, and allows you to create nested top-level transactions in a more natural manner than the one provided by the OTS.

Advanced subtransaction-Resource classes

Allow nested transactions to use a two-phase commit protocol. These Resources can also be ordered within JBossTS, enabling you to control the order in which Resources are called during the commit or abort protocol.

Implicit context propagation between client and server

Where available, JBossTS uses implicit context propagation between client and server. Otherwise, JBossTS provides an explicit interposition class, which simplifies the work involved in interposition. The JBossTS API, Transactional Objects for Java (TXOJ), requires either explicit or implicit interposition. This is even true in a stand-alone mode when using a separate transaction manager. TXOJ is fully described in the ArjunaCore Development Guide.

Note

the extensions to the CosTransactions.idl are located in the com.arjuna.ArjunaOTS package and the ArjunaOTS.idl file.

The OTS implementation of nested transactions is extremely limited, and can lead to the generation of inconsistent results. One example is a scenario in which a subtransaction coordinator discovers part of the way through committing that a resources cannot commit. It may not be able to tell the committed resources to abort.

In most transactional systems which support subtransactions, the subtransaction commit protocol is the same as a top-level transaction’s. There are two phases, a prepare phase and a commit or abort phase. Using a multi-phase commit protocol avoids the above problem of discovering that one resources cannot commit after others have already been told to commit. The prepare phase generates consensus on the commit outcome, and the commit or abort phase enforces the outcome.

JBossTS supports the strict OTS implementation of subtransactions for those resources derived from CosTransactions::SubtransactionAwareResource. However, if a resource is derived from ArjunaOTS::ArjunaSubtranAwareResource, it is driven by a two-phase commit protocol whenever a nested transaction commits.


During the first phase of the commit protocol the prepare_subtransaction method is called, and the resource behaves as though it were being driven by a top-level transaction, making any state changes provisional upon the second phase of the protocol. Any changes to persistent state must still be provisional upon the second phase of the top-level transaction, as well. Based on the votes of all registered resources, JBossTS then calls either commit_subtransaction or rollback_subtransaction.

Note

This scheme only works successfully if all resources registered within a given subtransaction are instances of the ArjunaSubtranAwareResource interface, and that after a resource tells the coordinator it can prepare, it does not change its mind.

When resources are registered with a transaction, the transaction maintains them within a list, called the intentions list. At termination time, the transaction uses the intentions list to drive each resource appropriately, to commit or abort. However, you have no control over the order in which resources are called, or whether previously-registered resources should be replaced with newly registered resources. The JBossTS interface ArjunaOTS::OTSAbstractRecord gives you this level of control.


typeId

returns the record type of the instance. This is one of the values of the enumerated type Record_type.

uid

a stringified Uid for this record.

propagateOnAbort

by default, instances of OTSAbstractRecord should not be propagated to the parent transaction if the current transaction rolls back. By returning TRUE, the instance will be propagated.

propagateOnCommit

returning TRUE from this method causes the instance to be propagated to the parent transaction if the current transaction commits. Returning FALSE disables the propagation.

saveRecord

returning TRUE from this method causes JBossTS to try to save sufficient information about the record to persistent state during commit, so that crash recovery mechanisms can replay the transaction termination in the event of a failure. If FALSE is returned, no information is saved.

merge

used when two records need to merge together.

alter

used when a record should be altered.

shouldAdd

returns true ii the record should be added to the list, false if it should be discarded.

shouldMerge

returns true if the two records should be merged into a single record, false otherwise.

shouldReplace

returns true if the record should replace an existing one, false otherwise.

When inserting a new record into the transaction’s intentions list, JBossTS uses the following algorithm:

  1. if a record with the same type and uid has already been inserted, then the methods shouldAdd, and related methods, are invoked to determine whether this record should also be added.

  2. If no such match occurs, then the record is inserted in the intentions list based on the type field, and ordered according to the uid. All of the records with the same type appear ordered in the intentions list.

OTSAbstractRecord is derived from ArjunaSubtranAwareResource. Therefore, all instances of OTSAbstractRecord inherit the benefits of this interface.

In terms of the OTS, AtomicTransaction is the preferred interface to the OTS protocol engine. It is equivalent to CosTransactions::Current, but with more emphasis on easing application development. For example, if an instance of AtomicTransaction goes out of scope before it is terminates, the transaction automatically rolls back. CosTransactions::Current cannot provide this functionality. When building applications using JBossTS, use AtomicTransaction for the added benefits it provides. It is located in the com.arjuna.ats.jts.extensions.ArjunaOTS package.

Example 5.3. AtomicTransaction

public class AtomicTransaction

{
    public AtomicTransaction ();
    public void begin () throws SystemException, SubtransactionsUnavailable,
                                NoTransaction;
    public void commit (boolean report_heuristics) throws SystemException, 
                                                          NoTransaction, HeuristicMixed,
                                                          HeuristicHazard,TransactionRolledBack;
    public void rollback () throws SystemException, NoTransaction;
    public Control control () throws SystemException, NoTransaction;
    public Status get_status () throws SystemException;
    /* Allow action commit to be supressed */    
    public void rollbackOnly () throws SystemException, NoTransaction;
    public void registerResource (Resource r) throws SystemException, Inactive;
    public void
        registerSubtransactionAwareResource (SubtransactionAwareResource)
        throws SystemException, NotSubtransaction;
    public void
        registerSynchronization(Synchronization s) throws SystemException,
                                                          Inactive;
};


Transaction nesting is determined dynamically. Any transaction started within the scope of another running transaction is nested.

The TopLevelTransaction class, which is derived from AtomicTransaction, allows creation of nested top-level transactions. Such transactions allow non-serializable and potentially non-recoverable side effects to be initiated from within a transaction, so use them with caution. You can create nested top-level transactions with a combination of the CosTransactions::TransactionFactory and the suspend and resume methods of CosTransactions::Current. However, the TopLevelTransaction class provides a more user-friendly interface.

AtomicTransaction and TopLevelTransaction are completely compatible with CosTransactions::Current. You an use the two transaction mechanisms interchangeably within the same application or object.

AtomicTransaction and TopLevelTransaction are similar to CosTransactions::Current. They both simplify the interface between you and the OTS. However, you gain two advantages by using AtomicTransaction or TopLevelTransaction.

  • The ability to create nested top-level transactions which are automatically associated with the current thread. When the transaction ends, the previous transaction associated with the thread, if any, becomes the thread’s current transaction.

  • Instances of AtomicTransaction track scope, and if such an instance goes out of scope before it is terminated, it is automatically aborted, along with its children.

When using TXOJ in a distributed manner, JBossTS requires you to use interposition between client and object. This requirement also exists if the application is local, but the transaction manager is remote. In the case of implicit context propagation, where the application object is derived from CosTransactions::TransactionalObject, you do not need to do anything further. JBossTS automatically provides interposition. However, where implicit propagation is not supported by the ORB, or your application does not use it, you must take additional action to enable interposition.

The class com.arjuna.ats.jts.ExplicitInterposition allows an application to create a local control object which acts as a local coordinator, fielding registration requests that would normally be passed back to the originator. This surrogate registers itself with the original coordinator, so that it can correctly participate in the commit protocol. The application thread context becomes the surrogate transaction hierarchy. Any transaction context currently associated with the thread is lost. The interposition lasts for the lifetime of the explicit interposition object, at which point the application thread is no longer associated with a transaction context. Instead, it is set to null.

interposition is intended only for those situations where the transactional object and the transaction occur within different processes, rather than being co-located. If the transaction is created locally to the client, do not use the explicit interposition class. The transaction is implicitly associated with the transactional object because it resides within the same process.


A transaction context can be propagated between client and server in two ways: either as a reference to the client’s transaction Control, or explicitly sent by the client. Therefore, there are two ways in which the interposed transaction hierarchy can be created and registered. For example, consider the class Example which is derived from LockManager and has a method increment:


if the Control passed to the register operation of ExplicitInterposition is null, no exception is thrown. The system assumes that the client did not send a transaction context to the server. A transaction created within the object will thus be a top-level transaction.

When the application returns, or when it finishes with the interposed hierarchy, the program should call unregisterTransaction to disassociate the thread of control from the hierarchy. This occurs automatically when the ExplicitInterposition object is garbage collected. However, since this may be after the transaction terminates, JBossTS assumes the thread is still associated with the transaction and issues a warning about trying to terminate a transaction while threads are still active within it.

This example illustrates the concepts and the implementation details for a simple client/server example using implicit context propagation and indirect context management.

This example only includes a single unit of work within the scope of the transaction. consequently, only a one-phase commit is needed.

The client and server processes are both invoked using the implicit propagation and interposition command-line options.

For the purposes of this worked example, a single method implements the DemoInterface interface. This method is used in the DemoClient program.


This section deals with the pieces needed to implement the example interface.

The example overrides the methods of the Resource implementation class. The DemoResource implementation includes the placement of System.out.println statements at judicious points, to highlight when a particular method is invoked.

Only a single unit of work is included within the scope of the transaction. Therefore, the prepare or commit methods should never be invoked, but the commit_one_phase method should be invoked.


At this stage, the Demo.idl has been processed by the ORB’s idl compiler to generate the necessary client and server package.

Line 14 returns the transactional context for the Current pseudo object. After obtaining a Control object, you can derive the Coordinator object (line 16).

Lines 17 and 19 create a resource for the transaction, and then inform the ORB that the resource is ready to receive incoming method invocations.

Line 20 uses the Coordinator to register a DemoResource object as a participant in the transaction. When the transaction terminates, the resource receives requests to commit or rollback the updates performed as part of the transaction.


First, you need to to initialize the ORB and the POA. Lines 10 through 14 accomplish these tasks.

The servant class DemoImplementation contains the implementation code for the DemoInterface interface. The servant services a particular client request. Line 16 instantiates a servant object for the subsequent servicing of client requests.

Once a servant is instantiated, connect the servant to the POA, so that it can recognize the invocations on it, and pass the invocations to the correct servant. Line 18 performs this task.

Lines 20 through to 21 registers the service through the default naming mechanism. More information about the options available can be found in the ORB Portability Guide.

If this registration is successful, line 23 outputs a sanity check message.

Finally, line 25 places the server process into a state where it can begin to accept requests from client processes.


After the server compiles, you can use the command line options defined below to start a server process. By specifying the usage of a filter on the command line, you can override settings in the TransactionService.properties file.

Note

if you specify the interposition filter, you also imply usage of implicit context propagation.

The client, like the server, requires you to first initialize the ORB and the POA. Lines 14 through 18 accomplish these tasks.

After a server process is started, you can obtain the object reference through the default publication mechanism used to publish it in the server. This is done in lines 20 and 21. Initially the reference is an instance of Object. However, to invoke a method on the servant object, you need to narrow this instance to an instance of the DemoInterface interface. This is shown in line 21.

Once we have a reference to this servant object, we can start a transaction (line 23), perform a unit of work (line 25) and commit the transaction (line 27).


These settings are defaults, and you can override them at run-time by using property variables, or in the properties file in the etc/ directory of the installation.

7.1. Introduction
7.2. Overview of the X/Open DTP model
7.3. Interface between functional components
7.4. Overview of the Distributed Transaction Processing
7.5. Example
7.5.1. Transactional Concepts
7.5.2. Transaction Components
7.5.3. Application Programs
7.5.4. Standards
7.5.5. Overview of the OMG Object Transaction Service
7.5.6. Application programming models
7.5.7. Examples
7.6. OTS Interfaces
7.7. Managing Transactions in Java EE
7.7.1. JTA/JTS Architecture
7.7.2. Java Transaction API
7.7.3. Java Transaction API - Usage
7.8. Managing Transactions in EJB
7.8.1. An Application Server Model - The Enterprise Java Beans
7.9. JDBC and Transactions
7.10. Configuring the JBoss Transaction Service
7.10.1. Properties File
7.10.2. ObjectStore management
7.10.3. Configuring Output
7.11. ORB Portability
7.11.1. Introduction
7.11.2. The ORB Portability API
7.11.3. Using the ORB
7.11.4. Using the Object Adapater (OA)
7.11.5. Example
7.11.6. Specifying the ORB to use
7.11.7. JBossTS Failure Recovery
7.11.8. The Recovery Manager
7.11.9. Configuring the Recovery Manager
7.11.10. Periodic Recovery
7.11.11. Expired entry removal
7.12. Installation Content
7.12.1. Verifying Installation
7.12.2. Testing your installation
7.12.3. Setting properties
7.13. Specifying the ORB to use
7.14. Overview of the Distributed Transaction Processing
7.15. Example
7.15.1. What is a Transaction?
7.15.2. Transactional Concepts
7.16. JBossTS Overview
7.16.1. Key features
7.17. The Sample Application
7.17.1. The Banking Application
7.17.2. Deploying and Testing The Banking Application
7.18. Making the Banking Application Persistent
7.19. What is Transactional Object For Java
7.19.1. Recovery and Persistency
7.19.2. The concurrency controller
7.19.3. Further Reading
7.19.4. Making the Banking Application Persistent with Transactional Object For Java
7.19.5. Developing applications with JDBC and JBossTS JTS
7.20. Recovery From Failure Examples
7.20.1. Introduction
7.20.2. Running the Recovery Manager
7.20.3. The Recovery Process and XAResources

JBoss Transaction Service (JBossTS) assures complete, accurate business transactions for any Java based applications, including those written for the Java EE and EJB frameworks.

JBossTS is a 100% Java implementation of a distributed transaction management system based on the Sun Microsystems Java EE Java Transaction Service (JTS) standard. Our implementation of the JTS utilizes the Object Management Group's (OMG) Object Transaction Service (OTS) model for transaction interoperability as recommended in the Java EE and EJB standards. Although any JTS-compliant product will allow Java objects to participate in transactions, one of the key features of JBossTS is it's 100% Java implementation. This allows JBossTS to support fully distributed transactions that can be coordinated by distributed parties.

JBossTS runs can be run both as an embedded distributed service of an application server (e.g. JBossAS), affording the user all the added benefits of the application server environment such as real-time load balancing, unlimited linear scalability and unmatched fault tolerance that allows you to deliver an always-on solution to your customers. It is also available as a free-standing Java Transaction Service.

In addition to providing full compliance with the latest version of the JTS specification, JBossTS leads the market in providing many advanced features such as fully distributed transactions and ORB portability with POA support.

JBossTS is tested on HP-UX 11i, Red Hat Linux, Windows Server 2003, and Sun Solaris 10, using Sun's JDK 5. It should howerver work on any system with JDK 5 or 6.

The Java Transaction API support for JBossTS comes in two flavours:

Key features

This trail map will help you get started with running JBoss transaction service product. It is structured as follows:

In addition to the trails listed above, a set of trails giving more explanation on concept around transaction processing and standards, and also a quick access to section explaining how to configure JBossTS are listed in the section "Additional Trails".

Note:When running the local JTS transactions part of the trailmap, you will need to start the recovery manager: java com.arjuna.ats.arjuna.recovery.RecoveryManager -test

There are six interfaces between software components in the X/Open DTP model.

The functions that each RM provides for the TM are called the xa_*() functions. For example the TM calls xa_start( ) in each participating RM to start an RM-internal transaction as part of a new global transaction. Later, the TM may call in sequence xa_end() xa_prepare( ) and xa_commit() to coordinate a (successful in this case) two-phase commit protocol. The functions that the TM provides for each RM are called the ax_*( ) functions. For example an RM calls ax_reg( ) to register dynamically with the TM.

  • the TxRPC interface (see the referenced TxRPC specification)
  • the XATMI interface (see the referenced XATMI specification)
  • the CPI-C interface (see the referenced CPI-C specification).
  • AP-RM. The AP-RM interfaces give the AP access to resources. X/Open interfaces, such as SQL and ISAM provide AP portability. The X/Open DTP model imposes few constraints on native RM APIs. The constraints involve only those native RM interfaces that define transactions.
  • AP-TM. The AP-TM interface (the TX interface) provides the AP with an Application Programming Interface (API) by which the AP coordinates global transaction management with the TM. For example, when the AP calls tx_begin( ) the TM informs the participating RMs of the start of a global transaction. After each request is completed, the TM provides a return value to the AP reporting back the success or otherwise of the TX call.
  • TM-RM. The TM-RM interface (the XA interface) lets the TM structure the work of RMs into global transactions and coordinate completion or recovery. The XA interface is the bidirectional interface between the TM and RM.
  • TM-CRM. The TM-CRM interface (the XA+ interface) supports global transaction information flow across TM Domains. In particular TMs can instruct CRMs by use of xa_*() function calls to suspend or complete transaction branches, and to propagate global transaction commitment protocols to other transaction branches. CRMs pass information to TMs in subordinate branches by use of ax_*( ) function calls. CRMs also use ax_*( ) function calls to request the TM to create subordinate transaction branches, to save and retrieve recovery information, and to inform the TM of the start and end of blocking conditions.
  • AP-CRM. X/Open provides portable APIs for DTP communication between APs within a global transaction. The API chosen can significantly influence (and may indeed be fundamental to) the whole architecture of the application. For this reason, these APIs are frequently referred to in this specification and elsewhere as communication paradigms.In practice, each paradigm has unique strengths, so X/Open offers the following popular paradigms:
  • CRM-OSI TP. This interface (the XAP-TP interface) provides a programming interface between a CRM and Open Systems Interconnection Distributed Transaction Processing (OSI TP) services. XAP-TP interfaces with the OSI TP Service and the Presentation Layer of the seven-layer OSI model. X/Open has defined this interface to support portable implementations of application-specific OSI services. The use of OSI TP is mandatory for communication between heterogeneous TM domains. For details of this interface, see the referenced XAP-TP specification and the OSI TP standards.
Although the aim of the Open Group was providing portable interfaces, only the XA interface appears to be accepted and implemented by a wide range of vendors.

XA is a bidirectional interface between resource managers and transaction managers. This interface specifies two sets of functions. The first set, called as xa_*() functions are implemented by resource managers for use by the transaction manager.

Table 1 - XA Interface of X/Open DTP Model for the transaction manager

FunctionPurpose
xa_startDirects a resource manager to associate the subsequent requests by application programs to a transaction identified by the supplied identifier.
xa_endEnds the association of a resource manager with the transaction.
xa_preparePrepares the resource manager for the commit operation. Issued by the transaction manager in the first phase of the two-phase commit operation.
xa_commitCommits the transactional operations. Issued by the transaction manager in the second phase of the two-phase commit operation.
xa_recoverRetrieves a list of prepared and heuristically committed or heuristically rolled back transactions
xa_forgetForgets the heuristic transaction associated with the given transaction identifier

The second set of functions, called as ax_*() functions, are implemented by the transaction manager for use by resource managers.

Table 2 - XA Interface of X/Open DTP Model for resource managers

FunctionPurpose
ax_reg()Dynamically enlists with the transaction manager.
ax_unreg()Dynamically delists from the transaction manager.

Transaction management is one of the most crucial requirements for enterprise application development. Most of the large enterprise applications in the domains of finance, banking and electronic commerce rely on transaction processing for delivering their business functionality.

Enterprise applications often require concurrent access to distributed data shared amongst multiple components, to perform operations on data. Such applications should maintain integrity of data (as defined by the business rules of the application) under the following circumstances:

In such cases, it may be required that a group of operations on (distributed) resources be treated as one unit of work. In a unit of work, all the participating operations should either succeed or fail and recover together. This problem is more complicated when

In either case, it is required that success or failure of a unit of work be maintained by the application. In case of a failure, all the resources should bring back the state of the data to the previous state (i.e., the state prior to the commencement of the unit of work).

From the programmer's perspective a transaction is a scoping mechanism for a collection of actions which must complete as a unit. It provides a simplified model for exception handling since only two outcomes are possible:

To illustrate the reliability expected by the application let’s consider the funds transfer example which is familiar to all of us.

The Money transfer involves two operations: Deposit and Withdrawal

The complexity of implementation doesn't matter; money moves from one place to another. For instance, involved accounts may be either located in a same relational table within a database or located on different databases.

A Simple transfer consists on moving money from savings to checking while a Complex transfer can be performed at the end- of- day according to a reconciliation between international banks

The concept of a transaction, and a transaction manager (or a transaction processing service) simplifies construction of such enterprise level distributed applications while maintaining integrity of data in a unit of work.

A transaction is a unit of work that has the following properties:

  • Atomicity – either the whole transaction completes or nothing completes - partial completion is not permitted.
  • Consistency – a transaction transforms the system from one consistent state to another. In other words, On completion of a successful transaction, the data should be in a consistent state. For example, in the case of relational databases, a consistent transaction should preserve all the integrity constraints defined on the data.
  • Isolation: Each transaction should appear to execute independently of other transactions that may be executing concurrently in the same environment. The effect of executing a set of transactions serially should be the same as that of running them concurrently. This requires two things:
    • During the course of a transaction, intermediate (possibly inconsistent) state of the data should not be exposed to all other transactions.
    • Two concurrent transactions should not be able to operate on the same data. Database management systems usually implement this feature using locking.
  • Durabiliy: The effects of a completed transaction should always be persistent.

These properties, called as ACID properties, guarantee that a transaction is never incomplete, the data is never inconsistent, concurrent transactions are independent, and the effects of a transaction are persistent.

A collection of actions is said to be transactional if they possess the ACID properties. These properties are assumed to be ensured, in the presence of failures; if actions involved within the transaction are performed by a Transactional System. A transaction system includes a set of components where each of them has a particular role. Main components are described below.

Application Programs are clients for the transactional resources. These are the programs with which the application developer implements business transactions. With the help of the transaction manager, these components create global transactions and operate on the transactional resources with in the scope of these transactions. These components are not responsible for implementing mechanisms for preserving ACID properties of transactions. However, as part of the application logic, these components generally make a decision whether to commit or rollback transactions.

Application responsibilities could be summarized as follow:

A resource manager is in general a component that manages persistent and stable data storage system, and participates in the two phase commit and recovery protocols with the transaction manager.

A resource manager is typically a driver that provides two sets of interfaces: one set for the application components to get connections and operating, and the other set for participating in two phase commit and recovery protocols coordinated by a transaction manager. This component may also, directly or indirectly, register resources with the transaction manager so that the transaction manager can keep track of all the resources participating in a transaction. This process is called as resource enlistment.

Resource Manager responsibilities could be summarized as follow

The transaction manager is the core component of a transaction processing environment. Its main responsibilities are to create transactions when requested by application components, allow resource enlistment and delistment, and to manage the two-phase commit or recovery protocol with the resource managers.

A typical transactional application begins a transaction by issuing a request to a transaction manager to initiate a transaction. In response, the transaction manager starts a transaction and associates it with the calling thread. The transaction manager also establishes a transaction context. All application components and/or threads participating in the transaction share the transaction context. The thread that initially issued the request for beginning the transaction, or, if the transaction manager allows, any other thread may eventually terminate the transaction by issuing a commit or rollback request.

Before a transaction is terminated, any number of components and/or threads may perform transactional operations on any number of transactional resources known to the transaction manager. If allowed by the transaction manager, a transaction may be suspended or resumed before finally completing the transaction.

Once the application issues the commit request, the transaction manager prepares all the resources for a commit operation, and based on whether all resources are ready for a commit or not, issues a commit or rollback request to all the resources.

Resource Manager responsibilities could be summarized as follow:

Basically, the Recovery is the mechanism which preserves the transaction atomicity in presence of failures. The basic technique for implementing transactions in presence of failures is based on the use of logs. That is, a transaction system has to record enough information to ensure that it can be able to return to a previous state in case of failure or to ensure that changes committed by a transaction are properly stored.

In addition to be able to store appropriate information, all participants within a distributed transaction must log similar information which allow them to take a same decision either to set data in their final state or in their initial state.

Two techniques are in general used to ensure transaction's atomicity. A first technique focuses on manipulated data, such the Do/Undo/Redo protocol (considered as a recovery mechanism in a centralized system), which allow a participant to set its data in their final values or to retrieve them in their initial values. A second technique relies on a distributed protocol named the two phases commit, ensuring that all participants involved within a distributed transaction set their data either in their final values or in their initial values. In other words all participants must commit or all must rollback.

In addition to failures we refer as centralized such system crashes, communication failures due for instance to network outages or message loss have to be considered during the recovery process of a distributed transaction.

In order to provide an efficient and optimized mechanism to deal with failure, modern transactional systems typically adopt a “presume abort” strategy, which simplifies the transaction management.

The presumed abort strategy can be stated as «when in doubt, abort». With this strategy, when the recovery mechanism has no information about the transaction, it presumes that the transaction has been aborted.

A particularity of the presumed-abort assumption allows a coordinator to not log anything before the commit decision and the participants do not to log anything before they prepare. Then, any failure which occurs before the 2pc starts lead to abort the transaction. Furthermore, from a coordinator point of view any communication failure detected by a timeout or exception raised on sending prepare is considered as a negative vote which leads to abort the transaction. So, within a distributed transaction a coordinator or a participant may fail in two ways: either it crashes or it times out for a message it was expecting. When a coordinator or a participant crashes and then restarts, it uses information on stable storage to determine the way to perform the recovery. As we will see it the presumed-abort strategy enable an optimized behavior for the recovery.
Saying that a distributed transaction can involve several distributed participants, means that these participant must be integrated within a global transaction manager which has the responsibility to ensure that all participants take a common decision to commit or rollback the distributed transaction. The key of such integration is the existence of a common transactional interface which is understood by all participants, transaction manager and resource managers such databases.

The importance of common interfaces between participants, as well as the complexity of their implementation, becomes obvious in an open systems environment. For this aim various distributed transaction processing standards have been developed by international standards organizations. Among these organizations, We list three of them which are mainly considered in the JBoss Transaction Service product:

  • The X/Open model and its successful XA interface
  • The OMG with its CORBA infrastructure and the Object Transaction Service and finally
  • The Java Community Process leaded by Sun with its JTA/JTS specification
Basically these standards have proposed logical models, which divide transaction processing into several functions:
  • those assigned to the application which ties resources together in application- specific operations
  • those assigned to the Resource manager which access physically to data stores
  • functions performed by the Transaction Manager which manages transactions, and finally
  • Communication Resource Managers which allow to exchange information with other transactional domains.
Object Transaction Service (OTS) is a distributed transaction processing service specified by the Object Management Group (OMG). This specification extends the CORBA model and defines a set of interfaces to perform transaction processing across multiple CORBA objects.

OTS is based on the Open Group's DTP model and is designed so that it can be implemented using a common kernel for both the OTS and Open Group APIs. In addition to the functions defined by DTP, OTS contains enhancements specifically designed to support the object environment. Nested transactions and explicit propagation are two examples.

The CORBA model also makes some of the functions in DTP unnecessary so these have been consciously omitted. Static registration and the communications resource manager are unnecessary in the CORBA environment.

A key feature of OTS is its ability to share a common transaction with XA compliant resource managers. This permits the incremental addition of objects into an environment of existing procedural applications.

Figure 1 - OTS Architecture

The OTS architecture, shown in Figure 1, consists of the following components:

  • Transaction Client: A program or object that invokes operations on transactional objects.
  • Transactional Object: A CORBA object that encapsulates or refers to persistent data, and whose behavior depends on whether or not its operations are invoked during a transaction.
  • Recoverable Object: A transactional object that directly maintains persistent data, and participates in transaction protocols.
  • Transactional Server: A collection of one or more transactional objects.
  • Recoverable Server: A collection of objects, of which at least one of which is recoverable.
  • Resource Object: A resource object is an object in the transaction service that is registered for participation in the two-phase commit and recovery protocol.
In addition to the usual transactional semantics, the CORBA OTS provides for the following features:
  • Nested Transactions: This allows an application to create a transaction that is embedded in an existing transaction. In this model, multiple subtransactions can be embedded recursively in a transaction. Subtransactions can be committed or rolled back without committing or rolling back the parent transaction. However, the results of a commit operation are contingent upon the commitment of all the transaction's ancestors. The main advantage of this model is that transactional operations can be controlled at a finer granularity. The application will have an opportunity to correct or compensate for failures at the subtransaction level, without actually attempting to commit the complete parent transaction.
  • Application Synchronization: Using the OTS synchronization protocol, certain objects can be registered with the transaction service for notification before the start of and the completion of the two-phase commit process. This enables such application objects to synchronize transient state and data stored in persistent storage.
A client application program may use direct or indirect context management to manage a transaction. With indirect context management, an application uses the pseudo object called Current, provided by the Transaction Service , to associate the transaction context with the application thread of control. In direct context management, an application manipulates the Control object and the other objects associated with the transaction.

An object may require transactions to be either explicitly or implicitly propagated to its operations.

  • Explicit propagation means that an application propagates a transaction context by passing objects defined by the Transaction Service as explicit parameters. This should typically be the PropagationContext structure.
  • Implicit propagation means that requests are implicitly associated with the client's transaction; they share the client's transaction context. It is transmitted implicitly to the objects, without direct client intervention. Implicit propagation depends on indirect context management, since it propagates the transaction context associated with the Current pseudo object. An object that supports implicit propagation would not typically expect to receive any Transaction Service object as an explicit parameter.
A client may use one or both forms of context management, and may communicate with objects that use either method of transaction propagation. (Details of how to enable implicit propagation were described in Section Chapter 0 and Section 0). This results in four ways in which client applications may communicate with transactional objects:
  • Direct Context Management/Explicit Propagation: the client application directly accesses the Control object, and the other objects which describe the state of the transaction. To propagate the transaction to an object, the client must include the appropriate Transaction Service object as an explicit parameter of an operation; typically this should be the PropagationContext structure.
  • Indirect Context Management/Implicit Propagation: the client application uses operations on the Current pseudo object to create and control its transactions. When it issues requests on transactional objects, the transaction context associated with the current thread is implicitly propagated to the object.
  • Indirect Context Management/Explicit Propagation: for an implicit model application to use explicit propagation, it can get access to the Control using the get_control operation on the Current pseudo object. It can then use a Transaction Service object as an explicit parameter to a transactional object; for efficiency reasons this should be the PropagationContext structure, obtained by calling get_txcontext on the appropriate Coordinator reference. This is explicit propagation.
  • Direct Context Management/Implicit Propagation: a client that accesses the Transaction Service objects directly can use the resume pseudo object operation to set the implicit transaction context associated with its thread. This allows the client to invoke operations of an object that requires implicit propagation of the transaction context.

The main difference between direct and indirect context management is the effect on the invoking thread's transaction context. If using indirect (i.e., invoking operations through the Current pseudo object), then the thread's transaction context will be modified automatically by the OTS, e.g., if begin is called then the thread's notion of the current transaction will be modified to the newly created transaction; when that is terminated, the transaction previously associated with the thread (if any) will be restored as the thread's context (assuming subtransactions are supported by the OTS implementation). However, if using direct management, no changes to the threads transaction context are performed by the OTS: the application programmer assumes responsibility for this.

Figure 2 describes the principal interfaces in the CORBA OTS specification, with their interaction, while the Table 1 below provides more details for each interface.

Figure 2 - OTS interfaces and their interactions

Table 1 - OTS Interfaces and their role.

InterfaceRole and operations
Current
  • Transaction demarcation (begin, commit, rollback, rollback_only, set_time_out)
  • Status of the transaction (get_status)
  • Name of the transaction (get_transaction_name)
  • Transaction context (get_control)
TransactionFactoryExplicit transaction creation
  • create a transaction with its associated cooridinator (create)
  • create an interposed coordinator as a subrodinator in the transaction tree (recreate)
ControlExplicit transaction context management
  • access to the transaction coordinator (get_coordinator)
  • access to the transactions terminator (get_terminator)
TerminatorCommit (commit) or rollback (rollback) a transaction in a direct transaction management mode
Coordinator
  • Status of the transaction (get_status, get_parent_status, get_top_level_status)
  • Transaction information (is_same_transaction, is_related_transaction, is_ancestor_transaction, is_descendant_transaction, is_top_level_transaction, hash_transaciton, hash_top_level_transaction, get_transaction_name, get_txcontext)
  • Resource enlistment (register_resource, register_subtrans_aware)
  • Registration of synchronization objects (register_synchronization)
  • Set the transaction for rollback (rollback_only)
  • Create subtransactions (create_subtransaction)
RecoveryCoordinatorAllows to coordinate recovery in case of failure (replay_completion)
ResourceParticipation in two-phase commit and recovery protocol (prepare, rollback, commit, commit_one_phase, forget)
SynchronizationApplication synchronization before beginning and after completion of two-phase commit (before_completion, after_completion)
SubtransactionAwareResourceCommit or rollback a subtransaction (commit_subtransaction, rollback_subtransaction)
TransactionalObjectA marker interface to be implemented by all transactional objects (no operation defined)
The Java transaction initiative consists of two specifications: Java Transaction Service (JTS) and Java Transaction API (JTA).

JTS specifies the implementation of a Java transaction manager. This transaction manager supports the JTA, using which application servers can be built to support transactional Java applications. Internally the JTS implements the Java mapping of the OMG OTS specifications.

The JTA specifies an architecture for building transactional application servers and defines a set of interfaces for various components of this architecture. The components are: the application, resource managers, and the application server, as shown in the slide.

The JTS thus provides a new architecture for transactional application servers and applications, while complying to the OMG OTS 1.1 interfaces internally. This allows the JTA compliant applications to interoperate with other OTS 1.1 complaint applications through the standard IIOP.

As shown in the Figure 1, in the Java transaction model, the Java application components can conduct transactional operations on JTA compliant resources via the JTS. The JTS acts as a layer over the OTS. The applications can therefore initiate global transactions to include other OTS transaction managers, or participate in global transactions initiated by other OTS compliant transaction managers.

Figure 1 - The JTA/JTS transaction model

The Java Transaction Service is architected around an application server and a transaction manager. The architecture is shown in Figure 2.

Figure 2 - The JTA/JTS Architecture

The JTS architecture consists of the following components:

  • Transaction Manager: The transaction manager is the core component of this architecture and is provided by an implementation of the JTS. It provides interfaces to create transactions (including transaction demarcation and propagation of transaction context), allows enlistment and delistment of resources, provides interfaces for registering components for application synchronization, implements the synchronization protocol, and initiates and directs the two phase commit and recovery protocol with the resource managers.
  • Application Server: One of the key features of the JTS architecture is that it allows an application server to be built on top of the transaction service and the resources. Application developers can develop and deploy application components onto the application server for initiating and managing transactions. The application server can therefore abstract all transactional semantics from the application programs.
  • Application Components: These are the clients for the transactional resources and implement business transactions. These are deployed on the application server. Depending on the architecture of the application server, these components can directly or indirectly create transactions and operate on the transactional resources. For example, an Enterprise JavaBean (EJB) server allows declarative transaction demarcation, in which case, the EJB components need not directly implement the transactions. However, a Java implementation of a CORBA OTS, requires the CORBA object to demarcate transactions explicitly.
  • Resource Manager: A resource manager is an X/Open XA compliant component that manages a persistent and stable storage system, and participates in the two phase commit and recovery protocol with the transaction manager. The application manager also provides interfaces for the application server and the application components to operate on the data managed by it.
  • Communication Resource Manager: This allows the transaction manager to participate in transactions initiated by other transaction managers. However, the JTS specification does not specify any protocol for this communication and assumes that an implementation of the communication resource manager supports the CORBA OTS and GIOP specifications.
The JTA specification may be classified into three categories of interface as shown in Figure 3. The Java Transaction API consists of three elements: a high-level application transaction demarcation interface, a high-level transaction manager interface intended for application server, and a standard Java mapping of the X/Open XA protocol intended for transactional resource manager.

Figure 3 - JTA Interfaces
FlagPurpose
STATUS_ACTIVETransaction is active (started but not prepared)
STATUS_COMMITTEDTransaction is committed
STATUS_COMMITTINGTransaction is in the process of committing.
STATUS_MARKED_ROLLBACKTransaction is marked for rollback.
STATUS_NO_TRANSACTIONThere is no transaction associated with the current Transaction, UserTransaction or TransactionManager objects.
STATUS_PREPAREDVoting phase of the two phase commit is over and the transaction is prepared.
STATUS_PREPARINGTransaction is in the process of preparing.
STATUS_ROLLEDBACKOutcome of the transaction has been determined as rollback. It is likely that heuristics exists.
STATUS_ROLLING_BACKTransaction is in the process of rolling back.
STATUS_UNKNOWNA transaction exists but its current status can not be determined. This is a transient condition

The javax.transaction.Transaction, javax.transaction.TransactionManager, and javax.transaction.UserTransaction interfaces provide a getStatus method that returns one of the above status flags.

This section describes the usage of the JTA for implementing various transaction semantics. The purpose of this section is to provide conceptual guidelines only.
Transactional resources such as database connections are typically managed by the application server in conjunction with some resource adapter and optionally with connection pooling optimisation. In order for an external transaction manager to co-ordinate transactional work performed by the resource managers, the application server must enlist and de-list the resources used in the transaction. These resources (participants) are enlisted with the transaction so that they can be informed when the transaction terminates, e.g., are driven through the two-phase commit protocol.

The JTA is much more closely integrated with the XA concept of resources than the arbitrary objects. For each resource in-use by the application, the application server invokes the enlistResource method with an XAResource object which identifies the resource in use.

The enlistment request results in the transaction manager informing the resource manager to start associating the transaction with the work performed through the corresponding resource. The transaction manager is responsible for passing the appropriate flag in its XAResource.start method call to the resource manager.

The delistResource method is used to disassociate the specified resource from the transaction context in the target object. The application server invokes the method with the two parameters: the XAResource object that represents the resource, and a flag to indicate whether the operation is due to the transaction being suspended (TMSUSPEND), a portion of the work has failed (TMFAIL), or a normal resource release by the application (TMSUCCESS).

The de-list request results in the transaction manager informing the resource manager to end the association of the transaction with the target XAResource. The flag value allows the application server to indicate whether it intends to come back to the same resource whereby the resource states must be kept intact. The transaction manager passes the appropriate flag value in its XAResource.end method call to the underlying resource manager.

The application server can enlist and delist resource managers with the transaction manager using the javax.transaction.Transaction interface

Usage

Resource enlistment is in general done by the application server when an application requests it for a connection to a transactional resource.



// ... an implementation of the application server
// Get a reference to the underlying TransactionManager object.
...
// Get the current Transaction object from the TransactionManager.
transaction = transactionManager.getTransaction();
// Get an XAResource object from a transactional resource.
...
// Create a Transaction object.
...
// Enlist the resource
transaction.enlistResource(xaResource);...
// Return the connection to the application.
...

Resource delistment is done similarly after the application closes connections to transactional resources.

Enterprise Java Beans (EJB) is a technology specification from Sun Microsystems Inc. that specifies a framework for building component-based distributed applications. As an application server framework, the EJB servers address transaction processing, resource pooling, security, threading, persistence, remote access, life cycle etc.

The EJB framework specifies construction, deployment and invocation of components called as enterprise beans. The EJB specification classifies enterprise beans into two categories: entity beans and session beans. While entity beans abstract persistent domain data, session beans provide for session specific application logic. Both types of beans are maintained by EJB compliant servers in what are called as containers. A container provides the run time environment for an enterprise bean. Figure 4 shows a simplified architecture of transaction management in EJB compliant application servers.

Figure 4 - EJB and Transactions

An enterprise bean is specified by two interfaces: the home interface and the remote interface. The home interface specifies how a bean can created or found. With the help of this interface, a client or another bean can obtain a reference to a bean residing in a container on an EJB server. The remote interface specifies application specific methods that are relevant to entity or session beans.

Clients obtain references to home interfaces of enterprise beans via the Java Naming and Directory Interface (JNDI) mechanism. An EJB server should provide a JNDI implementation for any naming and directory server. Using this reference to the home interface, a client can obtain a reference to the remote interface. The client can then access methods specified in the remote interface. The EJB specification specifies the Java Remote Method Invocation (RMI) as the application level protocol for remote method invocation. However, an implementation can use IIOP as the wire-level protocol.

In Figure 5, the client first obtains a reference to the home interface, and then a reference to an instance of Bean A via the home interface. The same procedure is applicable for instance of Bean A to obtain a reference and invoke methods on an instance of Bean B.

The EJB framework does not specify any specific transaction service (such as the JTS) or protocol for transaction management. However, the specification requires that the javax.transaction.UserTransaction interface of the JTS be exposed to enterprise beans. This interface is required for programmatic transaction demarcation as discussed in the next section.

The EJB framework allows both programmatic and declarative demarcation of transactions. Declarative demarcation is needed for all enterprise beans deployed on the EJB. In addition, EJB clients can also initiative and end transactions programmatically.

The container performs automatic demarcation depending on the transaction attributes specified at the time of deploying an enterprise bean in a container. The following attributes determine how transactions are created.

  • NotSupported: The container invokes the bean without a global transaction context.
  • Required: The container invokes the bean within a global transaction context. If the invoking thread already has a transaction context associated, the container invokes the bean in the same context. Otherwise, the container creates a new transaction and invokes the bean within the transaction context.
  • Supports: The bean is transaction-ready. If the client invokes the bean within a transaction, the bean is also invoked within the same transaction. Otherwise, the bean is invoked without a transaction context.
  • RequiresNew: The container invokes the bean within a new transaction irrespective of whether the client is associated with a transaction or not.
  • Mandatory: The container must invoke the bean within a transaction. The caller should always start a transaction before invoking any method on the bean.

Java Data Base Connectivity, provide Java programs with a way to connect to and use relational databases. The JDBC API lets you invoke SQL commands from Java programming language methods. In simplest terms, JDBC allows to do three things

The following code fragment gives a simple example of these three steps:



Connection con = DriverManager.getConnection(
  "jdbc:myDriver:wombat", "myLogin", "myPassword");
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("SELECT a, b, c FROM Table1");
while (rs.next()) {
  int x = rs.getInt("a");
  String s = rs.getString("b");
  float f = rs.getFloat("c");
}

Before the version 2.0 of JDBC, only local transactions controlled by the transaction manager of the DBMS is possible. To code a JDBC transaction, you invoke the commit and rollback methods of the java.sql.Connection interface. The beginning of a transaction is implicit. A transaction begins with the first SQL statement that follows the most recent commit, rollback, or connect statement. (This rule is generally true, but may vary with DBMS vendor.). The following example illustrates how transactions are managed by the JDBC API.



public void withdraw (double amount) {
  try {
    //A connection opened with JDBC is an AUTO COMMIT mode meaning
    // that the commitment is automatically performed when the connection
    // is closed
    //setAutoCommit to false disable this feature
    connection.setAutoCommit(false);
    //perform an SQL update to Withdraw money from account
    connection.commit();
  } catch (Exception ex) {
      try {
         connection.rollback();
          throw new Exception("Transaction failed: " +  ex.getMessage());
      } catch (Exception sqx) {
           throw new Exception(...}
      }
  }
}

From the version 2.0, a JDBC driver can be involved within a distributed transaction since it supports the XAResource interface that allows to participate to the 2PC protocol. An application that need to include more than one database can create a JTA transaction. To demarcate a JTA transaction, the application program invokes the begin, commit, and rollback methods of the javax.transaction.UserTransaction interface. The following code, that can be applied to a bean-managed transaction, demonstrates the UserTransaction methods. The begin and commit invocations delimit the updates to the database. If the updates fail, the code invokes the rollback method and throws an Exception.



public void transfer(double amount) {
  UserTransaction ut = context.getUserTransaction();
  try {
     ut.begin();
     // Perform SQL command to debit account 1
     // Perform SQL command to debit account 2
     ut.commit();
   } catch (Exception ex) {
        try {
          ut.rollback();
        } catch (Exception ex1) {
             throw new Exception ("Rollback failed: " + ex1.getMessage());
        }
        throw new Exception ("Transaction failed: " + ex.getMessage());
   }
}

This trail provides information on the way to configure environmental variables needed to define the behaviour of transactional applications managed with JBossTS. Basically, the behaviour of the JBossTS product is configurable through property attributes. Although these property attributes may be specified as command line arguments, it is more convenient to organise and initialise them through properties files.

The properties file named jbossts-properties.xml and located under the <ats_installation_directory>/etc directory is organised as a collection of property names.

Some properties must be specified by the developer while others do not need to be defined and can be used with their default values. Basically the properties file that does not provide default values to all its properties is the jbossts-properties.xml.

The following table describes some properties in the jbossts-properties.xml, where:

Name Description Possible Value Default Value
com.arjuna.ats.arjuna.objectstore.localOSRoot By default, all object states will be stored within the "defaultStore" subdirectory of the object store root. However, this subdirectory can be changed by setting the localOSRoot property variable accordingly Directory name defaultStore
com.arjuna.ats.arjuna.objectstore.objectStoreDir Specify the location of the ObjectStore Directory name PutObjectStoreDirHere
com.arjuna.ats.arjuna.common.varDir JBossTS needs to be able to write temporary files to a well known location during execution. By default this location is var. However, by setting the varDir property variable this can be overridden. Directory name var/tmp

Sometimes it is desirable, mainly in case of debugging, to have some form of output during execution to trace internal actions performed. JBossTS uses the logging tracing mechanism provided by the Arjuna Common Logging Framework (CLF) version 2.4, which provides a high level interface that hides differences that exist between logging APIs such Jakarta log4j, JDK 1.4 logging API or dotnet logging API.

With the CLF applications make logging calls on commonLogger objects. These commonLogger objects pass log messages to Handler for publication. Both commonLoggers and Handlers may use logging Levels to decide if they are interested in a particular log message. Each log message has an associated log Level, that gives the importance and urgency of a log message. The set of possible Log Levels are DEBUG, INFO, WARN, ERROR and FATAL. Defined Levels are ordered according to their integer values as follows: DEBUG < INFO < WARN < ERROR < FATAL.

The CLF provides an extension to filter logging messages according to finer granularity an application may define. That is, when a log message is provided to the commonLogger with the DEBUG level, additional conditions can be specified to determine if the log message is enabled or not.

Note: These conditions are applied if and only the DEBUG level is enabled and the log request performed by the application specifies debugging granularity.

When enabled, Debugging is filtered conditionally on three variables:

  • Debugging level: this is where the log request with the DEBUG Level is generated from, e.g., constructors or basic methods.
  • Visibility level: the visibility of the constructor, method, etc. that generates the debugging.
  • Facility code: for instance the package or sub-module within which debugging is generated, e.g., the object store.

According to these variables the Common Logging Framework defines three interfaces. A particular product may implement its own classes according to its own finer granularity. JBossTS uses the default Debugging level and the default Visibility level provided by CLF, but it defines its own Facility Code. JBossTS uses the default level assigned to its commonLoggers objects (DEBUG). However, it uses the finer debugging features to disable or enable debug messages. Finer values used by the JBossTS are defined below:

  • Debugging level – JBossTS uses the default values defined in the class com.arjuna.common.util.logging.CommonDebugLevel
Debug LevelValueDescription
NO_DEBUGGING0x0000A commonLogger object assigned with this values discard all debug requests
CONSTRUCTORS 0x0001Diagnostics from constructors
DESTRUCTORS0x0002Diagnostics from finalizers.
CONSTRUCT_AND_DESTRUCTCONSTRUCTORS | DESTRUCTORSDiagnostics from constructors and finalizers
FUNCTIONS0x010Diagnostics from functions
OPERATORS0x020Diagnostics from operators, such as equals
FUNCS_AND_OPSFUNCTIONS | OPERATORSDiagnostics from functions and operations.
ALL_NON_TRIVIALCONSTRUCT_AND_DESTRUCT | FUNCTIONS | OPERATORSDiagnostics from all non-trivial operations
TRIVIAL_FUNCS0x0100Diagnostics from trivial functions.
TRIVIAL_OPERATORS:0x0200Diagnostics from trivial operations, and operators.
ALL_TRIVIALTRIVIAL_FUNCS | TRIVIAL_OPERATORSDiagnostics from all trivial operations
FULL_DEBUGGING0xffffFull diagnostics.
  • Visibility level – JBossTS uses the default values defined in the class com.arjuna.common.util.logging.CommonVisibilityLevel
Debug LevelValueDescription
VIS_NONE0x0000No Diagnostic
VIS_PRIVATE0x0001only from private methods.
VIS_PROTECTED0x0002only from protected methods.
VIS_PUBLIC0x0004only from public methods.
VIS_PACKAGE0x0008only from package methods.
VIS_ALL0xffffFull Diagnostic
  • Facility Code – JBossTS uses the following values
Facility Code Level ValueDescription
FAC_ATOMIC_ACTION0x00000001atomic action core module
FAC_BUFFER_MAN0x00000004state management (buffer) classes
FAC_ABSTRACT_REC0x00000008abstract records
FAC_OBJECT_STORE0x00000010object store implementations
FAC_STATE_MAN0x00000020state management and StateManager)
FAC_SHMEM0x00000040 shared memory implementation classes
FAC_GENERAL0x00000080general classes
FAC_CRASH_RECOVERY0x00000800detailed trace of crash recovery module and classes
FAC_THREADING0x00002000threading classes
FAC_JDBC0x00008000JDBC 1.0 and 2.0 support
FAC_RECOVERY_NORMAL0x00040000normal output for crash recovery manager

To ensure appropriate output, it is necessary to set some of the finer debug properties explicitly as follows:

 <properties>

   <!-- CLF 2.4 properties -->
   <property
     name="com.arjuna.common.util.logging.DebugLevel"
     value="0x00000000"/>
   <property
     name="com.arjuna.common.util.logging.FacilityLevel"
     value="0xffffffff"/>
   <property
     name="com.arjuna.common.util.logging.VisibilityLevel"
     value="0xffffffff"/>
   <property
     name="com.arjuna.common.util.logger"
     value="log4j"/>
 </properties>

By default, debugging messages are not enabled since the DebugLevel is set to NO_DEBUGGING (0x00000000). You can enable debugging by providing one of the appropriate value listed above - for instance with you wish to see all internal actions performed by the RecoveryManager to recover transactions from a failure set the DebugLevel to FULL_DEBUGGING (0xffffffff) and the FacilityCode Level FAC_CRASH_RECOVERY.

Note: To enable finger debug messages, the logging level should be set to the DEBUG level as described below.

From the program point of view a same API is used whatever the underlying logging mechanism, but from a configuration point of view is that the user is totally responsible for the configuration of the underlying logging system. Hence, the properties of the underlying log system are configured in a manner specific to that log system, e.g., a log4j.properties file in the case that log4j logging is used. To set the logging level to the DEBUG value, the log4j.properties file can be edited to set that value.

The property com.arjuna.common.util.logger allows to select the underlying logging system. Possible value are listed in the following table.

Property ValueDescription
log4jLog4j logging (log4j classes must be available in the classpath); configuration through the log4j.properties file, which is picked up from the CLASSPATH or given through a System property: log4j.configuration
jdk14JDK 1.4 logging API (only supported on JVMs of version 1.4 or higher). Configuration is done through a file logging.properties in the jre/lib directory.
simpleSelects the simple JDK 1.1 compatible console-based logger provided by Jakarta Commons Logging
csfSelects CSF-based logging (CSF embeddor must be available)
jakartaUses the default log system selection algorithm of the Jakarta Commons Logging framework
dotnetSelects a .net logging implementation

Since a dotnet logger is not currently implemented, this is currently identical to simple. Simple is a purely JDK1.1 console-based log implementation.

avalonUses the Avalon Logkit implementation
noopDisables all logging

The ORB class provided in the package com.arjuna.orbportability.ORB shown below provides a uniform way of using the ORB. There are methods for obtaining a reference to the ORB, and for placing the application into a mode where it listens for incoming connections. There are also methods for registering application specific classes to be invoked before or after ORB initialisation.



public class ORB
{
   public static ORB getInstance(String uniqueId);
   // given the various parameters,this method initialises the ORB and
   // retains a reference to it within the ORB class.
   public synchronized void initORB () throws SystemException;
   public synchronized void initORB (Applet a, Properties p)
        throws SystemException;
   public synchronized void initORB (String[] s, Properties p)
        throws SystemException;
  //The orb method returns a reference to the ORB.
  //After shutdown is called this reference may be null.
   public synchronized org.omg.CORBA.ORB orb ();
   public synchronized boolean setOrb (org.omg.CORBA.ORB theORB);
   // If supported, this method cleanly shuts down the ORB.
   // Any pre- and post- ORB shutdown classes which
   //have been registered will also be called.
   public synchronized void shutdown ();
  public synchronized boolean addAttribute (Attribute p);
  public synchronized void addPreShutdown (PreShutdown c);
  public synchronized void addPostShutdown (PostShutdown c);
  public synchronized void destroy () throws SystemException;
  //these methods place the ORB into a listening mode,
  //where it waits for incoming invocations.
   public void run ();
   public void run (String name);
};

Note, some of the methods are not supported on all ORBs, and in this situation, a suitable exception will be thrown. The ORB class is a factory class which has no public constructor. To create an instance of an ORB you must call the getInstance method passing a unique name as a parameter. If this unique name has not been passed in a previous call to getInstance you will be returned a new ORB instance. Two invocations of getInstance made with the same unique name, within the same JVM, will return the same ORB instance.

The OA classes shown below provide a uniform way of using Object Adapters (OA). There are methods for obtaining a reference to the OA. There are also methods for registering application specific classes to be invoked before or after OA initialisation. Note, some of the methods are not supported on all ORBs, and in this situation, a suitable exception will be thrown. The OA class is an abstract class and provides the basic interface to an Object Adapter. It has two sub-classes RootOA and ChildOA, these classes expose the interfaces specific to the root Object Adapter and a child Object Adapter respectively. From the RootOA you can obtain a reference to the RootOA for a given ORB by using the static method getRootOA. To create a ChildOA instance use the createPOA method on the RootOA.

As described below, the OA class and its sub-classes provide most operations provided by the POA as specified in the POA specification.



public abstract class OA
{
  public synchronized static RootOA getRootOA(ORB associatedORB);
  public synchronized void initPOA () throws SystemException;
  public synchronized void initPOA (String[] args) throws SystemException;
  public synchronized void initOA () throws SystemException;
  public synchronized void initOA (String[] args) throws SystemException;
  public synchronized ChildOA createPOA (String adapterName,
      PolicyList policies) throws AdapterAlreadyExists, InvalidPolicy;
  public synchronized org.omg.PortableServer.POA rootPoa ();
  public synchronized boolean setPoa (org.omg.PortableServer.POA thePOA);
  public synchronized org.omg.PortableServer.POA poa (String adapterName);
  public synchronized boolean setPoa (String adapterName,
     org.omg.PortableServer.POA thePOA);
  ...
};
public class RootOA extends OA
{
  public synchronized void destroy() throws SystemException;
  public org.omg.CORBA.Object corbaReference (Servant obj);
  public boolean objectIsReady (Servant obj, byte[] id);
  public boolean objectIsReady (Servant obj);
  public boolean shutdownObject (org.omg.CORBA.Object obj);
  public boolean shutdownObject (Servant obj);
};
public class ChildOA extends OA
{
  public synchronized boolean setRootPoa (POA thePOA);
  public synchronized void destroy() throws SystemException;
  public org.omg.CORBA.Object corbaReference (Servant obj);
  public boolean objectIsReady (Servant obj, byte[] id)
      throws SystemException;
  public boolean objectIsReady (Servant obj) throws SystemException;
  public boolean shutdownObject (org.omg.CORBA.Object obj);
  public boolean shutdownObject (Servant obj);
};
The Recovery Manager is a daemon process responsible for performing crash recovery. Only one Recovery Manager runs per node. The Object Store provides persistent data storage for transactions to log data. During normal transaction processing each transaction will log persistent data needed for the commit phase to the Object Store. On successfully committing a transaction this data is removed, however if the transaction fails then this data remains within the Object Store.

The Recovery Manager functions by:

  • Periodically scanning the Object Store for transactions that may have failed. Failed transactions are indicated by the presence of log data after a period of time that the transaction would have normally been expected to finish.
  • Checking with the application process which originated the transaction whether the transaction is still in progress or not.
  • Recovering the transaction by re-activating the transaction and then replaying phase two of the commit protocol.
To start the Recovery Manager issue the following command:


java com.arjuna.ats.arjuna.recovery.RecoveryManager
If the -test flag is used with the Recovery Manager then it will display a "Ready" message when initialised, i.e.,


java com.arjuna.ats.arjuna.recovery.RecoveryManager -test
On initialization the Recovery Manager first loads in configuration information via a properties file. This configuration includes a number of recovery activators and recovery modules, which are then dynamically loaded.

Each recovery activator, which implements the com.arjuna.ats.arjuna.recovery.RecoveryActivator interface, is used to instantiate a recovery class related to the underlying communication protocol. Indeed, since the version 3.0 of JBossTS, the Recovery Manager is not specifically tied to an Object Request Broker or ORB, which is to specify a recovery instance able to manage the OTS recovery protocol the new interface RecoveryActivator is provided to identify specific transaction protocol. For instance, when used with OTS, the RecoveryActivitor has the responsibility to create a RecoveryCoordinator object able to respond to the replay_completion operation.

All RecoveryActivator instances inherit the same interface. They are loaded via the following recovery extension property:



<property
  name="com.arjuna.ats.arjuna.recovery.recoveryActivator_<number>"
  value="RecoveryClass"/>

For instance the RecoveryActivator provided in the distribution of JTS/OTS, which shall not be commented, is as follow :



<property
  name="com.arjuna.ats.arjuna.recovery.recoveryActivator_1"
  value="com.arjuna.ats.internal.jts.
     orbspecific.recovery.RecoveryEnablement"/>
Each recovery module, which implements the com.arjuna.ats.arjuna.recovery.RecoveryModule interface, is used to recover a different type of transaction/resource, however each recovery module inherits the same basic behaviour.

Recovery consists of two separate passes/phases separated by two timeout periods. The first pass examines the object store for potentially failed transactions; the second pass performs crash recovery on failed transactions. The timeout between the first and second pass is known as the backoff period. The timeout between the end of the second pass and the start of the first pass is the recovery period. The recovery period is larger than the backoff period.

The Recovery Manager invokes the first pass upon each recovery module, applies the backoff period timeout, invokes the second pass upon each recovery module and finally applies the recovery period timeout before restarting the first pass again.

The recovery modules are loaded via the following recovery extension property:



com.arjuna.ats.arjuna.recovery.recoveryExtension<number>=<RecoveryClass>
The default RecoveryExtension settings are:


<property name="com.arjuna.ats.arjuna.recovery.recoveryExtension1"
  value="com.arjuna.ats.internal.
     arjuna.recovery.AtomicActionRecoveryModule"/>
<property name="com.arjuna.ats.arjuna.recovery.recoveryExtension2"
  value="com.arjuna.ats.internal.
     txoj.recovery.TORecoveryModule"/>
<property name="com.arjuna.ats.arjuna.recovery.recoveryExtension3"
  value="com.arjuna.ats.internal.
     jts.recovery.transactions.TopLevelTransactionRecoveryModule"/>
<property  name="com.arjuna.ats.arjuna.recovery.recoveryExtension4"
  value="com.arjuna.ats.internal.
     jts.recovery.transactions.ServerTransactionRecoveryModule"/>
The operation of the recovery subsystem will cause some entries to be made in the ObjectStore that will not be removed in normal progress. The RecoveryManager has a facility for scanning for these and removing items that are very old. Scans and removals are performed by implementations of the com.arjuna.ats.arjuna.recovery.ExpiryScanner. Implementations of this interface are loaded by giving the class name as the value of a property whose name begins with ExperyScanner.

The RecoveryManager calls the scan() method on each loaded ExpiryScanner implementation at an interval determined by the property com.arjuna.ats.arjuna.recovery.expiryScanInterval. This value is given in hours default is 12. An EXPIRY_SCAN_INTERVAL value of zero will suppress any expiry scanning. If the value as supplied is positive, the first scan is performed when RecoveryManager starts; if the value is negative, the first scan is delayed until after the first interval (using the absolute value)

The default ExpiryScanner is:



<property
  name="com.arjuna.ats.arjuna.recovery.
        expiryScannerTransactionStatusManager"
  value="com.arjuna.ats.internal.arjuna.recovery.
       ExpiredTransactionStatusManagerScanner"/>
 

The following table summarize properties used by the Recovery Manager. These properties are defined by default the properties file named RecoveryManager-properties.xml.

NameDescriptionPossible ValueDefault Value
com.arjuna.ats.arjuna.recovery.periodicRecoveryPeriodInterval in seconds between initiating the periodic recovery modulesValue in seconds120
com.arjuna.ats.arjuna.recovery.recoveryBackoffPeriodInterval in seconds between first and second pass of periodic recoveryValue in seconds10
com.arjuna.ats.arjuna.recovery.recoveryExtensionXIndicates a periodic recovery module to use. X is the occurence number of the recovery module among a set of recovery modules. These modules are invoked in sort-order of namesThe class name of the periodic recovery module JBossTS provides a set classes given in the RecoveryManager-properties.xml file
com.arjuna.ats.arjuna.recovery.recoveryActivator_XIndicates a recovery activator to use. X is the occurence number of the recovery activator among a set of recovery activators. The class name of the periodic recovery activatorJBossTS provide one class that manages the recovery protocol specified by the OTS specification
com.arjuna.ats.arjuna.recovery.expiryScannerXXXExpiry scanners to use (order of invocation is random). Names must begin with "com.arjuna.ats.arjuna.recovery.expiryScanner"Class nameJBossTS provides one class given in the RecoveryManager-properties.xml file
com.arjuna.ats.arjuna.recovery.expiryScanIntervalInterval, in hours, between running the expiry scanners. This can be quite long. The absolute value determines the interval - if the value is negative, the scan will NOT be run until after one interval has elapsed. If positive the first scan will be immediately after startup. Zero will prevent any scanning. Value in hours12
com.arjuna.ats.arjuna.recovery.transactionStatusManagerExpiryTimeAge, in hours, for removal of transaction status manager item. This should be longer than any ts-using process will remain running. Zero = Never removed. Value in Hours12
com.arjuna.ats.arjuna.recovery.transactionStatusManagerPortUse this to fix the port on which the TransactionStatusManager listensPort number (short) use a free port

To ensure that your JBossTS installation is fully operational, we will run the simple demo.

Please follow these steps before running the transactional applications

In the client window you should see the following lines:



     Creating a transaction !
     Call the Hello Server !
     Commit transaction
     Done

In the server, which must be stopped by hand, you should see:



     Hello - called within a scope of a transaction

Transaction management is one of the most crucial requirements for enterprise application development. Most of the large enterprise applications in the domains of finance, banking and electronic commerce rely on transaction processing for delivering their business functionality.

Enterprise applications often require concurrent access to distributed data shared amongst multiple components, to perform operations on data. Such applications should maintain integrity of data (as defined by the business rules of the application) under the following circumstances:

In such cases, it may be required that a group of operations on (distributed) resources be treated as one unit of work. In a unit of work, all the participating operations should either succeed or fail and recover together. This problem is more complicated when

In either case, it is required that success or failure of a unit of work be maintained by the application. In case of a failure, all the resources should bring back the state of the data to the previous state ( i.e., the state prior to the commencement of the unit of work).

From the programmer's perspective a transaction is a scoping mechanism for a collection of actions which must complete as a unit. It provides a simplified model for exception handling since only two outcomes are possible:

To illustrate the reliability expected by the application let’s consider the funds transfer example which is familiar to all of us.

The Money transfer involves two operations: Deposit and Withdrawal

The complexity of implementation doesn't matter; money moves from one place to another. For instance, involved accounts may be either located in a same relational table within a database or located on different databases.

A Simple transfer consists on moving money from savings to checking while a Complex transfer can be performed at the end- of- day according to a reconciliation between international banks

The concept of a transaction, and a transaction manager (or a transaction processing service) simplifies construction of such enterprise level distributed applications while maintaining integrity of data in a unit of work.

A transaction is a unit of work that has the following properties:

These properties, called as ACID properties, guarantee that a transaction is never incomplete, the data is never inconsistent, concurrent transactions are independent, and the effects of a transaction are persistent.

The transaction manager is the core component of a transaction processing environment. Its main responsibilities are to create transactions when requested by application components, allow resource enlistment and delistment, and to manage the two-phase commit or recovery protocol with the resource managers.

A typical transactional application begins a transaction by issuing a request to a transaction manager to initiate a transaction. In response, the transaction manager starts a transaction and associates it with the calling thread. The transaction manager also establishes a transaction context. All application components and/or threads participating in the transaction share the transaction context. The thread that initially issued the request for beginning the transaction, or, if the transaction manager allows, any other thread may eventually terminate the transaction by issuing a commit or rollback request.

Before a transaction is terminated, any number of components and/or threads may perform transactional operations on any number of transactional resources known to the transaction manager. If allowed by the transaction manager, a transaction may be suspended or resumed before finally completing the transaction.

Once the application issues the commit request, the transaction manager prepares all the resources for a commit operation, and based on whether all resources are ready for a commit or not, issues a commit or rollback request to all the resources.

Resource Manager responsibilities could be summarized as follow:

Basically, the Recovery is the mechanism which preserves the transaction atomicity in presence of failures. The basic technique for implementing transactions in presence of failures is based on the use of logs. That is, a transaction system has to record enough information to ensure that it can be able to return to a previous state in case of failure or to ensure that changes committed by a transaction are properly stored.

In addition to be able to store appropriate information, all participants within a distributed transaction must log similar information which allow them to take a same decision either to set data in their final state or in their initial state.

Two techniques are in general used to ensure transaction's atomicity. A first technique focuses on manipulated data, such the Do/Undo/Redo protocol (considered as a recovery mechanism in a centralized system), which allow a participant to set its data in their final values or to retrieve them in their initial values. A second technique relies on a distributed protocol named the two phases commit, ensuring that all participants involved within a distributed transaction set their data either in their final values or in their initial values. In other words all participants must commit or all must rollback.

In addition to failures we refer as centralized such system crashes, communication failures due for instance to network outages or message loss have to be considered during the recovery process of a distributed transaction.

In order to provide an efficient and optimized mechanism to deal with failure, modern transactional systems typically adopt a “presume abort” strategy, which simplifies the transaction management.

The presumed abort strategy can be stated as «when in doubt, abort». With this strategy, when the recovery mechanism has no information about the transaction, it presumes that the transaction has been aborted.

A particularity of the presumed-abort assumption allows a coordinator to not log anything before the commit decision and the participants do not to log anything before they prepare. Then, any failure which occurs before the 2pc starts lead to abort the transaction. Furthermore, from a coordinator point of view any communication failure detected by a timeout or exception raised on sending prepare is considered as a negative vote which leads to abort the transaction. So, within a distributed transaction a coordinator or a participant may fail in two ways: either it crashes or it times out for a message it was expecting. When a coordinator or a participant crashes and then restarts, it uses information on stable storage to determine the way to perform the recovery. As we will see it the presumed-abort strategy enable an optimized behavior for the recovery.
Saying that a distributed transaction can involve several distributed participants, means that these participant must be integrated within a global transaction manager which has the responsibility to ensure that all participants take a common decision to commit or rollback the distributed transaction. The key of such integration is the existence of a common transactional interface which is understood by all participants, transaction manager and resource managers such databases.

The importance of common interfaces between participants, as well as the complexity of their implementation, becomes obvious in an open systems environment. For this aim various distributed transaction processing standards have been developed by international standards organizations. Among these organizations, We list three of them which are mainly considered in the Jboss Transaction Service product:

  • The X/Open model and its successful XA interface
  • The OMG with its CORBA infrastructure and the Object Transaction Service and finally
  • The Java Community Process leaded by Sun with its JTA/JTS specification
Basically these standards have proposed logical models, which divide transaction processing into several functions:
  • those assigned to the application which ties resources together in application- specific operations
  • those assigned to the Resource manager which access physically to data stores
  • functions performed by the Transaction Manager which manages transactions, and finally
  • Communication Resource Managers which allow to exchange information with other transactional domains.

JBoss Transaction Service (JBossTS) assures complete, accurate business transactions for any Java based applications, including those written for the Java EE and EJB frameworks.

JBossTS is a 100% Java implementation of a distributed transaction management system based on the Sun Microsystems Java EE Java Transaction Service (JTS) standard. Our implementation of the JTS utilizes the Object Management Group's (OMG) Object Transaction Service (OTS) model for transaction interoperability as recommended in the Java EE and EJB standards. Although any JTS-compliant product will allow Java objects to participate in transactions, one of the key features of JBossTS is it's 100% Java implementation. This allows JBossTS to support fully distributed transactions that can be coordinated by distributed parties.

JBossTS runs can be run both as an embedded distributed service of an application server (e.g. JBossAS), affording the user all the added benefits of the application server environment such as real-time load balancing, unlimited linear scalability and unmatched fault tolerance that allows you to deliver an always-on solution to your customers. It is also available as a free-standing Java Transaction Service.

In addition to providing full compliance with the latest version of the JTS specification, JBossTS leads the market in providing many advanced features such as fully distributed transactions and ORB portability with POA support.

JBossTS works on a number of operating systems including Red Hat linux, Sun Solaris and Microsoft Windows XP. It requires a Java 5 or later environment.

The Java Transaction API support for JBossTS comes in two flavours:

The sample application consists of a banking application that involves a bank able to manage accounts on behalf of clients. Clients can obtain information on accounts and perform operations such credit, withdraw and transfer money from one account to an other.

Figure 1 - The Banking Applications

Each operation provided to the client leads to the creation of a transaction; therefore in order to commit or rollback changes made on an account, a resource is associated with the account to participate to the transaction commitment protocol. According to the final transaction decision, the resource is able to set the Account either to its initial state (in case of rollback) or to the final state (in case of commit). From the transactional view, Figure 2 depicts of transactional components.

Figure 2 - The Banking Application and the transactional Component

Assuming that the JBoss Transactioning product has been installed, this trail provides a set of examples that show how to build transactional applications. Two types of transactional applications are presented, those using the JTA interface and those accessing to the JTS (OTS) interfaces.

Please follow these steps before running the transactional applications

To illustrate the programming interfaces possibilities enabled by JBossTS, the banking application is provided in several versions: a version that uses the JTA API and a second that uses JTS/OTS interfaces.

This trail focuses to understanding concepts related to the creation of transactions and the behavior of the commitment protocol, while the next trail illustrates the similar application with persistent data.

The Banking sample using JTA creates local transactions, ensure that JTA is configured for local transactions as explained above.

To launch the JTA version of the Banking application, which creates only local transactions, execute the following java program:



java com.arjuna.demo.jta.localbank.BankClient

Once one of the program given above is launched the following lines are displayed:



-------------------------------------------------
  Bank client
-------------------------------------------------
Select an option :
   0. Quit
   1. Create a new account.
   2. Get an account information.
   3. Make a transfer.
   4. Credit an account.
   5. Withdraw from an account
Your choice :

After introducing your choice, the appropriate operation is performed by the Bank object, to get the requested account, and by the account to execute the credit or withdraw or to return the current balance. Let's consider the following execution.

Enter the number 1 as your choice, then give the name "Foo" as the account name and "1000" as an initial value of the account to create. You should get the following lines:

Your choice : 1

- Create a new account -
------------------------
Name : Foo
Initial balance : 1000
Beginning a User transaction to create account
XA_START[]
Attempt to commit the account creation transaction
XA_END[]
XA_COMMIT (ONE_PHASE)[]
  • The line XA_START indicates that the AccountResource object that implements the XAResource interface and enlisted to participate in the account creation transaction, receives the indication from the Transaction Manager that the transaction has started.
  • The line XA_END indicates that the calling thread in which the AccountRessource object is associated shall be ended to enable the transaction completion as recommended by the X/Open specification.
  • Since only one AccountResource then only one XAResource is involved in the account creation transaction, the two phases needed to get a consensus in the 2PC protocol are not mandatory. The one phase commit optimization, indicated by the "XA_COMMIT (ONE_PHASE)", is applied.

In the same way create a second account with the name "Bar" and the initial balance set to 500.

As a choice now, enter "3" to make a transfer (300) from "Foo" to "Bar".

Your choice : 3

- Make a transfer -
-------------------
Take money from : Foo
Put money to : Bar
Transfert amount : 300
Beginning a User transaction to get balance
XA_START[]
XA_START[]
XA_END[]
XA_PREPARE[]
XA_END[]
XA_PREPARE[]
XA_COMMIT[]
XA_COMMIT[]
  • Now two AccountResource objects, then two XAResource objects are enlisted with the transaction. The displayed lines show that the two phases, prepare and commit, are applied.

Any attempt to manipulate an account that it doesn't exist leads to throw the NotExistingAccount exception and to rollback the transaction in progress. For instance, let's withdraw money from an account FooBar not previously created.

Your choice : 5

- Withdraw from an Account -
----------------------------
Give the Account name : FooBar
Amount to withdraw : 200
Beginning a User transaction to
withdraw from an account
The requested account does not exist!
ERROR - javax.transaction.RollbackException

From an architectural point of view of JTA, the bank client is considered as an application program able to manage transactions via the javax.transaction.UserTransaction interface. The following portion of code illustrates how a JTA transaction is started and terminated when the client asks to transfer money from one account to another. This also describes what are JBossTS packages that need to be used in order to obtain appropriate objects instances (such UserTransaction).

Note: The code below is a simplified view of the BankClient.java program. Only the transfer operation is illustrated; other operations manage transactions in the same way. (see for details the src/com/arjuna/demo/jta/localbank/BankClient.java)



package com.arjuna.demo.jta.localbank;
public class BankClient
{
   private Bank _bank;
   // This operation is used to make a transfer
   //from an account to another account
   private void makeTransfer()
   {
     System.out.print("Take money from : ");
     String name_supplier = input();
     System.out.print("Put money to : ");
     String name_consumer = input();
     System.out.print("Transfer amount : ");
     String amount = input();
     float famount = 0;
     try
      {
        famount = new Float( amount ).floatValue();
      }
     catch ( java.lang.Exception ex )
      {
        System.out.println("Invalid float number, abort operation...");
        return;
      }
     try
      {
       //the following instruction asks a specific JBossTS
       //class to obtain a UserTransaction instance
       javax.transaction.UserTransaction userTran = com.arjuna.ats.jta.UserTransaction.userTransaction();
       System.out.println("Beginning a User transaction to get balance");
       userTran.begin();
       Account supplier = _bank.get_account( name_supplier );
       Account consumer = _bank.get_account( name_consumer );
       supplier.debit( famount );
       consumer.credit( famount );
       userTran.commit( );
      }
     catch (Exception e)
      {
       System.err.println("ERROR - "+e);
      }
   }
   ......
}

The Bank object has mainly two operations: creating an account, which is added in the account list, and returning an Account object. No transactional instruction is performed by the Bank object



package com.arjuna.demo.jta.localbank;
public class Bank {
   private java.util.Hashtable _accounts;
   public Bank()
   {
     _accounts = new java.util.Hashtable();
   }
   public Account create_account( String name )
   {
     Account acc = new Account(name);
     _accounts.put( name, acc );
      return acc;
   }
   public Account get_account(String name)
   throws NotExistingAccount
   {
     Account acc = ( Account ) _accounts.get( name );
     if ( acc == null )
       throw new NotExistingAccount("The Account requested does not exist");
     return acc;
   }
}

The Account object provides mainly three methods balance, credit and withdraw. However, in order to provide the transactional behaviour, rather than to modify the current account directly (according to credit or withdraw) this task is delegated to an AccountResource object that is able, according to the transaction outcome, to set the account value either to its initial state or its final state.

The AccountResource object is in fact an object that implements the javax.transactions.XAResource, then able to participate to the transaction commitment. For this aim, the Account object has to register or enlist the AccountResource object as a participant after having obtaining the reference of the javax.transaction.Transaction object via the javax.transaction.TransactionManager object



package com.arjuna.demo.jta.localbank;
public class Account
{
   float _balance;
   AccountResource accRes = null;
   public Account(String name)
   {
     _name = name;
     _balance = 0;
   }
   public float balance()
   {
     return getXAResource().balance();;
   }
   public void credit( float value )
   {
     getXAResource().credit( value );
   }
   public void debit( float value )
   {
     getXAResource().debit( value );
   }
   public AccountResource getXAResource()
   {
     try
     {
       javax.transaction.TransactionManager transactionManager = com.arjuna.ats.jta.TransactionManager.transactionManager(); javax.transaction.Transaction currentTrans = transactionManager.getTransaction();
       if (accRes == null) {
         currentTrans.enlistResource( accRes = new AccountResource(this, _name) );
       }
       currentTrans.delistResource( accRes, XAResource.TMSUCCESS );
     }
     catch (Exception e)
     {
       System.err.println("ERROR - "+e);
     }
     return accRes;
   }
   ...
}

The AccountResource class that implements the javax.transaxtion.XAResource interface provides similar methods as the Account class (credit, withdraw and balance) but also all methods specified by the javax.transaxtion.XAResource. The following portion of code describes how the methods prepare, commit and rollback are implemented.



public class AccountResource implements XAResource
{
   public AccountResource(Account account, String name )
   {
     _name = name;
     _account = account;
     _initial_balance = account._balance;
     _current_balance = _initial_balance;
   }
   public float balance()
   {
     return _current_balance;
   }
   public void credit( float value )
   {
     _current_balance += value;
   }
   public void debit( float value )
   {
     _current_balance -= value;
   }
   public void commit(Xid id, boolean onePhase) throws XAException
   {
     //The value of the associated Account object is modified
     _account._balance = _current_balance;
   }
   public int prepare(Xid xid) throws XAException
   {
     if ( _initial_balance == _current_balance ) //account not modified
        return (XA_RDONLY);
     if ( _current_balance < 0 )
        throw new XAException(XAException.XA_RBINTEGRITY);
        //If the integrity of the account is corrupted then vote rollback
     return (XA_OK); //return OK
   }
   
public void rollback(Xid xid) throws XAException

   {
     //Nothing is done
   }
   
   private float _initial_balance;

   private float _current_balance;
   private Account _account;
   }
 }

The JTS version of the Banking application means that the Object Request Broker will be used. The JBossTS distribution is provided to work with the bundled JacORB version

To describe the possibilities provided by JBossTS to build a transactional application according to the programming models defined by the OTS specification, the Banking Application is programmed in different ways.

JTS Local Transactions>

JTS Distributed Transactions

The JTS version of the Banking application means that the Object Request Broker will be used. The JBossTS distribution is provided to work with the bundled JacORB version

Note: Ensure that the jacorb jar files are added in your CLASSPATH

To launch the JTS version of the Banking application, execute the following java program

Once one of the program given above is launched the following lines are displayed:

After introducing your choice, the appropriate operation is performed by the Bank object, to get the requested account, and by the account to execute the credit or withdraw or to return the current balance. Let's consider the following execution.

Enter the number 1 as your choice, then give the name "Foo" as the account name and "1000" as an initial value of the account to create. You should get the following lines:

In the same way create a second account with the name "Bar" and the initial balance set to 500.

As a choice now, enter "3" to make a transfer (300) from "Foo" to "Bar".

Any attempt to manipulate an account that it doesn't exist leads to throw the NotExistingAccount exception and to rollback the transaction in progress. For instance, let's withdraw money from an account FooBar not previously created.

The JTS version of the Banking application means that the Object Request Broker will be used. The JBossTS distribution is provided to work with the bundled JacORB version

Note: Ensure that the jacorb jar files are added in your CLASSPATH

In both cases (implicit and explicit), the Bank Server, which can be stopped by hand, displays the following lines:

In both cases (implicit and Explicit), the Bank Client window displays the following lines:

After entering your choice, the appropriate operation is performed by the remote Bank object, to get the requested account, and by the account to execute the credit or withdraw or to return the current balance. Let's consider the following execution.

Enter the number 1 as your choice, then give the name "Foo" as the account name and "1000" as an initial value of the account to create. You should get in the server window a result that terminates with the following line

In the same way create a second account with the name "Bar" and the initial balance set to 500.

As a choice now, enter in the client window "3" to make a transfer (300) from "Foo" to "Bar".

In the Server window you should see a result with the following lines

Any attempt to manipulate an account that it doesn't exist leads to throw the NotExistingAccount exception and to rollback the transaction in progress. For instance, let's withdraw money from an account FooBar not previously created.

It is possible to run the JBoss Transaction Service and recovery manager processes on a different machine and have clients access these centralized services in a hub-and-spoke style architecture.

All that must be done is to provide the clients with enough information to contact the transaction service (such as the ORB's NameService). However, configuring the ORB is beyond the remit of this trailmap and so we shall opt for a simpler mechanism wherby the transaction services IOR is shared by access to a common file.

This trailmap stage assumes that the transaction service has been appropriately installed and configured (the setenv.[bat|sh] script has been ran) onto two hosts (for the purpose of explanation we shall refer to these hosts as host1 and host2).

From an architectural point of view of JTS, the bank client is considered as an application program able to manage transactions either in a direct or indirect management mode, respectively with the interfaces org.omg.CosTransactions.TransactionFactory and org.omg.CosTransactions.Terminator or with the org.omg.CosTransactions.Current interface. Transactions created by the client in the Banking application are done in the indirect mode.

The following portion of code illustrates how a JTS transaction is started and terminated when the client asks to transfer money from one account to another. This also describes what are JBossTS packages that need to be used in order to obtain appropriate objects instances (such Current).

Note: The code below is a simplified view of the BankClient.java program. Only the transfer operation is illustrated; other operations manage transactions in the same way. (see for details the ../src/com/arjuna/demo/jts/localbank/BankClient.java)

package com.arjuna.demo.jta.localbank;
import com.arjuna.ats.jts.OTSManager;
import com.arjuna.ats.internal.jts.ORBManager;

                    
public class BankClient

{
   private Bank _bank; //Initialised on BankClient initializations
   ....
   // This operation is used to make a transfer from an account to another account
   private void makeTransfer()
   {
     System.out.print("Take money from : ");
     String name_supplier = input();
     System.out.print("Put money to : ");
     String name_consumer = input();
     System.out.print("Transfert amount : ");
     String amount = input();
     float famount = 0;
     try
      {
        famount = new Float( amount ).floatValue();
      }
     catch ( java.lang.Exception ex )
      {
        System.out.println("Invalid float number, abort operation...");
        return;
      }
     try
      {
       //the following instruction asks a specific JBossTS class to obtain a Current instance
       Current current = OTSManager.get_current();
       System.out.println("Beginning a User transaction to get balance");
       current.begin();
       Account supplier = _bank.get_account( name_supplier );
       Account consumer = _bank.get_account( name_consumer );
       supplier.debit( famount );
       consumer.credit( famount );
       current.commit( );
      }
     catch (Exception e)
      {
       System.err.println("ERROR - "+e);
      }
   }

Since JTS is used invocations against an ORB are needed, such ORB and Object Adapter instantiation and initialisation. To ensure a better portability, the ORB Portability API provides a set of methods that can be used as described below.

public static void main( String [] args )

{  
    try {
     myORB = ORB.getInstance("test");// Create an ORB instance
     myOA = OA.getRootOA(myORB); //Obtain the Root POA
     myORB.initORB(args, null); //Initialise the ORB
     myOA.initOA(); //Initialise the POA
     // The ORBManager is a class provided by JBossTS to facilitate the association
     // of the ORB/POA with the transaction service
     ORBManager.setORB(myORB);
     ORBManager.setPOA(myOA);
     ....
   }
   catch(Exception e)
   {
     e.printStackTrace(System.err);
   }
}

The Bank object has mainly two operations: creating an account, which is added in the account list, and returning an Account object. No transactional instruction is performed by the Bank object

The Account object provides mainly three methods balance, credit and withdraw. However, in order to provide the transactional behaviour, rather than to modify the current account directly (according to credit or withdraw) this task is delegated to an AccountResource object that is able, according to the transaction outcome, to set the account value either to its initial state or its final state.

The AccountResource object is in fact an object that implements the org.omg.CosTransactions.Resource, then able to participate to the transaction commitment. For this aim, the Account object has to register the AccountResource object as a participant, after having obtaining the reference of the org.omg.CosTransactions.Coordinator object , itself obtained via the org.omg.CosTransactions.Control object

To be considered as a org.omg.CosTransactions.Resource, the AccountResource class shall extends the class org.omg.CosTransactions.ResourcePOA generated by the CORBA IDL compiler. The AccountRessource provides similar methods as the Account class (credit, withdraw and balance) with the appropriate methods to participate to the 2PC protocol. The following portion of code describes how the methods prepare, commit and rollback are implemented.

public class AccountResource extends org.omg.CosTransactions.ResourcePOA

{
   public AccountResource(Account account, String name )
   {
     _name = name;
     _account = account;
     _initial_balance = account._balance;
     _current_balance = _initial_balance;
   }
   public float balance()
   {
     return _current_balance;
   }
   public void credit( float value )
   {
     _current_balance += value;
   }
   public void debit( float value )
   {
     _current_balance -= value;
   }
   public org.omg.CosTransactions.Vote prepare()
       throws org.omg.CosTransactions.HeuristicMixed, org.omg.CosTransactions.HeuristicHazard
    {
      if ( _initial_balance == _current_balance )
       return org.omg.CosTransactions.Vote.VoteReadOnly;
     if ( _current_balance < 0 )
       return org.omg.CosTransactions.Vote.VoteRollback;
     return org.omg.CosTransactions.Vote.VoteCommit;
    }
   public void rollback()
     throws org.omg.CosTransactions.HeuristicCommit, org.omg.CosTransactions.HeuristicMixed,
                            org.omg.CosTransactions.HeuristicHazard
   {
     //Nothing to do
   }
   public void commit()
     throws org.omg.CosTransactions.NotPrepared, org.omg.CosTransactions.HeuristicRollback,
                      org.omg.CosTransactions.HeuristicMixed, org.omg.CosTransactions.HeuristicHazard
   {
      _account._balance = _current_balance;
   }
   public void commit_one_phase()
     throws org.omg.CosTransactions.HeuristicHazard
   {
     _account._balance = _current_balance;
   }
   .....
   private float _initial_balance;

   private float _current_balance;
   private Account _account;
   }
 

The bank client is an application program able to manage transactions either in a direct or indirect management mode, respectively with the interfaces org.omg.CosTransactions.TransactionFactory and org.omg.CosTransactions.Terminator or with the org.omg.CosTransactions.Current interface. Transactions created by the client in the Banking application are done in the indirect mode.

Invoking a remote object within a CORBA environment means that the remote object implements a CORBA interface defined in a CORBA idl file. The following Bank.idl describes the interfaces then the possible kind of distributed CORBA objects involved in the banking application. There is no any interface that inherits the CosTransactions::TransactionalObject interface, which means that for any remote invocations the transactional context is normally not propagated. However, since the Account object may have to register Resource objects that participate to transaction completion, a context is needed. In the following Bank.idl file operations defined in the Account interface have explicitly in their signature the CosTransactions::Control argument meaning that it passed explicitly by the caller - in this case the Bank Client program.



module arjuna {
   module demo {
     module jts {
      module explicitremotebank {
        interface Account :
        {
          float balance(in CosTransactions::Control ctrl);
          void credit( in CosTransactions::Control ctrl, in float value );
          void debit( in CosTransactions::Control ctrl, in float value );
        };
        exception NotExistingAccount
        { };
        interface Bank
        {
          Account create_account( in string name );
          Account get_account( in string name )
            raises( NotExistingAccount );
        };
       };
      };
     };
   };
   

The following portion of code illustrates how a JTS transaction is started and terminated when the client asks to transfer money from one account to another. This also describes what are JBossTS packages that need to be used in order to obtain appropriate objects instances (such Current).

Note: The code below is a simplified view of the BankClient.java program. Only the transfer operation is illustrated; other operations manage transactions in the same way. (see for details the src/com/arjuna/demo/jts/explicitremotebank/BankClient.java)

package com.arjuna.demo.jta.remotebank;
import com.arjuna.ats.jts.OTSManager;

public class BankClient
{
   private Bank _bank;
   ....
   // This operation is used to make a transfer
   //from an account to another account
   private void makeTransfer()
   {
     //get the name of the supplier(name_supplier) and
     // the consumer(name_consumer)
     // get the amount to transfer (famount)
     ...
     try
      {
       //the following instruction asks a specific
       //JBossTS class to obtain a Current instance
       Current current = OTSManager.get_current();
       System.out.println("Beginning a User transaction to get balance");
       current.begin();
       Account supplier = _bank.get_account( name_supplier );
       Account consumer = _bank.get_account( name_consumer );
       supplier.debit( current.get_control(), famount );
       //The Control is explicitly propagated
       consumer.credit( current.get_control(), famount );
       current.commit( );
      }
     catch (Exception e)
      {
       ...
      }
   }

Since JTS is used invocations against an ORB are needed, such ORB and Object Adapter instantiation and initialisation. To ensure a better portability, the ORB Portability API provides a set of methods that can be used as described below.

public static void main( String [] args )

{
  ....
  myORB = ORB.getInstance("test");// Create an ORB instance myORB.initORB(args, null); //Initialise the ORB
  org.omg.CORBA.Object obj = null;
  try
  {
     //Read the reference string from a file then convert to Object
     ....
      obj = myORB.orb().string_to_object(stringTarget);
  }
  catch ( java.io.IOException ex )
  {
     ...
  }
  Bank bank = BankHelper.narrow(obj);
   ....
}

The Bank object has mainly two operations: creating an account, which is added in the account list, and returning an Account object. No transactional instruction is performed by the Bank object. The following lines decribe the implementation of the Bank CORBA object

public class BankImpl extends BankPOA {

     public BankImpl(OA oa)
     {
       _accounts = new java.util.Hashtable();
       _oa = oa;
     }
     public Account create_account( String name )
     {
         AccountImpl acc = new AccountImpl(name);
         _accounts.put( name, acc );
          return com.arjuna.demo.jts.remotebank.AccountHelper.
               narrow(_oa.corbaReference(acc));
     }
     public Account get_account(String name)
          throws NotExistingAccount
     {
      AccountImpl acc = ( AccountImpl ) _accounts.get( name );
      if ( acc == null )
       throw new NotExistingAccount("The Account requested does not exist");
      return com.arjuna.demo.jts.remotebank.AccountHelper.
           narrow(_oa.corbaReference(acc));
     }
     private java.util.Hashtable _accounts;// Accounts created by the Bank
     private OA _oa;
}

After having defined an implementation of the Bank object, we should now create an instance and make it available for client requests. This is the role of the Bank Server that has the responsibility to create the ORB and the Object Adapater instances, then the Bank CORBA object that has its object reference stored in a file well known by the bank client. The following lines describe how the Bank server is implemented.

public class BankServer

{
      public static void main( String [] args )
      {
       ORB myORB = null;
       RootOA myOA = null;
       try
       {
        myORB = ORB.getInstance("ServerSide"); myOA = OA.getRootOA(myORB); myORB.initORB(args, null); myOA.initOA();
        ....
        BankImpl bank = new BankImpl(myOA);
        String reference = myORB.orb(). object_to_string(myOA.corbaReference(bank));
        //Store the Object reference in the file
        ...
        System.out.println("The bank server is now ready...");
        myOA.run();
      }
}

The Account object provides mainly three methods balance, credit and withdraw. However, in order to provide the transactional behaviour, rather than to modify the current account directly (according to credit or withdraw) this task is delegated to an AccountResource object that is able, according to the transaction outcome, to set the account value either to its initial state or its final state.

The AccountResource object is in fact an object that implements the org.omg.CosTransactions.Resource, then able to participate to the transaction commitment. For this aim, the Account object has to register the AccountResource object as a participant, after having obtaining the reference of the org.omg.CosTransactions.Coordinator object , itself obtained via the org.omg.CosTransactions.Control object



package com.arjuna.demo.jta.remotebank;
import org.omg.CosTransactions.*;
import ....
public class AccountImpl extends AccountPOA
{
   float _balance;
   AccountResource accRes = null;
   public Account(String name )
   {
     _name = name;
     _balance = 0;
   }
   public float balance(Control ctrl)
   {
     return getResource(ctrl).balance();;
   }
   public void credit(Control ctrl, float value )
   {
     getResource(ctrl).credit( value );
   }
   public void debit(Control ctrl, float value )
   {
     getResource(ctrl).debit( value );
   }
   public AccountResource getResource(Control control)
   {
      try
      {
         if (accRes == null) {
            accRes = new AccountResource(this, _name) ;
            //The invocation on the ORB illustrates the fact that the same //ORB instance created by the Bank Server is returned. ref = org.omg.CosTransactions.ResourceHelper. narrow(OA.getRootOA(ORB.getInstance("ServerSide")). corbaReference(accRes)); RecoveryCoordinator recoverycoordinator = control.get_coordinator().register_resource(ref);
         }
      }
      catch (Exception e){...}
      return accRes;
       }
   ...
}

To be considered as a org.omg.CosTransactions.Resource, the AccountResource class shall extends the class org.omg.CosTransactions.ResourcePOA generated by the CORBA IDL compiler. The AccountRessource provides similar methods as the Account class (credit, withdraw and balance) with the appropriate methods to participate to the 2PC protocol. The following portion of code describes how the methods prepare, commit and rollback are implemented.

public class AccountResource extends org.omg.CosTransactions.ResourcePOA

{
   public AccountResource(Account account, String name )
   {
     _name = name;
     _account = account;
     _initial_balance = account._balance;
     _current_balance = _initial_balance;
   }
   public float balance()
   {
     return _current_balance;
   }
   public void credit( float value )
   {
     _current_balance += value;
   }
   public void debit( float value )
   {
     _current_balance -= value;
   }
   public org.omg.CosTransactions.Vote prepare()
       throws org.omg.CosTransactions.HeuristicMixed,
       org.omg.CosTransactions.HeuristicHazard
  {
    if ( _initial_balance == _current_balance )
       return org.omg.CosTransactions.Vote.VoteReadOnly;
    if ( _current_balance < 0 )
       return org.omg.CosTransactions.Vote.VoteRollback;
    return org.omg.CosTransactions.Vote.VoteCommit;
  }
   public void rollback()
     throws org.omg.CosTransactions.HeuristicCommit,
     org.omg.CosTransactions.HeuristicMixed,
     org.omg.CosTransactions.HeuristicHazard
   {
     //Nothing to do
   }
   public void commit()
     throws org.omg.CosTransactions.NotPrepared,
     org.omg.CosTransactions.HeuristicRollback,
     org.omg.CosTransactions.HeuristicMixed,
     org.omg.CosTransactions.HeuristicHazard
   {
      _account._balance = _current_balance;
   }
   public void commit_one_phase()
     throws org.omg.CosTransactions.HeuristicHazard
   {
     _account._balance = _current_balance;
   }
   .....
   private float _initial_balance;

   private float _current_balance;
   private Account _account;
   }
 

The bank client is an application program able to manage transactions either in a direct or indirect management mode, respectively with the interfaces org.omg.CosTransactions.TransactionFactory and org.omg.CosTransactions.Terminator or with the org.omg.CosTransactions.Current interface. Transactions created by the client in the Banking application are done in the indirect mode.

Invoking a remote object within a CORBA environment means that the remote object implements a CORBA interface defined in a CORBA idl file. The following Bank.idl describes the interfaces then the possible kind of distributed CORBA objects involved in the banking application. Only the Account interface inherits the CosTransactions::TransactionalObject interface, this means that an Account CORBA object is expected to invoked within a scope of transaction and the transactional context is implicitly propagated.



module arjuna {
   module demo {
     module jts {
      module remotebank {
        interface Account : CosTransactions::TransactionalObject
        {
          float balance();
          void credit( in float value );
          void debit( in float value );
        };
        exception NotExistingAccount
        { };
        interface Bank
        {
          Account create_account( in string name );
          Account get_account( in string name )
            raises( NotExistingAccount );
        };
       };
      };
     };
   };

The following portion of code illustrates how a JTS transaction is started and terminated when the client asks to transfer money from one account to another. This also describes what are JBossTS packages that need to be used in order to obtain appropriate standard JTS API objects instances (such Current).

Note: The code below is a simplified view of the BankClient.java program. Only the transfer operation is illustrated; other operations manage transactions in the same way. (see for details the src/com/arjuna/demo/jts/localbank/BankClient.java)



package com.arjuna.demo.jta.remotebank; import com.arjuna.ats.jts.OTSManager;
public class BankClient
{
   private Bank _bank;
   ....
   // This operation is used to make a transfer
   // from an account to another account
   private void makeTransfer()
   {
     //get the name of the supplier(name_supplier)
     // and the consumer(name_consumer)
     // get the amount to transfer (famount)
     ...
     try
      {
       //the following instruction asks a
       // specific JBossTS class
       // to obtain a Current instance
       Current current = OTSManager.get_current();
       System.out.println("Beginning a User
              transaction to get balance");
       current.begin();
       Account supplier = _bank.get_account( name_supplier );
       Account consumer = _bank.get_account( name_consumer );
       supplier.debit( famount );
       consumer.credit( famount );
       current.commit( );
      }
     catch (Exception e)
      {
       ...
      }
   }

Since JTS is used invocations against an ORB are needed, such ORB and Object Adapter instantiation and initialisation. To ensure a better portability, the ORB Portability API provides a set of methods that can be used as described below.

public static void main( String [] args )

{  .... myORB = ORB.getInstance("test"); myORB.initORB(args, null); //Initialise the ORB org.omg.CORBA.Object obj = null;
     try
      {
        //Read the reference string from
        // a file then convert to Object
        ....
        obj = myORB.orb().string_to_object(stringTarget);
      }
     catch ( java.io.IOException ex )
     {
       ...
     }
     Bank bank = BankHelper.narrow(obj);
    ....
}

The Bank object has mainly two operations: creating an account, which is added in the account list, and returning an Account object. No transactional instruction is performed by the Bank object. The following lines decribe the implementation of the Bank CORBA object

public class BankImpl extends BankPOA {

     public BankImpl(OA oa)
     {
       _accounts = new java.util.Hashtable();
       _oa = oa;
     }
     public Account create_account( String name )
     {
         AccountImpl acc = new AccountImpl(name);
         _accounts.put( name, acc );
          return com.arjuna.demo.jts.remotebank.AccountHelper.
               narrow(_oa.corbaReference(acc));
     }
     public Account get_account(String name)
          throws NotExistingAccount
     {
        AccountImpl acc = ( AccountImpl ) _accounts.get( name );
        if ( acc == null )
          throw new NotExistingAccount("The Account requested
                      does not exist");
        return com.arjuna.demo.jts.remotebank.AccountHelper.
             narrow(_oa.corbaReference(acc));
     }
     private java.util.Hashtable _accounts;
        // Accounts created by the Bank
     private OA _oa;
}

After having defined an implementation of the Bank object, we should now create an instance and make it available for client requests. This is the role of the Bank Server that has the responsibility to create the ORB and the Object Adapater instances, then the Bank CORBA object that has its object reference stored in a file well known by the bank client. The following lines describe how the Bank server is implemented.

public class BankServer

{
      public static void main( String [] args )
      {
       ORB myORB = null;
       RootOA myOA = null;
       try
       {
        myORB = ORB.getInstance("ServerSide"); myOA = OA.getRootOA(myORB); myORB.initORB(args, null); myOA.initOA();
        ....
        BankImpl bank = new BankImpl(myOA);
        String reference = myORB.orb(). object_to_string(myOA.corbaReference(bank));
        //Store the Object reference in the file
        ...
        System.out.println("The bank server is now ready...");
        myOA.run();
      }
}

The Account object provides mainly three methods balance, credit and withdraw. However, in order to provide the transactional behaviour, rather than to modify the current account directly (according to credit or withdraw) this task is delegated to an AccountResource object that is able, according to the transaction outcome, to set the account value either to its initial state or its final state.

The AccountResource object is in fact an object that implements the org.omg.CosTransactions.Resource, then able to participate to the transaction commitment. For this aim, the Account object has to register the AccountResource object as a participant, after having obtaining the reference of the org.omg.CosTransactions.Coordinator object , itself obtained via the org.omg.CosTransactions.Control object

package com.arjuna.demo.jta.remotebank;

import ....
public class AccountImpl extends AccountPOA
{
   float _balance;
   AccountResource accRes = null;
   public Account(String name )
   {
     _name = name;
     _balance = 0;
   }
   public float balance()
   {
     return getResource().balance();;
   }
   public void credit( float value )
   {
     getResource().credit( value );
   }
   public void debit( float value )
   {
     getResource().debit( value );
   }
   public AccountResource getResource()
   {
     try
     {
      if (accRes == null) {
        accRes = new AccountResource(this, _name) ;
        //The invocation on the ORB illustrates the // fact that the same ORB instance created // by the Bank Server is returned. ref = org.omg.CosTransactions.ResourceHelper. narrow(OA.getRootOA(ORB.getInstance("ServerSide")). corbaReference(accRes)); RecoveryCoordinator recoverycoordinator = OTSManager.get_current(). get_control().get_coordinator().register_resource(ref);
      }
    }
    catch (Exception e)
    {....}
      return accRes;
   }
   ...
}

To be considered as a org.omg.CosTransactions.Resource, the AccountResource class shall extends the class org.omg.CosTransactions.ResourcePOA generated by the CORBA IDL compiler. The AccountResource provides similar methods as the Account class (credit, withdraw and balance) with the appropriate methods to participate to the 2PC protocol. The following portion of code describes how the methods prepare, commit and rollback are implemented.



public class AccountResource  extends org.omg.CosTransactions.ResourcePOA
{
   public AccountResource(Account account, String name )
   {
     _name = name;
     _account = account;
     _initial_balance = account._balance;
     _current_balance = _initial_balance;
   }
   public float balance()
   {
     return _current_balance;
   }
   public void credit( float value )
   {
     _current_balance += value;
   }
   public void debit( float value )
   {
     _current_balance -= value;
   }
   public org.omg.CosTransactions.Vote prepare()
       throws org.omg.CosTransactions.HeuristicMixed,
       org.omg.CosTransactions.HeuristicHazard
       {
          if ( _initial_balance == _current_balance )
              return org.omg.CosTransactions.Vote.VoteReadOnly;
            if ( _current_balance < 0 )
                  return org.omg.CosTransactions.Vote.VoteRollback;
              return org.omg.CosTransactions.Vote.VoteCommit;
          }
   public void rollback()
     throws org.omg.CosTransactions.HeuristicCommit,
     org.omg.CosTransactions.HeuristicMixed,
     org.omg.CosTransactions.HeuristicHazard
   {
     //Nothing to do
   }
   public void commit()
     throws org.omg.CosTransactions.NotPrepared,
     org.omg.CosTransactions.HeuristicRollback,
     org.omg.CosTransactions.HeuristicMixed,
     org.omg.CosTransactions.HeuristicHazard
   {
      _account._balance = _current_balance;
   }
   public void commit_one_phase()
     throws org.omg.CosTransactions.HeuristicHazard
   {
     _account._balance = _current_balance;
   }
   ....
   private float _initial_balance;
   private float _current_balance;
   private Account _account;
   }
 

From an architectural point of view of JTS, the bank client is considered as an application program able to manage transactions either in a direct or indirect management mode, respectively with the interfaces org.omg.CosTransactions.TransactionFactory and org.omg.CosTransactions.Terminator or with the org.omg.CosTransactions.Current interface. Transactions created by the client in the Banking application are done in the indirect mode.

The following portion of code illustrates how a JTS transaction is started and terminated when the client asks to transfer money from one account to another. This also describes what are JBossTS packages that need to be used in order to obtain appropriate objects instances (such Current).

Note: The code below is a simplified view of the BankClient.java program. Only the transfer operation is illustrated; other operations manage transactions in the same way. (see for details the src/com/arjuna/demo/jts/localbank/BankClient.java)



package com.arjuna.demo.jta.localbank; import com.arjuna.ats.jts.OTSManager;
public class BankClient
{
   private Bank _bank;
    ....
   // This operation is used to make
   //a transfer from an account to another account
   private void makeTransfer()
   {
     System.out.print("Take money from : ");
     String name_supplier = input();
     System.out.print("Put money to : ");
     String name_consumer = input();
     System.out.print("Transfert amount : ");
     String amount = input();
     float famount = 0;
     try
      {
        famount = new Float( amount ).floatValue();
      }
     catch ( java.lang.Exception ex )
      {
        System.out.println("Invalid float number,
                     abort operation...");
        return;
      }
     try
      {
       //the following instruction asks a specific
       // JBossTS class to obtain a Current instance
       Current current = OTSManager.get_current();
       System.out.println("Beginning a User
                     transaction to get balance");
       current.begin();
       Account supplier = _bank.get_account( name_supplier );
       Account consumer = _bank.get_account( name_consumer );
       supplier.debit( famount );
       consumer.credit( famount );
       current.commit( );
      }
     catch (Exception e)
      {
       System.err.println("ERROR - "+e);
      }
   }
   

Since JTS is used invocations against an ORB are needed, such ORB and Object Adapter instantiation and initialisation. To ensure a better portability, the ORB Portability API provides a set of methods that can be used as described below.



public static void main( String [] args )
{
  try
   {  // Create an ORB instance myORB = ORB.getInstance("test"); //Obtain the Root POA myOA = OA.getRootOA(myORB); //Initialise the ORB myORB.initORB(args, null); //Initialise the POA myOA.initOA(); ....
   }
   catch(Exception e)
   { ....}
}

The Bank object has mainly two operations: creating an account, which is added in the account list, and returning an Account object. No transactional instruction is performed by the Bank object

package com.arjuna.demo.jta.localbank;

public class Bank {
   private java.util.Hashtable _accounts;
   public Bank()
   {
     _accounts = new java.util.Hashtable();
   }
   public Account create_account( String name )
   {
     Account acc = new Account(name);
     _accounts.put( name, acc );
      return acc;
   }
   public Account get_account(String name)
   throws NotExistingAccount
   {
     Account acc = ( Account ) _accounts.get( name );
     if ( acc == null )
       throw new NotExistingAccount("The Account
                      requested does not exist");
     return acc;
   }
}

The Account object provides mainly three methods balance, credit and withdraw. However, in order to provide the transactional behaviour, rather than to modify the current account directly (according to credit or withdraw) this task is delegated to an AccountResource object that is able, according to the transaction outcome, to set the account value either to its initial state or its final state.

The AccountResource object is in fact an object that implements the org.omg.CosTransactions.Resource, then able to participate to the transaction commitment. For this aim, the Account object has to register the AccountResource object as a participant, after having obtaining the reference of the org.omg.CosTransactions.Coordinator object , itself obtained via the org.omg.CosTransactions.Control object



package com.arjuna.demo.jta.localbank;
public class Account
{
 float _balance;
 AccountResource accRes = null;
 public Account(String name )
 {
   _name = name;
   _balance = 0;
 }
 public float balance()
 {
   return getResource().balance();;
 }
 public void credit( float value )
 {
   getResource().credit( value );
 }
 public void debit( float value )
 {
   getResource().debit( value );
 }
 public AccountResource getResource()
 {
   try
   {
    if (accRes == null) {
     accRes = new AccountResource(this, _name) ;
     Resource ref = org.omg.CosTransactions.ResourceHelper. narrow(OA.getRootOA(ORB.getInstance("test")).corbaReference(accRes));
     RecoveryCoordinator recoverycoordinator = OTSManager.get_current(). get_control().get_coordinator().register_resource(ref);
    }
  }
  catch (Exception e)
   {...}
   return accRes;
 }
  ...
}

To be considered as a org.omg.CosTransactions.Resource, the AccountResource class shall extends the class org.omg.CosTransactions.ResourcePOA generated by the CORBA IDL compiler. The AccountRessource provides similar methods as the Account class (credit, withdraw and balance) with the appropriate methods to participate to the 2PC protocol. The following portion of code describes how the methods prepare, commit and rollback are implemented.



public class AccountResource extends org.omg.CosTransactions.ResourcePOA
{
   public AccountResource(Account account, String name )
   {
     _name = name;
     _account = account;
     _initial_balance = account._balance;
     _current_balance = _initial_balance;
   }
   public float balance()
   {
     return _current_balance;
   }
   public void credit( float value )
   {
     _current_balance += value;
   }
   public void debit( float value )
   {
     _current_balance -= value;
   }
   public org.omg.CosTransactions.Vote prepare()
       throws org.omg.CosTransactions.HeuristicMixed,
       org.omg.CosTransactions.HeuristicHazard
    {
      if ( _initial_balance == _current_balance )
       return org.omg.CosTransactions.Vote.VoteReadOnly;
     if ( _current_balance < 0 )
       return org.omg.CosTransactions.Vote.VoteRollback;
     return org.omg.CosTransactions.Vote.VoteCommit;
    }
   public void rollback()
     throws org.omg.CosTransactions.HeuristicCommit,
     org.omg.CosTransactions.HeuristicMixed,
     org.omg.CosTransactions.HeuristicHazard
   {
     //Nothing to do
   }
   public void commit()
     throws org.omg.CosTransactions.NotPrepared,
     org.omg.CosTransactions.HeuristicRollback,
     org.omg.CosTransactions.HeuristicMixed,
     org.omg.CosTransactions.HeuristicHazard
   {
      _account._balance = _current_balance;
   }
   public void commit_one_phase()
     throws org.omg.CosTransactions.HeuristicHazard
   {
     _account._balance = _current_balance;
   }
   .....
   private float _initial_balance;
   private float _current_balance;
   private Account _account;
   }
 

ArjunaCore exploits object-oriented techniques to present programmers with a toolkit of Java classes from which application classes can inherit to obtain desired properties, such as persistence and concurrency control. These classes form a hierarchy, part of which is shown below.

Figure 1 - ArjunaCore class hierarchy.

Apart from specifying the scopes of transactions, and setting appropriate locks within objects, the application programmer does not have any other responsibilities: ArjunaCore and Transactional Objects for Java (TXOJ) guarantee that transactional objects will be registered with, and be driven by, the appropriate transactions, and crash recovery mechanisms are invoked automatically in the event of failures.

Making an object persistent and recoverable means that we shall be able to store its final state or to retrieve its initial state according to the final status of a transaction even in the presence of failures. ArjunaCore provides a set of techniques to save to and to retrieve from the Object Store states of objects. All objects made persistent with these ArjunaCore mechanisms are assigned unique identifiers (instances of the Uid class), when they are created, and this is to identify them within the object store. Due to common functionality for persistency and recovery required by several applications, objects are stored and retrieved from the object store using the same mechanism: the classes OutputObjectState and InputObjecState.

At the root of the class hierarchy, given in Figure 1, is the class StateManager. This class is responsible for object activation and deactivation and object recovery. The simplified signature of the class is:

Objects are assumed to be of three possible flavours. They may simply be recoverable, in which case StateManager will attempt to generate and maintain appropriate recovery information for the object. Such objects have lifetimes that do not exceed the application program that creates them. Objects may be recoverable and persistent, in which case the lifetime of the object is assumed to be greater than that of the creating or accessing application, so that in addition to maintaining recovery information StateManager will attempt to automatically load (unload) any existing persistent state for the object by calling the activate (deactivate) operation at appropriate times. Finally, objects may possess none of these capabilities, in which case no recovery information is ever kept nor is object activation/deactivation ever automatically attempted.

According to the its activation or deactivation a transactional object for Java move from a passive state to an active state and vice-versa. The fundamental life cycle of a persistent object in TXOJ is shown in Figure 2.

Figure 2 - The life cycle of a persistent object.

While deactivating and activating a transactional object for java, the operations save_state and restore_state are respectively invoked. These operations must be implemented by the programmer since StateManager cannot detect user level state changes. This gives the programmer the ability to decide which parts of an object’s state should be made persistent. For example, for a spreadsheet it may not be necessary to save all entries if some values can simply be recomputed. The save_state implementation for a class Example that has two integer member variables called A and B and one String member variable called C could simply be:

public boolean save_state(OutputObjectState o)

{
   if (!super.save_state(o))
      return false;
   try
   {
     o.packInt(A);
     o.packInt(B);
     o.packString(C));
   }
   catch (Exception e)
   {
     return false;
   }
   return true;
}

while, the corresponding restore_state implementation allowing to retrieve similar values is:

public boolean restore_state(InputObjectState o)

{
   if (!super.restore_state(o))
      return false;
   try
   {
     A = o.unpackInt();
     B = o.unpackInt();
     S = o.unpackString());
   }
   catch (Exception e)
   {
     return false;
   }
   return true;
}

Classes OutputObjectState and InputObjectState provide respectively operations to pack and unpack instances of standard Java data types. In other words for a standard Java data type, for instance Long or Short, there are corresponding methods to pack and unpack, i.e., packLong or packShort and unpackLong or unpackShort.

Note: it is necessary for all save_state and restore_state methods to call super.save_state and super.restore_state. This is to cater for improvements in the crash recovery mechanisms.

The concurrency controller is implemented by the class LockManager which provides sensible default behaviour while allowing the programmer to override it if deemed necessary by the particular semantics of the class being programmed. The primary programmer interface to the concurrency controller is via the setlock operation. By default, the runtime system enforces strict two-phase locking following a multiple reader, single writer policy on a per object basis. However, as shown in Figure 1, by inheriting from the Lock class it is possible for programmers to provide their own lock implementations with different lock conflict rules to enable type specific concurrency control.

Lock acquisition is (of necessity) under programmer control, since just as StateManager cannot determine if an operation modifies an object, LockManager cannot determine if an operation requires a read or write lock. Lock release, however, is under control of the system and requires no further intervention by the programmer. This ensures that the two-phase property can be correctly maintained.

public abstract class LockManager extends StateManager

{
   public LockResult setlock (Lock toSet, int retry, int timeout);
};

The LockManager class is primarily responsible for managing requests to set a lock on an object or to release a lock as appropriate. However, since it is derived from StateManager, it can also control when some of the inherited facilities are invoked. For example, LockManager assumes that the setting of a write lock implies that the invoking operation must be about to modify the object. This may in turn cause recovery information to be saved if the object is recoverable. In a similar fashion, successful lock acquisition causes activate to be invoked.

The code below shows how we may try to obtain a write lock on an object:

public class Example extends LockManager

{
   public boolean foobar ()
   {
     AtomicAction A = new AtomicAction;
     /*
      * The ArjunaCore AtomicAction class is here used to create * a transaction. Any interface provided by the JTA or * JTS interfaces that allow to create transactions can * be used in association with the Locking mechanisms * described in this trail.
     */
     boolean result = false;
     A.begin();
     if (setlock(new Lock(LockMode.WRITE), 0) == Lock.GRANTED)
     {
       /*
       * Do some work, and TXOJ will
       * guarantee ACID properties.
       */
       // automatically aborts if fails
       if (A.commit() == AtomicAction.COMMITTED)
       {
         result = true;
       }
     }
    else
       A.rollback();
    return result;
   }
}

The banking application consists of a Bank object that contains a list of Account object, which in turn have a String (name) and a float (the value) as member variables. It appears clearly that from the persistent point of view, an Account Object need to store its name and its current balance or value, while the Bank Object need to store the list of accounts that it manages.

Since a distributed version has been adopted to present the application with Transactional Object for Java, an IDL file named Bank.idl described below is needed. The difference with the Bank.idl presented in previous trails is the fact that the Bank interface inherits the CosTransactions::TransactionalObject interface. Since we consider now that a Bank object need to modify its list in a transactional, we consider now a Bank object as a CORBA transactional.

module arjuna {

   module demo {
     module jts {
      module txojbank {
        interface Account : CosTransactions::TransactionalObject
        {
          float balance();
          void credit( in float value );
          void debit( in float value );
        };
        exception NotExistingAccount
        { };
        interface Bank : CosTransactions::TransactionalObject
        {
          Account create_account( in string name );
          Account get_account( in string name )
            raises( NotExistingAccount );
        };
       };
      };
     };
   };

To take benefit from the persistency and locking mechanism provided by ArjunaCore, a user class can inherit from the appropriate class (StateManager for recovery, and LockManager for recovery and concurrency control). The AccountImpl class that implements the Account interface inherits the LockManager and implements the AccountOperations interface generated by the CORBA IDL compiler. Since multiple inheritance is not allowed in Java, inheriting the AccountPOA class, as made in simple jts remote version, in addition to the LockManager is not possible. That we use in this version a CORBA TIE mechanism to associate a servant to an CORBA object reference.

The Java interface definition of the AccountImpl class is given below:

public class AccountImpl extends LockManager implements AccountOperations

{
  float _balance;
  String _name;
  public AccountImpl(String name );
  public AccountImpl(Uid uid);
  public void finalize ();
  public float balance();
  public void credit( float value );
  public void debit( float value );
  public boolean save_state (OutputObjectState os, int ObjectType);
  public boolean restore_state (InputObjectState os, int ObjectType);
  public String type();
}
public void finalize ()

{
  super.terminate();
}
public String type ()

{
  return "/StateManager/LockManager/BankingAccounts";
}

To take benefit from the persistency and locking mechanism provided by ArjunaCore, a user class can inherit from the appropriate class (StateManager for recovery, and LockManager for recovery and concurrency control). The BankImpl class that implements the Bank interface inherits the LockManager and implements the BankOperations interface generated by the CORBA IDL compiler. Since multiple inheritance is not allowed in Java, inheriting the BankPOA class, as made in simple jts remote version, in addition to the LockManager is not possible. That we use in this version a CORBA TIE mechanism to associate a servant to an CORBA object reference.

The Java interface definition of the BankImpl class is given below:

public class BankImpl extends LockManager implements BankOperations

{
  public BankImpl(OA oa);
  public BankImpl(Uid uid, OA oa);
  public BankImpl(Uid uid);
  public Account create_account( String name );
  public Account get_account( String name );
  public boolean save_state (OutputObjectState os, int ObjectType);
  public boolean restore_state (InputObjectState os, int ObjectType);
  public String type();
  public static final int ACCOUNT_SIZE = 10;
  // ACCOUNT_SIZE is the maximum number of accounts
  private String [] accounts;
  private int numberOfAccounts;
  private ORB _orb;
  private OA _oa;
  private java.util.Hashtable _accounts; //The list of accounts
}

The role of the BankServer class is mainly to initialise the ORB and the Object Adapter and to create the default Bank object responsible to create banking accounts.

Globally the BankServer has the following structure.

JBossTS JTS supports the construction of both local and distributed transactional applications which access databases using the JDBC APIs. JDBC supports two-phase commit of transactions, and is similar to the XA X/Open standard. The JDBC support is found in the com.arjuna.ats.jdbc package.

The JBossTS JTS approach to incorporating JDBC connections within transactions is to provide transactional JDBC drivers through which all interactions occur. These drivers intercept all invocations and ensure that they are registered with, and driven by, appropriate transactions. There is a single type of transactional driver through which any JDBC driver can be driven; obviously if the database is not transactional then ACID properties cannot be guaranteed. This driver is com.arjuna.ats.jdbc.TransactionalDriver, which implements the java.sql.Driver interface.

The driver may be directly instantiated and used within an application. For example:

 TransactionalDriver arjunaJDBC2Driver = new TransactionalDriver(); 

It can be registered with the JDBC driver manager (java.sql.DriverManager) by adding them to the Java system properties. The jdbc.drivers property contains a list of driver class names, separated by colons, that are loaded by the JDBC driver manager when it is initialised, for instance:

jdbc.drivers=foo.bar.Driver:mydata.sql.Driver:bar.test.myDriver

On running an application, it is the DriverManager's responsibility to load all the drivers found in the system property jdbc.drivers. For example, this is where the driver for the Oracle database may be defined. When opening a connection to a database it is the DriverManager' s role to choose the most appropriate driver from the previously loaded drivers.

A program can also explicitly load JDBC drivers at any time. For example, the my.sql.Driver is loaded with the following statement:

Class.forName("my.sql.Driver"); 

Calling Class.forName() will automatically register the driver with the JDBC driver manager. It is also possible to explicitly create an instance of the JDBC driver using the registerDriver method of the DriverManager. This is the case for instance for the TransactionalDriver that can be registered as follow:

TransactionalDriver arjunaJDBC2Driver = new TransactionalDriver();

DriverManager.registerDriver(arjunaJDBC2Driver);

When you have loaded a driver, it is available for making a connection with a DBMS.

Once a driver is loaded and ready for a connection to be made, instances of a Connection class can be created using the getConnection method on the DriverManager, as follow:

Connection con = DriverManager.getConnection(url, username, password);

From its version 2.0, the JDBC API has introduced a new way to obtain instances of the Connection class. This is the case of the interfaces DataSource and XADataSource that creates transactional connections. When using a JDBC 2.0 driver, JBossTS will use the appropriate DataSource whenever a connection to the database is made. It will then obtain XAResources and register them with the transaction via the JTA interfaces. It is these XAResources which the transaction service will use when the transaction terminates in order to drive the database to either commit or rollback the changes made via the JDBC connection.

There are two ways in which the JBossTS JDBC 2.0 support can obtain XADataSources. These will be explained in the following sections. Note, for simplicity we shall assume that the JDBC 2.0 driver is instantiated directly by the application.

Database Type Property Name
Cloudscape 3.6 com.arjuna.ats.internal.jdbc.drivers.cloudscape_3_6
Sequelink 5.1 com.arjuna.ats.internal.jdbc.drivers.sequelink_5_1
Oracle 8.1.6 com.arjuna.ats.internal.jdbc.drivers.oracle_8_1_6
SQL Server 2000 com.arjuna.ats.internal.jdbc.drivers.sqlserver_2_2

Note on properties used by the com.arjuna.ats.jdbc.TransactionalDriver class

The following Banking application illustrates some methods that use the JDBC API. In this application, the way to create a jdbc connection is made via an XADataSource obtained with JNDI operations, es explained in the previous trail jdbc introduction The BankClient class instantiates an XADataSource and bind it to a jndi naming in order to be retrieved to create transactional connections. This portion of code illustrates how this made against oracle (tested on version 9i). A similar code could tested against an other database by providng the appropriate XADataSource implementation. Details of the BankClient class can be found in the file src/com/arjuna/demo/jta/jdbcbank/BankClient.java



  package com.arjuna.demo.jta.jdbcbank;
  import javax.naming.*;
  import java.util.Hashtable;
  import oracle.jdbc.xa.client.OracleXADataSource;
  import com.arjuna.ats.jdbc.common.jdbcPropertyManager;
  public class BankClient
  {
   .....
   public static void main(String[] args)
    {
      //Provide the apporopriate information to access the database
      for (int i = 0; i < args.length; i++)
      {
          if (args[i].compareTo("-host") == 0)
              host = args[+ 1]
          if (args[i].compareTo("-port") == 0)
                port = args[+ 1];
          if (args[i].compareTo("-username") == 0)
                user = args[+ 1];
          if (args[i].compareTo("-password") == 0)
                password = args[+ 1];
          if (args[i].compareTo("-dbName") == 0)
                dbName = args[+ 1];
          ....
      }
     try
     {
       // create DataSource
       OracleXADataSource ds = new OracleXADataSource();
       ds.setURL("jdbc:oracle:thin:@"+host+":"+port+":"+dbName);
       // now stick it into JNDI
       Hashtable env = new Hashtable();
       env.put (Context.INITIAL_CONTEXT_FACTORY,
       "com.sun.jndi.fscontext.RefFSContextFactory");
        env.put (Context.PROVIDER_URL, "file:/tmp/JNDI");
        InitialContext ctx = new InitialContext(env);
        ctx.rebind("jdbc/DB", ds);
     }
     catch (Exception ex)
     { }
     //Set the jndi information to be user by the Arjuna JDBC Property Manager
     jdbcPropertyManager.propertyManager.setProperty("Context.INITIAL_CONTEXT_FACTORY",
       "com.sun.jndi.fscontext.RefFSContextFactory");
     jdbcPropertyManager.propertyManager.setProperty("Context.PROVIDER_URL",
       "file:/tmp/JNDI");
     Bank bank = new Bank();
     BankClient client = new BankClient(bank);
   }
  

While the BankClient class is responsible to obtain information to access the database, tocreate the XADataSource and bind it to jndi, and also to get order from a user (create_account, debit, transfer, ..), the Bank class is resposnible to create jdbc connections to perform user's requests. The Bank class is illustarted below where. All methods are not illusrated here but have a similar behavior; they could be found in details in the src/com/arjuna/demo/jta/jdbcbank/Bank.java">Bank.java program. Note that for simplicity, much error checking code has been removed.

public Bank()

{
  try
  {
    DriverManager.registerDriver(new TransactionalDriver());
    dbProperties = new Properties();
    dbProperties.put(TransactionalDriver.userName, user);
    dbProperties.put(TransactionalDriver.password, password);
    arjunaJDBC2Driver = new TransactionalDriver(); //
    create_table();
  }
   catch (Exception e)
   {
   e.printStackTrace();
   System.exit(0);
   }
   _accounts = new java.util.Hashtable();
   reuseConnection = true;
   }
   public void create_account( String _name, float _value )
   {
    try
    {
      Connection conne = arjunaJDBC2Driver.connect("jdbc:arjuna:jdbc/DB", dbProperties);
      Statement stmtx = conne.createStatement(); // tx statement
      stmtx.executeUpdate
        ("INSERT INTO accounts (name, value)
          VALUES ('"+_name+"',"+_value+")");
    }
    catch (SQLException e)
    {
      e.printStackTrace();
    }
   }
  public float get_balance(String _name)
     throws NotExistingAccount
  {
    float theBalance = 0;
    try
    {
      Connection conne = arjunaJDBC2Driver.connect("jdbc:arjuna:jdbc/DB", dbProperties);
      Statement stmtx = conne.createStatement(); // tx statement
      ResultSet rs = stmtx.executeQuery
         ("SELECT value from accounts
           WHERE name    = '"+_name+"'");
      while (rs.next()) {
        theBalance = rs.getFloat("value");
      }
    }
    catch (SQLException e)
    {
      e.printStackTrace();
      throw new NotExistingAccount("The Account requested does not exist");
    }
    return theBalance;
  }
 ...
}

The JBossTS recovery manager provides support for recovering XAResources whether or not they are Serializable. XAResources that do implement the Serializable interface are handled without requiring additional programmer defined classes. For those XAResources that need to recover but which cannot implement Serializable, it is possible to provide a small class which is used to help recover them.

This example shows the JBossTS recovery manager recovering a Serializable XAResource and a non-Serializable XAResource.

When recovering from failures, JBossTS requires the ability to reconnect to the resource managers that were in use prior to the failures in order to resolve any outstanding transactions. In order to recreate those connections for non-Serializable XAResources it is necessary to provide implementations of the following JBossTS interface com.arjuna.ats.jta.recovery.XAResourceRecovery.

To inform the recovery system about each of the XAResourceRecovery instances, it is necessary to specify their class names through property variables in the jbossts-properties.xml file. Any property variable which starts with the name XAResourceRecovery will be assumed to represent one of these instances, and its value should be the class name.

When running XA transaction recovery it is necessary to tell JBossTS which types of Xid it can recover. Each Xid that JBossTS creates has a unique node identifier encoded within it and JBossTS will only recover transactions and states that match a specified node identifier. The node identifier to use should be provided to JBossTS via a property that starts with the name com.arjuna.ats.jta.xaRecoveryNode (multiple values may be provided). A value of * will force JBossTS to recover (and possibly rollback) all transactions irrespective of their node identifier and should be used with caution.

The recovery module for the non-Serializable XAResource must be deployed in order to provide support to recover the non-Serializable XAResource. If this step was missed out the Serializable XAResource would recover OK but JBossTS would have no knowledge of the non-Serializable XAResource and so it could not recover it. To register the non-Serializable XAResource XAResourceRecovery module, add an entry to the jbossts-properties.xml.

Under the element <properties depends="jts" name="jta">, add:

WARNING: Implementing a RecoveryModule and AbstractRecord is a very advanced feature of the transaction service. It should only be performed by users familiar with the all the concepts used in the JBoss Transactions product. Please see the ArjunaCore guide for more information about RecoveryModules and AbstractRecords.

The following sample gives an overview how the Recovery Manager invokes a module to recover from failure. This basic sample does not aim to present a complete process to recover from failure, but mainly to illustrate the way to implement a recovery module. More details can be found in "Failure Recovery Guide".

The application used here consists to create an atomic transaction, to register a participant within the created transaction and finally to terminate it either by commit or abort. A set of arguments are provided:
  • to decide committing or aborting the transaction,
  • to decide generating a crash during the commitment process.
The application consists of three programs
  • The code of the main class that control the application (src/com/arjuna/demo/recoverymodule/TestRecoveryModule.java">TestRecoveryModule.java), which consists to give the choice to either commit or abort the transaction and also to generate a crash.
  • The registered participant (src/com/arjuna/demo/recoverymodule/SimpleRecord.java">SimpleRecord.java) has the following behaviour:
    
    
                        - During the prepare phase, it writes a simple message - "I'm prepared" - on the disk such
                        The message is written in a well known file 
                        - During the commit phase, it writes another message - "I'm committed" - in the same file
                        used during prepare 
                        - If it receives an abort message, it removes from the disk the file used for prepare if any. 
                        - if a crash has been decided for the test, then it crashes during the commit phase - the file remains
                        with the message "I'm prepared".
  • A Recovery Module (src/com/arjuna/demo/recoverymodule/SimpleRecoveryModule.java">SimpleRecoveryModule.java) that consists to read the content of the file used to store the status of the participant, to determine that status and print a message indicating if a recovery action is needed or not.
Using the provided JBossTS Recovery Modules ensures that resources are correctly recovered. This sample illustrates how to define and register its own module. It's the responsibility of the module to re-create the appropriate objects using information retrieved from a log.

The failure recovery subsystem of JBossTS ensure that results of a transaction are applied consistently to all resources affected by the transaction, even if any of the application processes or the hardware hosting them crash or lose network connectivity. In the case of hardware crashes or network failures, the recovery does not take place until the system or network are restored, but the original application does not need to be restarted. Recovery is handled by the Recovery Manager process. For recover to take place, information about the transaction and the resources involved needs to survive the failure and be accessible afterward. This information is held in the ActionStore , which is part of the ObjectStore . If the ObjectStore is destroyed or modified, recovery may not be possible.

Until the recovery procedures are complete, resources affected by a transaction which was in progress at the time of the failure may be inaccessible. Database resources may report this as as tables or rows held by in-doubt transactions . For TXOJ resources, an attempt to activate the Transactional Object, such as when trying to get a lock, fails.

Recovery of XA resources accessed via JDBC is handled by the XARecoveryModule . This module includes both transaction-initiated and resource-initiated recovery.

Transaction-initiated recovery is automatic. The XARecoveryModule finds the JTA_ResourceRecord which needs recovery, using the two-pass mechanism described above. It then uses the normal recovery mechanisms to find the status of the transaction the resource was involved in, by running replay_completion on the RecoveryCoordinator for the transaction branch. Next, it creates or recreates the appropriate XAResource and issues commit or rollback on it as appropriate. The XAResource creation uses the same database name, username, password, and other information as the application.

Resource-initiated recovery must be specifically configured, by supplying the RecoveryManager with the appropriate information for it to interrogate all the XADataSources accessed by any JBossTS application. The access to each XADataSource is handled by a class that implements the com.arjuna.ats.jta.recovery.XAResourceRecovery interface. Instances of this class are dynamically loaded, as controlled by property JTAEnvironmentBean.xaResourceRecoveryInstances .

The XARecoveryModule uses the XAResourceRecovery implementation to get an XAResource to the target datasource. On each invocation of periodicWorkSecondPass , the recovery module issues an XAResource.recover request. This request returns a list of the transaction identifiers that are known to the datasource and are in an in-doubt state. The list of these in-doubt Xids is compared across multiple passes, using periodicWorkSecondPass-es . Any Xid that appears in both lists, and for which no JTA_ResourceRecord is found by the intervening transaction-initiated recovery, is assumed to belong to a transaction involved in a crash before any JTA_Resource_Record was written, and a rollback is issued for that transaction on the XAResource .

This double-scan mechanism is used because it is possible the Xid was obtained from the datasource just as the original application process was about to create the corresponding JTA_ResourceRecord. The interval between the scans should allow time for the record to be written unless the application crashes (and if it does, rollback is the right answer).

An XAResourceRecovery implementation class can contain all the information needed to perform recovery to a specific datasource. Alternatively, a single class can handle multiple datasources which have some similar features. The constructor of the implementation class must have an empty parameter list, because it is loaded dynamically. The interface includes an initialise method, which passes in further information as a string . The content of the string is taken from the property value that provides the class name. Everything after the first semi-colon is passed as the value of the string. The XAResourceRecovery implementation class determines how to use the string.

An XAResourceRecovery implementation class, com.arjuna.ats.internal.jdbc.recovery.BasicXARecovery , supports resource-initiated recovery for any XADataSource. For this class, the string received in method initialise is assumed to contain the number of connections to recover, and the name of the properties file containing the dynamic class name, the database username, the database password and the database connection URL. The following example is for an Oracle 8.1.6 database accessed via the Sequelink 5.1 driver:

XAConnectionRecoveryEmpay=com.arjuna.ats.internal.jdbc.recovery.BasicXARecovery;2;OraRecoveryInfo
      

This implementation is only meant as an example, because it relies upon usernames and passwords appearing in plain text properties files. You can create your own implementations of XAConnectionRecovery . See the javadocs and the example com.arjuna.ats.internal.jdbc.recovery.BasicXARecovery .

Example 8.3. XAConnectionRecovery implementation



/*
 * Copyright (C) 2000, 2001,
 *
 * Hewlett-Packard,
 * Arjuna Labs,
 * Newcastle upon Tyne,
 * Tyne and Wear,
 * UK.
 *
 */
package com.arjuna.ats.internal.jdbc.recovery;
import com.arjuna.ats.jdbc.TransactionalDriver;
import com.arjuna.ats.jdbc.common.jdbcPropertyManager;
import com.arjuna.ats.jdbc.logging.jdbcLogger;
import com.arjuna.ats.internal.jdbc.*;
import com.arjuna.ats.jta.recovery.XAConnectionRecovery;
import com.arjuna.ats.arjuna.common.*;
import com.arjuna.common.util.logging.*;
import java.sql.*;
import javax.sql.*;
import javax.transaction.*;
import javax.transaction.xa.*;
import java.util.*;
import java.lang.NumberFormatException;
/**
 * This class implements the XAConnectionRecovery interface for XAResources.
 * The parameter supplied in setParameters can contain arbitrary information
 * necessary to initialise the class once created. In this instance it contains
 * the name of the property file in which the db connection information is
 * specified, as well as the number of connections that this file contains
 * information on (separated by ;).
 *
 * IMPORTANT: this is only an *example* of the sorts of things an
 * XAConnectionRecovery implementor could do. This implementation uses
 * a property file which is assumed to contain sufficient information to
 * recreate connections used during the normal run of an application so that
 * we can perform recovery on them. It is not recommended that information such
 * as user name and password appear in such a raw text format as it opens up
 * a potential security hole.
 *
 * The db parameters specified in the property file are assumed to be
 * in the format:
 *
 * DB_x_DatabaseURL=
 * DB_x_DatabaseUser=
 * DB_x_DatabasePassword=
 * DB_x_DatabaseDynamicClass=
 *
 * DB_JNDI_x_DatabaseURL= 
 * DB_JNDI_x_DatabaseUser= 
 * DB_JNDI_x_DatabasePassword= 
 *
 * where x is the number of the connection information.
 *
 * @since JTS 2.1.
 */
public class BasicXARecovery implements XAConnectionRecovery
{    
    /*
     * Some XAConnectionRecovery implementations will do their startup work
     * here, and then do little or nothing in setDetails. Since this one needs
     * to know dynamic class name, the constructor does nothing.
     */
    public BasicXARecovery () throws SQLException
    {
        numberOfConnections = 1;
        connectionIndex = 0;
        props = null;
    }
    /**
     * The recovery module will have chopped off this class name already.
     * The parameter should specify a property file from which the url,
     * user name, password, etc. can be read.
     */
    public boolean initialise (String parameter) throws SQLException
    {
        int breakPosition = parameter.indexOf(BREAKCHARACTER);
        String fileName = parameter;
        if (breakPosition != -1)
            {
                fileName = parameter.substring(0, breakPosition -1);
                try
                    {
                        numberOfConnections = Integer.parseInt(parameter.substring(breakPosition +1));
                    }
                catch (NumberFormatException e)
                    {
                        //Produce a Warning Message
                        return false;
                    }
            }
        PropertyManager.addPropertiesFile(fileName);
        try
            {
                PropertyManager.loadProperties(true);
                props = PropertyManager.getProperties();
            }
        catch (Exception e)
            {
                //Produce a Warning Message 
                return false;
            }  
        return true;
    }    
    public synchronized XAConnection getConnection () throws SQLException
    {
        JDBC2RecoveryConnection conn = null;
        if (hasMoreConnections())
            {
                connectionIndex++;
                conn = getStandardConnection();
                if (conn == null)
                    conn = getJNDIConnection();
                if (conn == null)
                    //Produce a Warning message
                    }
        return conn;
    }
    public synchronized boolean hasMoreConnections ()
    {
        if (connectionIndex == numberOfConnections)
            return false;
        else
            return true;
    }
    private final JDBC2RecoveryConnection getStandardConnection () throws SQLException
    {
        String number = new String(""+connectionIndex);
        String url = new String(dbTag+number+urlTag);
        String password = new String(dbTag+number+passwordTag);
        String user = new String(dbTag+number+userTag);
        String dynamicClass = new String(dbTag+number+dynamicClassTag);
        Properties dbProperties = new Properties();
        String theUser = props.getProperty(user);
        String thePassword = props.getProperty(password);
        if (theUser != null)
            {
                dbProperties.put(ArjunaJDBC2Driver.userName, theUser);
                dbProperties.put(ArjunaJDBC2Driver.password, thePassword);
                String dc = props.getProperty(dynamicClass);
                if (dc != null)
                    dbProperties.put(ArjunaJDBC2Driver.dynamicClass, dc);
                return new JDBC2RecoveryConnection(url, dbProperties);
            }
        else
            return null;
    }
    private final JDBC2RecoveryConnection getJNDIConnection () throws SQLException
    {
        String number = new String(""+connectionIndex);
        String url = new String(dbTag+jndiTag+number+urlTag);
        String password = new String(dbTag+jndiTag+number+passwordTag);
        String user = new String(dbTag+jndiTag+number+userTag);
        Properties dbProperties = new Properties();
        String theUser = props.getProperty(user);
        String thePassword = props.getProperty(password);
        if (theUser != null)
            {
                dbProperties.put(ArjunaJDBC2Driver.userName, theUser);
                dbProperties.put(ArjunaJDBC2Driver.password, thePassword);    
                return new JDBC2RecoveryConnection(url, dbProperties);
            }
        else
            return null;
    }
    private int        numberOfConnections;
    private int        connectionIndex;
    private Properties props;   
    private static final String dbTag = "DB_";
    private static final String urlTag = "_DatabaseURL";
    private static final String passwordTag = "_DatabasePassword";
    private static final String userTag = "_DatabaseUser";
    private static final String dynamicClassTag = "_DatabaseDynamicClass";
    private static final String jndiTag = "JNDI_";
    /*
     * Example:
     *
     * DB2_DatabaseURL=jdbc\:arjuna\:sequelink\://qa02\:20001
     * DB2_DatabaseUser=tester2
     * DB2_DatabasePassword=tester
     * DB2_DatabaseDynamicClass=
     *      com.arjuna.ats.internal.jdbc.drivers.sequelink_5_1 
     *
     * DB_JNDI_DatabaseURL=jdbc\:arjuna\:jndi
     * DB_JNDI_DatabaseUser=tester1
     * DB_JNDI_DatabasePassword=tester
     * DB_JNDI_DatabaseName=empay
     * DB_JNDI_Host=qa02
     * DB_JNDI_Port=20000
     */
    private static final char BREAKCHARACTER = ';';  // delimiter for parameters
}

Multiple recovery domains and resource-initiated recovery

XAResource.recover returns the list of all transactions that are in-doubt with in the datasource. If multiple recovery domains are used with a single datasource, resource-initiated recovery sees transactions from other domains. Since it does not have a JTA_ResourceRecord available, it rolls back the transaction in the database, if the Xid appears in successive recover calls. To suppress resource-initiated recovery, do not supply an XAConnectionRecovery property, or confine it to one recovery domain.

Property OTS_ISSUE_RECOVERY_ROLLBACK controls whether the RecoveryManager explicitly issues a rollback request when replay_completion asks for the status of a transaction that is unknown. According to the presume-abort mechanism used by OTS and JTS, the transaction can be assumed to have rolled back, and this is the response that is returned to the Resource , including a subordinate coordinator, in this case. The Resource should then apply that result to the underlying resources. However, it is also legitimate for the superior to issue a rollback, if OTS_ISSUE_RECOVERY_ROLLBACK is set to YES .

The OTS transaction identification mechanism makes it possible for a transaction coordinator to hold a Resource reference that will never be usable. This can occur in two cases:

In the first case, the RecoveryManager for the Resource ObjectStore eventually reconstructs a new Resource (with a different CORBA object reference (IOR), and issues a replay_completion request containing the new Resource IOR. The RecoveryManager for the coordinator substitutes this in place of the original, useless one, and issues commit to the new reconstructed Resource . The Resource has to have been in a commit state, or there would be no transaction intention list. Until the replay_completion is received, the RecoveryManager tries to send commit to its Resource reference.–This will fail with a CORBA System Exception. Which exception depends on the ORB and other details.

In the second case, the Resource no longer exists. The RecoveryManager at the coordinator will never get through, and will receive System Exceptions forever.

The RecoveryManager cannot distinguish these two cases by any protocol mechanism. There is a perceptible cost in repeatedly attempting to send the commit to an inaccessible Resource . In particular, the timeouts involved will extend the recovery iteration time, and thus potentially leave resources inaccessible for longer.

To avoid this, the RecoveryManager only attempts to send commit to a Resource a limited number of times. After that, it considers the transaction assumed complete . It retains the information about the transaction, by changing the object type in the ActionStore , and if the Resource eventually does wake up and a replay_completion request is received, the RecoveryManager activates the transaction and issues the commit request to the new Resource IOR. The number of times the RecoveryManager attempts to issue commit as part of the periodic recovery is controlled by the property variable COMMITTED_TRANSACTION_RETRY_LIMIT , and defaults to 3 .

The operation of the recovery subsystem causes some entries to be made in the ObjectStore that are not removed in normal progress. The RecoveryManager has a facility for scanning for these and removing items that are very old. Scans and removals are performed by implementations of the >com.arjuna.ats.arjuna.recovery.ExpiryScanner . Implementations of this interface are loaded by giving the class names as the value of the property RecoveryEnvironmentBean.expiryScannerClassNames . The RecoveryManager calls the scan method on each loaded ExpiryScanner implementation at an interval determined by the property RecoveryEnvironmentBean.expiryScanInterval . This value is given in hours, and defaults to 12 . A property value of 0 disables any expiry scanning. If the value as supplied is positive, the first scan is performed when RecoveryManager starts. If the value is negative, the first scan is delayed until after the first interval, using the absolute value.

There are two kinds of item that are scanned for expiry:

Contact items

One contact item is created by every application process that uses JBossTS. They contain the information that the RecoveryManager uses to determine if the process that initiated the transaction is still alive, and what the transaction status is. The expiry time for these is set by the property RecoveryEnvironmentBean.transactionStatusManagerExpiryTime , which is expressed in hours. The default is 12 , and 0 suppresses the expiration. This is the interval after which a process that cannot be contacted is considered to be dead. It should be long enough to avoid accidentally removing valid entries due to short-lived transient errors such as network downtime.

Assumed complete transactions

The expiry time is counted from when the transactions were assumed to be complete. A replay_completion request resets the clock. The risk with removing assumed complete transactions it that a prolonged communication outage means that a remote Resource cannot connect to the RecoveryManager for the parent transaction. If the assumed complete transaction entry is expired before the communications are recovered, the eventual replay_completion will find no information and the Resource will be rolled back, although the transaction committed. Consequently, the expiry time for assumed complete transactions should be set to a value that exceeds any anticipated network outage. The parameter is ASSUMED_COMPLETE_EXPIRY_TIME . It is expressed in hours, with 240 being the default, and 0 meaning never to expire.


There are two ExpiryScannner s for the assumed complete transactions, because there are different types in the ActionStore.

Because of differences between ORBs, and errors in certain ORBs, the idl available with JBossTS may differ from that shown below. You should always inspect the idl files prior to implementation to determine what, if any, differences exist.

Example A.1. CosTransactions.idl

#ifndef COSTRANSACTIONS_IDL_

#define COSTRANSACTIONS_IDL_
module CosTransactions
{
    enum Status { StatusActive, StatusMarkedRollback, StatusPrepared,
        StatusCommitted, StatusRolledback, StatusUnknown,
           StatusPreparing, StatusCommitting, StatusRollingBack,
        StatusNoTransaction };
    enum Vote { VoteCommit, VoteRollback, VoteReadOnly };
    // Standard exceptions - some Orb supports them
exception TransactionRequired {};
exception TransactionRolledBack {};
exception InvalidTransaction {};
    // Heuristic exceptions
exception HeuristicRollback {};
       exception HeuristicCommit {};
       exception HeuristicMixed {};
       exception HeuristicHazard {};
    // Exception from ORB
exception WrongTransaction {};
    // Other transaction related exceptions
exception SubtransactionsUnavailable {};
exception NotSubtransaction {};
exception Inactive {};
exception NotPrepared {};
exception NoTransaction {};
exception InvalidControl {};
exception Unavailable {};
exception SynchronizationUnavailable {};
    // Forward references for later interfaces
interface Control;
interface Terminator;
interface Coordinator;
interface Resource;
interface RecoveryCoordinator;
interface SubtransactionAwareResource;
interface TransactionFactory;
interface TransactionalObject;
interface Current;
interface Synchronization;
    // Formally part of CosTSInteroperation
struct otid_t
{
    long formatID;
    long bequal_length;
    sequence <octet> tid;
};
struct TransIdentity
       {
           Coordinator coord;
       Terminator term;
           otid_t otid;
       };
struct PropagationContext
      {
       unsigned long timeout;
          TransIdentity currentTransaction;
       sequence <TransIdentity> parents;
       any implementation_specific_data;
      };
      interface Current : CORBA::Current
      {
       void begin () raises (SubtransactionsUnavailable);
       void commit (in boolean report_heuristics) raises (NoTransaction, HeuristicMixed, HeuristicHazard, TransactionRolledBack);
       void rollback () raises (NoTransaction);
       void rollback_only () raises (NoTransaction);
       Status get_status ();
       string get_transaction_name ();
       void set_timeout (in unsigned long seconds);
       Control get_control ();
       Control suspend ();
       void resume (in Control which) raises (InvalidControl);
      };
interface TransactionFactory
      {
       Control create (in unsigned long time_out);
           Control recreate (in PropagationContext ctx);
      };
interface Control
      {
       Terminator get_terminator () raises (Unavailable);
       Coordinator get_coordinator () raises (Unavailable);
      };
interface Terminator
      {
       void commit (in boolean report_heuristics) raises (HeuristicMixed, HeuristicHazard, TransactionRolledBack);
       void rollback ();
      };
      interface Coordinator
      {
       Status get_status ();
       Status get_parent_status ();
       Status get_top_level_status ();
       boolean is_same_transaction (in Coordinator tc);
       boolean is_related_transaction (in Coordinator tc);
       boolean is_ancestor_transaction (in Coordinator tc);
       boolean is_descendant_transaction (in Coordinator tc);
       boolean is_top_level_transaction ();
           unsigned long hash_transaction ();
       unsigned long hash_top_level_tran ();
       RecoveryCoordinator register_resource (in Resource r) raises (Inactive);
       void register_synchronization (in Synchronization sync) raises (Inactive, SynchronizationUnavailable);
       void register_subtran_aware (in SubtransactionAwareResource r) raises (Inactive, NotSubtransaction);
       void rollback_only () raises (Inactive);
       string get_transaction_name ();
       Control create_subtransaction () raises (SubtransactionsUnavailable, Inactive);
       PropagationContext get_txcontext () raises (Unavailable);
      };
      interface RecoveryCoordinator
      {
       Status replay_completion (in Resource r) raises (NotPrepared);
      };
interface Resource
       {
       Vote prepare () raises (HeuristicMixed, HeuristicHazard);
       void rollback () raises (HeuristicCommit, HeuristicMixed, HeuristicHazard);
       void commit () raises (NotPrepared, HeuristicRollback, HeuristicMixed, HeuristicHazard);
       void commit_one_phase () raises (HeuristicHazard);
       void forget ();
      };
interface SubtransactionAwareResource : Resource
      {
       void commit_subtransaction (in Coordinator parent);
       void rollback_subtransaction ();
      };
interface TransactionalObject
      {
      };   
interface Synchronization : TransactionalObject
      {
       void before_completion ();
       void after_completion (in Status s);
      };
};
#endif

Example A.2. ArjunaOTS.IDL

#ifndef ARJUNAOTS_IDL_

#define ARJUNAOTS_IDL_
#include <idl/CosTransactions.idl>
module ArjunaOTS
{
    exception ActiveTransaction {};
    exception BadControl {};
    exception Destroyed {};
    exception ActiveThreads {};
    exception InterpositionFailed {};
    interface UidCoordinator : CosTransactions::Coordinator
    {
   readonly attribute string uid;
   readonly attribute string topLevelUid;
    };
    interface ActionControl : CosTransactions::Control
    {
        CosTransactions::Control getParentControl ()
                                                raises (CosTransactions::Unavailable,
                                                  CosTransactions::NotSubtransaction);
        void destroy () raises (ActiveTransaction, ActiveThreads, BadControl,
                                Destroyed);
    };
    interface ArjunaSubtranAwareResource : 
                                     CosTransactions::SubtransactionAwareResource
    {
   CosTransactions::Vote prepare_subtransaction ();
    };
    interface ArjunaTransaction : UidCoordinator, CosTransactions::Terminator
    {
    };
    interface OTSAbstractRecord : ArjunaSubtranAwareResource
    {
        readonly attribute long typeId;
        readonly attribute string uid;
        boolean propagateOnAbort ();
        boolean propagateOnCommit ();
        boolean saveRecord ();
        void merge (in OTSAbstractRecord record);
        void alter (in OTSAbstractRecord record);
        boolean shouldAdd (in OTSAbstractRecord record);
        boolean shouldAlter (in OTSAbstractRecord record);
        boolean shouldMerge (in OTSAbstractRecord record);
        boolean shouldReplace (in OTSAbstractRecord record);
    };
};

Revision History
Revision 1Wed Nov 17 2010Misty Stanley-Jones
Initial conversion to Docbook
Revision 2Thu Apr 14 2011Tom Jenkinson
Moved some content to main developers guide and added tools information