Copyright © The Narayana Authors

SPDX short identifier: Apache-2.0

Introduction

The Transactions Overview Guide contains information on how to use Narayana; to develop applications that use transaction technology to manage business processes. This document covers functionality that is available within both the Narayana community version and is also available within the Red Hat JBoss EAP product.

Document Conventions

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.

Typographic Conventions

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:

To see the contents of the file my_next_bestselling_novel in your current working directory, enter the cat my_next_bestselling_novel command at the shell prompt and press Enter to execute the command.

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:

Press `Enter` to execute the command.

Press
// <keycombo>
//   <keycap>Ctrl</keycap>
//   <keycap>Alt</keycap>
//   <keycap>F2</keycap>
// </keycombo>
 to switch to the first virtual terminal.
Press
// <keycombo>
//   <keycap>Ctrl</keycap>
//   <keycap>Alt</keycap>
//   <keycap>F1</keycap>
// </keycombo>
 to return to your X-Windows session.

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:

File-related classes include filesystem for file systems, file for files, and dir for directories. Each class has its own associated set of permissions.

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:

Choose Preferences > Mouse from the main menu bar to launch Mouse Preferences. In the Buttons tab, click the Left-handed mouse check box and click Close to switch the primary mouse button from the left to the right (making the mouse suitable for use in the left hand).

To insert a special character into a gedit file, choose Accessories > Character Map from the main menu bar. Next, choose Find from the Character Map menu bar, type the name of the character in the Search field and click Next. The character you sought will be highlighted in the Character Table. Double-click this highlighted character to place it in the Text to copy field and then click the Copy button. Now switch back to your document and choose Paste from the gedit menu bar.

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:

To connect to a remote machine using ssh, type ssh username@domain.name at a shell prompt. If the remote machine is example.com and your username on that machine is john, type ssh john@example.com.

The mount -o remount file-system command remounts the named file system. For example, to remount the /home file system, the command is mount -o remount /home.

To see the version of a currently installed package, use the rpm -q package command. It will return a result as follows: package-version-release.

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:

This documentation uses Asciidoc.

Pull-quote Conventions

Terminal output and source code listings are set off visually from the surrounding text.

Output sent to a terminal is set in mono-spaced roman and presented thus:

books        Desktop   documentation  drafts  mss    photos   stuff  svn
books_tests  Desktop1  downloads      images  notes  scripts  svgs

Source-code listings are also set in mono-spaced roman but add syntax highlighting as follows:

package org.jboss.book.jca.ex1;

import javax.naming.InitialContext;

public class ExClient {
   public static void main(String args[]) throws Exception {
       InitialContext iniCtx = new InitialContext();
       Object         ref    = iniCtx.lookup("EchoBean");
       EchoHome       home   = (EchoHome) ref;
       Echo           echo   = home.create();

       System.out.println("Created Echo");

       System.out.println("Echo.echo('Hello') = " + echo.echo("Hello"));
   }
}

Notes and Warnings

Finally, we use three visual styles to draw attention to information that might otherwise be overlooked.

Note

Notes are tips, shortcuts or alternative approaches to the task at hand. Ignoring a note should have no negative consequences, but you might miss out on a trick that makes your life easier.

Important

Important boxes detail things that are easily missed: configuration changes that only apply to the current session, or services that need restarting before an update will apply. Ignoring a box labeled 'Important' will not cause data loss but may cause irritation and frustration.

Warning

Warnings should not be ignored. Ignoring warnings will most likely cause data loss.

We Need Feedback!

Please feel free to raise any issues you find with this document in our issue tracking system

1. Transactions Overview

1.1. What is a transaction?

This chapter deals with the theory of transactional services. If you are familiar with these principles, consider this chapter a reference.

Consider the following situation: a user wishes to purchase access to an on-line newspaper and requires to pay for this access from an account maintained by an on-line bank. Once the newspaper site has received the user’s credit from the bank, they will deliver an electronic token to the user granting access to their site. Ideally the user would like the debiting of the account, and delivery of the token to be "all or nothing" (atomic). However, hardware and software failures could prevent either event from occurring, and leave the system in an indeterminate state.

  • Atomic transactions (transactions) possess an "all-or-nothing" property, and are a well-known technique for guaranteeing application consistency in the presence of failures. Transactions possess the following ACID properties:

  • Atomicity: The transaction completes successfully (commits) or if it fails (aborts) all of its effects are undone (rolled back).

  • Consistency: Transactions produce consistent results and preserve application specific invariants.

  • Isolation: Intermediate states produced while a transaction is executing are not visible to others. Furthermore transactions appear to execute serially, even if they are actually executed concurrently.

  • Durability: The effects of a committed transaction are never lost (except by a catastrophic failure).

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.

Transactions have emerged as the dominant paradigm for coordinating interactions between parties in a (distributed) system, and in particular to manage applications that require concurrent access to shared data. A classic transaction is a unit of work that either completely succeeds, or fails with all partially completed work being undone. When a transaction is committed, all changes made by the associated requests are made durable, normally by committing the results of the work to a database. If a transaction should fail and is rolled back, all changes made by the associated work are undone. Transactions in distributed systems typically require the use of a transaction manager that is responsible for coordinating all of the participants that are part of the transaction.

The main components involved in using and defining transactional applications are:
  • A Transaction Service: The Transaction Service captures the model of the underlying transaction protocol and coordinates parties affiliated with the transaction according to that model.

  • A Transaction API: Provides an interface for transaction demarcation and the registration of participants.

  • A Participant: The entity that cooperates with the transaction service on behalf of its associated business logic.

  • The Context: Captures the necessary details of the transaction such that participants can enlist within its scope.

1.2. The Coordinator

Associated with every transaction is a coordinator, which is responsible for governing the outcome of the transaction. The coordinator may be implemented as a separate service or may be co-located with the user for improved performance. Each coordinator is created by the transaction manager service, which is in effect a factory for those coordinators.

A coordinator communicates with enrolled participants to inform them of the desired termination requirements, i.e., whether they should accept (e.g., confirm) or reject (e.g., cancel) the work done within the scope of the given transaction. For example, whether to purchase the (provisionally reserved) flight tickets for the user or to release them. An application/client may wish to terminate a transaction in a number of different ways (e.g., confirm or cancel). However, although the coordinator will attempt to terminate in a manner consistent with that desired by the client, it is ultimately the interactions between the coordinator and the participants that will determine the actual final outcome.

A transaction manager is typically responsible for managing coordinators for many transactions. The initiator of the transaction (e.g., the client) communicates with a transaction manager and asks it to start a new transaction and associate a coordinator with the transaction. Once created, the context can be propagated to Web services in order for them to associate their work with the transaction.

1.3. The Transaction Context

In order for a transaction to span a number of services, certain information has to be shared between those services in order to propagate information about the transaction. This information is known as the Context. The context is often automatically propagated and processed by transaction-aware components of an application:

Contents of a Context
Transaction Identifier

Guarantees global uniqueness for an individual transaction.

Transaction Coordinator Location

The endpoint address participants contact to enroll.

transactions overview fig web services context flow
Figure 1. Context Flow

1.4. Participants

The coordinator cannot know the details of how every transactional service is implemented; in fact it is not necessary for it to do so in order to negotiate a transactional outcome. It treats each service taking part in a transaction as a participant and communicates with it according to some predefined participant coordination models appropriate to the type of transaction. When a service begins performing work within the scope of a transaction it enrolls itself with the coordinator as a participant, specifying the participant model it wishes to follow. So, the term participant merely refers a transactional service enrolled in a specific transaction using a specific participant model.

1.5. Commit protocol

A two-phase commit protocol is required to guarantee that all of the action participants either commit or abort any changes made. See Two-Phase Commit Overview which illustrates the main aspects of the commit protocol: during phase 1, the action coordinator, C, attempts to communicate with all of the action participants, A and B, to determine whether they will commit or abort. An abort reply from any participant acts as a veto, causing the entire action to abort. Based upon these (lack of) responses, the coordinator arrives at the decision of whether to commit or abort the action. If the action will commit, the coordinator records this decision on stable storage, and the protocol enters phase 2, where the coordinator forces the participants to carry out the decision. The coordinator also informs the participants if the action aborts.

When each participant receives the coordinator’s phase 1 message, they record sufficient information on stable storage to either commit or abort changes made during the action. After returning the phase 1 response, each participant who returned a commit response must remain blocked until it has received the coordinator’s phase 2 message. Until they receive this message, these resources are unavailable for use by other actions. If the coordinator fails before delivery of this message, these resources remain blocked. However, if crashed machines eventually recover, crash recovery mechanisms can be employed to unblock the protocol and terminate the action.

transactions overview fig two phase commit overview
Figure 2. Two-Phase Commit Overview
  • A transaction is started, and some work is performed.

  • Once the work is finished, the two-phase commit begins.

  • The coordinator (transaction manager) of the transaction asks each resource taking part in the transaction whether it is prepared to commit.

  • If all resources respond positively, the coordinator instructs the resources to make all work performed durable (usually committed to a database).

  • If not, all work performed is rolled back (undone) such that the underlying data structures are in their original states.

During two-phase commit transactions, coordinators and resources keep track of activity in non-volatile data stores so that they can recover in the case of a failure.

1.6. The Synchronization Protocol

Besides the two-phase commit protocol, traditional transaction processing systems employ an additional protocol, often referred to as the synchronization protocol. With the original ACID properties, Durability is important when state changes need to be available despite failures. Applications interact with a persistence store of some kind, such as a database, and this interaction can impose a significant overhead, because disk access is much slower to access than main computer memory.

One solution to the problem disk access time is to cache the state in main memory and only operate on the cache for the duration of a transaction. Unfortunately, this solution needs a way to flush the state back to the persistent store before the transaction terminates, or risk losing the full ACID properties. This is what the synchronization protocol does, with Synchronization Participants.

Synchronizations are informed that a transaction is about to commit. At that point, they can flush cached state, which might be used to improve performance of an application, to a durable representation prior to the transaction committing. The synchronizations are then informed about when the transaction completes and its completion state.

Procedure: The "Four Phase Protocol" Created By Synchronizations

Synchronizations essentially turn the two-phase commit protocol into a four-phase protocol:

  1. Step 1

    Before the transaction starts the two-phase commit, all registered Synchronizations are informed. Any failure at this point will cause the transaction to roll back.

  2. Step 2 and 3

    The coordinator then conducts the normal two-phase commit protocol.

  3. Step 4

    Once the transaction has terminated, all registered Synchronizations are informed. However, this is a courtesy invocation because any failures at this stage are ignored: the transaction has terminated so there’s nothing to affect.

The synchronization protocol does not have the same failure requirements as the traditional two-phase commit protocol. For example, Synchronization participants do not need the ability to recover in the event of failures, because any failure before the two-phase commit protocol completes cause the transaction to roll back, and failures after it completes have no effect on the data which the Synchronization participants are responsible for.

1.7. Optimizations to the Protocol

There are several variants to the standard two-phase commit protocol that are worth knowing about, because they can have an impact on performance and failure recovery. Variants to the Two-Phase Commit Protocol gives more information about each one.

Table 1. Variants to the Two-Phase Commit Protocol
Variant Description

Presumed Abort

If a transaction is going to roll back, the coordinator may record this information locally and tell all enlisted participants. Failure to contact a participant has no effect on the transaction outcome. The coordinator is informing participants only as a courtesy. Once all participants have been contacted, the information about the transaction can be removed. If a subsequent request for the status of the transaction occurs, no information will be available and the requester can assume that the transaction has aborted. This optimization has the benefit that no information about participants need be made persistent until the transaction has progressed to the end of the prepare phase and decided to commit, since any failure prior to this point is assumed to be an abort of the transaction.

One-Phase

If only a single participant is involved in the transaction, the coordinator does not need to drive it through the prepare phase. Thus, the participant is told to commit, and the coordinator does not need to record information about the decision, since the outcome of the transaction is the responsibility of the participant.

Read-Only

When a participant is asked to prepare, it can indicate to the coordinator that no information or data that it controls has been modified during the transaction. Such a participant does not need to be informed about the outcome of the transaction since the fate of the participant has no affect on the transaction. Therefore, a read-only participant can be omitted from the second phase of the commit protocol.

1.8. Non-Atomic Transactions and Heuristic Outcomes

In order to guarantee atomicity, the two-phase commit protocol is blocking. As a result of failures, participants may remain blocked for an indefinite period of time, even if failure recovery mechanisms exist. Some applications and participants cannot tolerate this blocking.

To break this blocking nature, participants that are past the prepare phase are allowed to make autonomous decisions about whether to commit or rollback. Such a participant must record its decision, so that it can complete the original transaction if it eventually gets a request to do so. If the coordinator eventually informs the participant of the transaction outcome, and it is the same as the choice the participant made, no conflict exists. If the decisions of the participant and coordinator are different, the situation is referred to as a non-atomic outcome, and more specifically as a heuristic outcome.

Resolving and reporting heuristic outcomes to the application is usually the domain of complex, manually driven system administration tools, because attempting an automatic resolution requires semantic information about the nature of participants involved in the transactions.

Precisely when a participant makes a heuristic decision depends on the specific implementation. Likewise, the choice the participant makes about whether to commit or to roll back depends upon the implementation, and possibly the application and the environment in which it finds itself. The possible heuristic outcomes are discussed in Heuristic Outcomes .

Table 2. Heuristic Outcomes
Outcome Description

Heuristic Rollback

The commit operation was not able to commit the resources but all of the participants were able to be rolled back and so an atomic outcome was still achieved.

Heuristic Commit

An attempted rollback operation failed because all of the participants unilaterally committed. One situation where this might happen is if the coordinator is able to successfully prepare the transaction, but then decides to roll it back because its transaction log could not be updated. While the coordinator is making its decision, the participants decides to commit.

Heuristic Mixed

Some participants committed, while others were rolled back.

Heuristic Hazard

The disposition of some of the updates is unknown. For those which are known, they have either all been committed or all rolled back.

Heuristic decisions should be used with care and only in exceptional circumstances, since the decision may possibly differ from that determined by the transaction service. This type of difference can lead to a loss of integrity in the system. Try to avoid needing to perform resolution of heuristics, either by working with services and participants that do not cause heuristics, or by using a transaction service that provides assistance in the resolution process.

1.9. Interposition

Interposition is a scoping mechanism which allows coordination of a transaction to be delegated across a hierarchy of coordinators. See Interpositions for a graphical representation of this concept.

transactions overview fig interpositions
Figure 3. Interpositions

Interposition is particularly useful for Web Services transactions, as a way of limiting the amount of network traffic required for coordination. For example, if communications between the top-level coordinator and a web service are slow because of network traffic or distance, the web service might benefit from executing in a subordinate transaction which employs a local coordinator service. In Interpositions ,to prepare, the top-level coordinator only needs to send one prepare message to the subordinate coordinator, and receive one prepared or aborted reply. The subordinate coordinator forwards a prepare locally to each participant and combines the results to decide whether to send a single prepared or aborted reply.

1.10. A New Transaction Protocol

Many component technologies offer mechanisms for coordinating ACID transactions based on two-phase commit semantics. Some of these are CORBA/OTS, JTS/JTA, and MTS/MSDTC. ACID transactions are not suitable for all Web Services transactions, as explained in Reasons ACID is Not Suitable for Web Services.

Reasons ACID is Not Suitable for Web Services
  • Classic ACID transactions assume that an organization that develops and deploys applications owns the entire infrastructure for the applications. This infrastructure has traditionally taken the form of an Intranet. Ownership implies that transactions operate in a trusted and predictable manner. To assure ACIDity, potentially long-lived locks can be kept on underlying data structures during two-phase commit. Resources can be used for any period of time and released when the transaction is complete.

    In Web Services, these assumptions are no longer valid. One obvious reason is that the owners of data exposed through a Web service refuse to allow their data to be locked for extended periods, since allowing such locks invites denial-of-service attacks.

  • All application infrastructures are generally owned by a single party. Systems using classical ACID transactions normally assume that participants in a transaction will obey the directives of the transaction manager and only infrequently make unilateral decisions which harm other participants in a transaction.

    Web Services participating in a transaction can effectively decide to resign from the transaction at any time, and the consumer of the service generally has little in the way of quality of service guarantees to prevent this.

1.10.1. Addressing the Problems of Transactioning in Loosely Coupled Systems

Though extended transaction models which relax the ACID properties have been proposed over the years, standards such as OASIS WS-TX provide a new transaction protocol to implement these concepts for the Web services architecture. The are designed to accommodate four underlying requirements inherent in any loosely coupled architecture like Web services:.

Requirements of Web Services
  • Ability to handle multiple successful outcomes to a transaction, and to involve operations whose effects may not be isolated or durable.

  • Coordination of autonomous parties whose relationships are governed by contracts, rather than the dictates of a central design authority.

  • Discontinuous service, where parties are expected to suffer outages during their lifetimes, and coordinated work must be able to survive such outages.

  • Interoperation using XML over multiple communication protocols. XTS uses SOAP encoding carried over HTTP.

2. Failure Recovery

2.1. Architecture of the Recovery Manager

2.1.1. Crash Recovery Overview

The main architectural components within Crash Recovery are illustrated in the diagram below:

failure recovery fig1 crashrecoveryarchitecture
Figure 4. Recovery Manager Architecture

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.

The following sections describe the architectural components in more detail.

2.1.2. Recovery Manager

On initialisation, 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.

The Recovery Manager is not specifically tied to an Object Request Broker or ORB. Hence, the OTS recovery protocol is not implicitly enabled. To enable such protocol, we use the concept of recovery activator, defined with the interface RecoveryActivator, which is used to instantiate a recovery class related to the underlying communication 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:

<entry key="RecoveryEnvironmentBean.recoveryActivators">
    list_of_class_names
<entry>

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

<entry key="RecoveryEnvironmentBean.recoveryActivators">
    com.arjuna.ats.internal.jts.orbspecific.recovery.RecoveryEnablement
<entry>

When loaded all RecoveryActivator instances provide the method startRCservice invoked by the Recovery Manager and used to create the appropriate Recovery Component able to receive recovery requests according to a particular transaction protocol. For instance the RecoveryCoordinator defined by the OTS protocol.

Each recovery module is used to recover a different type of transaction/resource, however each recovery module inherits the same basic behavior.

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:

<entry key="RecoveryEnvironmentBean.recoveryExtenstions">
    list_of_class_names
<entry>

The backoff period and recovery period are set using the following properties:

<entry key="RecoveryEnvironmentBean.recoveryBackoffPeriod">
<entry key="RecoveryEnvironmentBean.periodicRecoveryPeriod">

The following java classes are used to implement the Recovery Manager:

  • package com.arjuna.ats.arjuna.recovery:

    RecoveryManager – The daemon process that starts up by instantiating an instance of the RecoveryManagerImple class.

    RecoveryEnvironment - Properties used by the recovery manager.

    RecoveryConfiguration - Specifies the name of the Recovery Manager property file.(ie RecoveryManager-properties.xml)

  • package com.arjuna.ats.internal.ts.arjuna.recovery:

    RecoveryManagerImple - Creates and starts instances of the RecActivatorLoader, the PeriodicRecovery thread and the ExpiryEntryMonitor thread.

    RecActivatorLoader - Dynamically loads in the RecoveryActivator specified in the Recovery Manager property file. Each RecoveryActicator is specified as a recovery extension in the properties file

    PeriodicRecovery - Thread which loads each recovery module, then calls the first pass method for each module, applies the backoff period timeout, calls the second pass method for each module and applies the recovery period timeout.

    RecoveryClassLoader - Dynamically loads in the recovery modules specified in the Recovery Manager property file. Each module is specified as a recovery extension in the properties file (e.g., com.arjuna.ats.arjuna.recovery.recoveryExtension1=com.arjuna.ats.internal.ts.arjuna.recovery.AtomicActionRecoveryModule).

By default, the recovery manager listens on the first available port on a given machine. If you wish to control the port number that it uses, you can specify this using the com.arjuna.ats.arjuna.recovery.recoveryPort attribute.

Managing recovery directly

As already mentioned, recovery typically happens at periodic intervals. If you require to drive recovery directly, then there are two options, depending upon how the RecoveryManager has been created.

Separate Recovery Manager

You can either use the com.arjuna.ats.arjuna.tools.RecoveryMonitor program to send a message to the Recovery Manager instructing it to perform recovery, or you can create an instance of the com.arjuna.ats.arjuna.recovery.RecoveryDriver class to do likewise. There are two types of recovery scan available:

  1. ASYNC_SCAN: here a message is sent to the RecoveryManager to instruct it to perform recovery, but the response returns before recovery has completed.

  2. SYNC: here a message is sent to the RecoveryManager to instruct it to perform recovery, and the response occurs only when recovery has completed.

    When using the RecoveryMonitor program there is a -verbose option which will trigger a recovery scan and report any warnings or errors emitted from the XA recovery module by printing "ERROR" (otherwise "DONE" is printed). If the monitor is invoked programmatically, for example RecoveryMonitor.main(new String [] {"-verbose", "-port", …​});, then the status of the recovery pass is available by calling the static method RecoveryMonitor.getResponse(); Note that only XA resource issues are reported using this mechanism which is sufficient to detect any resource recovery failures, including unavailablity of resources that impact orphan detection.

In process Recovery Manager

You can invoke the scan operation on the RecoveryManager. This operation returns only when recovery has completed. However, if you wish to have an asynchronous interaction pattern, then the RecoveryScan interface is provided:

RecoveryScan interface
public interface RecoveryScan {
    public void completed();
}

An instance of an object supporting this interface can be passed to the scan operation and its completed method will be called when recovery finishes. The scan operation returns immediately, however.

Recovering For Multiple Transaction Coordinators

Sometimes a single Recovery Manager can be made responsible for recovering transactions executing on behalf of multiple transaction coordinators. Conversely, due to specific configurations it may be that multiple Recovery Managers share the same Object Store and in which case should not conflict with each other, e.g., roll back transactions that they do not understand. Therefore, when running recovery it is necessary to tell Narayana which types of transactions it can recover and which transaction identifiers it should ignore.

When necessary each transaction identifier that Narayana creates may have a unique node identifier encoded within it and Narayana will only recover transactions and states that match a specified node identifier. The node identifier for each Narayana instance should be set via the com.arjuna.ats.arjuna.nodeIdentifier property. This value must be unique across Narayana instances. The contents of this should be alphanumeric and not exceed 10 bytes in length. If you do not provide a value, then Narayana will fabricate one and report the value via the logging infrastructure.

How this value is used will depend upon the type of resources being recovered and will be discussed within the relevant sections for the Recovery Modules.

Recovery From An Alternate Node

After failure it is sometimes desirable to recover on a different node from the one where the transaction manager failed. This kind of usage is only supported in JTA mode running inside an application server (with certain restrictions) and is not typical because of the consequences of incorrect configuration:

  • Only JTA transactions will be recovered (so the failing node must be configured in JTA mode).

  • Changing versions of Narayana or the application server on the new node is not supported.

  • The recovering node must have access to the same object store logs as the failed node (which can be achieved by either copying the logs or by using a shared file system or by using the JDBC object store connected to a database that is accessible to both nodes). If you are using the JDBC object store ensure that it is configured the same way on both nodes.

  • Both nodes must have access to the same set of resource managers and with the same configuration (minimally, the JNDI names must not change). Often the deployment model for databases is to host the resource manager on a different node from the application server so generally this should not be an issue.

  • Recovery requires help from Resource Managers which should be configured to support the ability to recover from other nodes. Database recovery is known to work but other resource managers may require case by case consideration.

  • If application deployments define their own datasources then these applications must also be deployed on the new server.

  • It is recommended that the transaction subsystem is configured in the same way on the new node as it was on the failed one. In particular the node identifier should not change. The comment made in the previous section about the uniqueness of the node identifier still applies so it is imperative that the failed node is not brought back online without changing its configuration. The same restrictions regarding object stores still apply, namely "exactly one recovery manager per ObjectStore must run on each node and ObjectStores must not be shared by multiple nodes".

  • Before restarting recovery on the new node sanity check your configuration to ensure it does not contain any hard coded IP addresses that refer to network interfaces on the failed node.

This is a long list of caveats and if it is not possible to simply restart the failed node then, in order to avoid the consequences of incorrect configuration, we advise that the application server on the recovering node uses the same configuration file as the failed node.

2.1.3. Recovery Modules

As stated before each recovery module is used to recover a different type of transaction/resource, but each recovery module must implement the following RecoveryModule interface, which defines two methods: periodicWorkFirstPass and periodicWorkSecondPass invoked by the Recovery Manager.

RecoveryModule interface
public interface RecoveryModule {
    /**
     * Called by the RecoveryManager at start up, and then
     * PERIODIC_RECOVERY_PERIOD seconds after the completion, for all
     * RecoveryModules of the second pass
     */
    public void periodicWorkFirstPass();

    /**
     * Called by the RecoveryManager RECOVERY_BACKOFF_PERIOD seconds after the
     * completion of the first pass
     */
    public void periodicWorkSecondPass();
}
Narayana Recovery Module Classes

Narayana provides a set of recovery modules that are responsible to manage recovery according to the nature of the participant and its position in a transactional tree. The provided classes (that all implements the RecoveryModule interface) are:

  • com.arjuna.ats.internal.arjuna.recovery.AtomicActionRecoveryModule

    Recovers AtomicAction transactions.

  • com.arjuna.ats.internal.jts.recovery.transactions.TransactionRecoveryModule

    Recovers JTS Transactions. This is a generic class from which TopLevel and Server transaction recovery modules inherit, respectively

  • com.arjuna.ats.internal.jts.recovery.transactions.TopLevelTransactionRecoveryModule

  • com.arjuna.ats.internal.jts.recovery.transactions.ServerTransactionRecoveryModule

2.1.4. A Recovery Module for XA Resources

During recovery, the Transaction Manager needs to be able to communicate to all resource managers that are in use by the applications in the system. For each resource manager, the Transaction Manager uses the XAResource.recover method to retrieve the list of transactions that are currently in a prepared or heuristically completed state. Typically, the system administrator configures all transactional resource factories that are used by the applications deployed on the system. An example of such a resource factory is the JDBC XADataSource object, which is a factory for the JDBC XAConnection objects.

Because XAResource objects are not persistent across system failures, the Transaction Manager needs to have some way to acquire the XAResource objects that represent the resource managers which might have participated in the transactions prior to the system failure. For example, a Transaction Manager might, through the use of JNDI lookup mechanism, acquire a connection from each of the transactional resource factories, and then obtain the corresponding XAResource object for each connection. The Transaction Manager then invokes the XAResource.recover method to ask each resource manager to return the transactions that are currently in a prepared or heuristically completed state.

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

One of the following recovery mechanisms will be used:

  • If the XAResource is serializable, then the serialized form will be saved during transaction commitment, and used during recovery. It is assumed that the recreated XAResource is valid and can be used to drive recovery on the associated database.

  • The com.arjuna.ats.jta.recovery.XAResourceRecovery, com.arjuna.ats.jta.recovery.XARecoveryResourceManager and com.arjuna.ats.jta.recovery.XARecoveryResource interfaces are used. These are described in detail later in this document.

To manage recovery, we have seen in the previous chapter that the Recovery Manager triggers a recovery process by calling a set of recovery modules that implements the two methods defined by the RecoveryModule interface. To enable recovery of participants controlled via the XA interface, a specific recovery module named XARecoveryModule is provided. The XARecoveryModule, defined in the packages com.arjuna.ats.internal.jta.recovery.arjunacore and com.arjuna.ats.internal.jta.recovery.jts, handles recovery of XA resources (databases etc.) used in JTA.

Narayana supports two JTA implementations: a purely local version (no distributed transactions) and a version layered on the JTS. Recovery for the former is straightforward. In the following discussion we shall implicitly consider on the JTS implementation.

Its behavior consists of two aspects: "transaction-initiated" and "`esource-initiated" recovery. Transaction-initiated recovery is possible where the particular transaction branch had progressed far enough for a JTA Resource Record to be written in the ObjectStore.

A JTA Resource record contains the information needed to link the transaction, as known to the rest of Narayana, to the database. Resource-initiated recovery is necessary for branches where a failure occurred after the database had made a persistent record of the transaction, but before the JTA ResourceRecord was persisted. Resource-initiated recovery is also necessary for datasources for which it is not possible to hold information in the JTA Resource record that allows the recreation in the RecoveryManager of the XAConnection/XAResource that was used in the original application.

Transaction-initiated recovery is automatic. The XARecoveryModule finds the JTA Resource Record that need recovery, then uses the normal recovery mechanisms to find the status of the transaction it was involved in (i.e., it calls replay_completion on the RecoveryCoordinator for the transaction branch), (re)creates the appropriate XAResource and issues commit or rollback on it as appropriate. The XAResource creation will use the same information, database name, username, password etc., as the original application.

Resource-initiated recovery has to be specifically configured, by supplying the Recovery Manager with the appropriate information for it to interrogate all the databases (XADataSources) that have been accessed by any Narayana application. The access to each XADataSource is handled by a class that implements the com.arjuna.ats.jta.recovery.XAResourceRecovery interface, as illustrated in Resource-initiated recovery and XA Recovery. Instances of classes that implements the XAResourceRecovery interface are dynamically loaded, as controlled by properties with names beginning com.arjuna.ats.jta.recovery.XAResourceRecovery.

failure recovery fig2 resourceinitiatedrecovery
Figure 5. Resource-initiated recovery and XA Recovery

The XARecoveryModule will use the XAResourceRecovery implementation to get a XAResource to the target datasource. On each invocation of periodicWorkSecondPass, the recovery module will issue an XAResource.recover request – this will (as described in the XA specification) return a list of the transaction identifiers (Xid’s) that are known to the datasource and are in an indeterminate (in-doubt) state. The list of these in-doubt Xid’s received on successive passes (i.e. periodicWorkSecondPass-es) is compared. Any Xid that appears in both lists, and for which no JTA ResourceRecord was found by the intervening transaction-initiated recovery is assumed to belong to a transaction that was involved in a crash before any JTA ResourceRecord 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 be written to contain all the information needed to perform recovery to some datasource. Alternatively, a single class can handle multiple datasources. The constructor of the implementation class must have an empty parameter list (because it is loaded dynamically), but 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 use made of this string is determined by the XAResourceRecovery implementation class.

For further details on the way to implement a class that implements the interface XAResourceRecovery, read the JDBC chapter of the JTA Programming Guide. An implementation class is provided that supports resource-initiated recovery for any XADataSource. This class could be used as a template to build your own implementation class.

Assumed complete

If a failure occurs in the transaction environment after the transaction coordinator had told the XAResource to commit but before the transaction log has been updated to remove the participant, then recovery will attempt to replay the commit. In the case of a Serialized XAResource, the response from the XAResource will enable the participant to be removed from the log, which will eventually be deleted when all participants have been committed. However, if the XAResource is not recoverable then it is extremely unlikely that any XAResourceRecovery instance will be able to provide the recovery sub-system with a fresh XAResource to use in order to attempt recovery; in which case recovery will continually fail and the log entry will never be removed.

There are two possible solutions to this problem:

  • Rely on the relevant ExpiryScanner to eventually move the log elsewhere. Manual intervention will then be needed to ensure the log can be safely deleted. If a log entry is moved, suitable warning messages will be output.

  • Set the com.arjuna.ats.jta.xaAssumeRecoveryComplete to true. This option is checked whenever a new XAResource instance cannot be located from any registered XAResourceRecovery instance. If false (the default), recovery assumes that there is a transient problem with the XAResourceRecovery instances (e.g., not all have been registered with the sub-system) and will attempt recovery periodically. If true then recovery assumes that a previous commit attempt succeeded and this instance can be removed from the log with no further recovery attempts. This option is global, so needs to be used with care since if used incorrectly XAResource instances may remain in an uncommitted state.

2.1.5. Recovering XAConnections

When recovering from failures, Narayana requires the ability to reconnect to databases that were in use prior to the failures in order to resolve any outstanding transactions. Most connection information will be saved by the transaction service during its normal execution, and can be used during recovery to recreate the connection. However, it is possible that not all such information will have been saved prior to a failure (for example, a failure occurs before such information can be saved, but after the database connection is used). In order to recreate those connections it is necessary to provide implementations of the following Narayana interface com.arjuna.ats.jta.recovery.XAResourceRecovery, one for each database that may be used by an application.

if using the transactional JDBC driver provided with Narayana, then no additional work is necessary in order to ensure that recovery occurs.

To inform the recovery system about each of the XAResourceRecovery instances, it is necessary to specify their class names through the JTAEnvironmentBean.xaResourceRecoveryInstances property variable, whose values is a list of space separated strings, each being a classname followed by optional configuration information.

JTAEnvironmentBean.xaResourceRecoveryInstances=com.foo.barRecovery

Additional information that will be passed to the instance when it is created may be specified after a semicolon:

JTAEnvironmentBean.xaResourceRecoveryInstances=com.foo.barRecovery;myData=hello

These properties need to go into the JTA section of the property file.

Any errors will be reported during recovery.

XAResourceRecovery interface
public interface XAResourceRecovery {
    public XAResource getXAResource() throws SQLException;

    public boolean initialise(String p);

    public boolean hasMoreResources();
};

Each method should return the following information:

  • initialise: once the instance has been created, any additional information which occurred on the property value (anything found after the first semi-colon) will be passed to the object. The object can then use this information in an implementation specific manner to initialise itself, for example.

  • hasMoreResources: each XAResourceRecovery implementation may provide multiple XAResource instances. Before any call to getXAResource is made, hasMoreResources is called to determine whether there are any further connections to be obtained. If this returns false, getXAResource will not be called again during this recovery sweep and the instance will not be used further until the next recovery scan. It is up to the implementation to maintain the internal state backing this method and to reset the iteration as required. Failure to do so will mean that the second and subsequent recovery sweeps in the lifetime of the JVM do not attempt recovery.

  • getXAResource: returns an instance of the XAResource object. How this is created (and how the parameters to its constructors are obtained) is up to the XAResourceRecovery implementation. The parameters to the constructors of this class should be similar to those used when creating the initial driver or data source, and should obviously be sufficient to create new XAResources that can be used to drive recovery.

If you want your XAResourceRecovery instance to be called during each sweep of the recovery manager then you should ensure that once hasMoreResources returns false to indicate the end of work for the current scan it then returns true for the next recovery scan.

2.1.6. Alternative to XAResourceRecovery

The iterator based approach used by XAResourceRecovery leads to a requirement for implementations to manage state, which makes them more complex than necessary.

As an alternative, starting with Narayana 4.4, users may provide an implementation of the public interface

XAResourceRecoveryHelper
public interface com.arjuna.ats.jta.recovery.

XAResourceRecoveryHelper {
    public boolean initialise (String p) throws Exception;
    public XAResource[] getXAResources () throws Exception;
}

During each recovery sweep the getXAResources method will be called and recovery attempted on each element of the array. For the majority of resource managers it will be necessary to have only one XAResource in the array, as the recover() call on it can return multiple Xids.

Unlike XAResourceRecovery instances, which are configured via the xml properties file and instantiated by Narayana, instances of XAResourceRecoveryHelper and constructed by the application code and registered with Narayana by calling

XARecoveryModule.addXAResourceRecoveryHelper(...)

The initialize method is not called by Narayana in the current implementation, but is provided to allow for the addition of further configuration options in later releases.

XAResourceRecoveryHelper instances may be deregistered, after which they will no longer be called by the recovery manager. Deregistration may block for a time if a recovery scan is in progress.

XARecoveryModule.removeXAResourceRecoveryHelper(...)

The ability to dynamically add and remove instances of XAResourceRecoveryHelper whilst the system is running makes this approach an attractive option for environments in which e.g. datasources may be deployed or undeployed, such as application servers. Care should be taken with classloading behaviour in such cases.

2.1.7. Shipped XAResourceRecovery implementations

Recovery of XA datasources can sometimes be implementation dependant, requiring developers to provide their own XAResourceRecovery instances. However, Narayana ships with several out-of-the-box implementations that may be useful.

These XAResourceRecovery instances are primarily intended for when running Narayana outside of a container such as WildFly Application Server, since they rely upon XADataSources as the primary handle to drive recovery. If you are not running Narayana stand-alone then you should consult the relevant integration documentation to ensure that the right recovery modules are being used.

com.arjuna.ats.internal.jdbc.recovery.BasicXARecovery

this expects an XML property file to be specified upon creation and from which it will read the configuration properties for the datasource. For example:

XML datasource
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
    <entry key="DB_X_DatabaseUser">username</entry>
    <entry key="DB_X_DatabasePassword">password"</entry>
    <entry key="DB_X_DatabaseDynamicClass">DynamicClass</entry>
    <entry key="DB_X_DatabaseURL">theURL</entry>
</properties>
com.arjuna.ats.internal.jdbc.recovery.JDBCXARecovery

this recovery implementation should work on any datasource that is exposed via JNDI. It expects an XML property file to be specified upon creation and from which it will read the database JNDI name, username and password. For example:

JNDI datasource
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
    <entry key="DatabaseJNDIName">java:ExampleDS</entry>
    <entry key="UserName">username</entry>
    <entry key="Password">password</entry>
</properties>

Because these classes are XAResourceRecovery instances they are passed any necessary initialization information via the initialise operation. In the case of BasicXARecovery and JDBCXARecovery this should be the location of a property file and is specified in the Narayana configuration file. For example:

com.arjuna.ats.jta.recovery.XAResourceRecoveryJDBC=com.arjuna.ats.internal.jdbc.recovery.JDBCXAResourceRecovery;thePropertyFile

2.1.8. TransactionStatusConnectionManager

The TransactionStatusConnectionManager object is used by the recovery modules to retrieve the status of transactions and acts like a proxy for TransactionStatusManager objects. It maintains a table of TransactionStatusConnector obects each of which connects to a TransactionStatusManager object in an Application Process.

The transactions status is retrieved using the getTransactionStatus methods which take a transaction Uid and if available a transaction type as parameters. The process Uid field in the transactions Uid parameter is used to lookup the target TransactionStatusManagerItem host/port pair in the Object Store. The host/port pair are used to make a TCP connection to the target TransactionStatusManager object by a TransactionStatusConnector object. The TransactionStatusConnector passes the transaction Uid/transaction type to the TransactionStatusManager in order to retrieve the transactions status.

2.1.9. Expired Scanner Thread

When the Recovery Manager initialises an expiry scanner thread ExpiryEntryMonitor is created which is used to remove long dead items from the ObjectStore. A number of scanner modules are dynamically loaded which remove long dead items for a particular type.

Scanner modules are loaded at initialisation and are specified as properties beginning with

<entry key="RecoveryEnvironmentBean.expiryScanners">
    list of class names
</entry>

All the scanner modules are called periodically to scan for dead items by the ExpiryEntryMonitor thread. This period is set with the property:

<entry key="RecoveryEnvironmentBean.expiryScanInterval">
    number_of_hours
</entry>

All scanners inherit the same behaviour from the java interface ExpiryScanner. A scan method is provided by this interface and implemented by all scanner modules, this is the method that gets called by the scanner thread.

The ExpiredTransactionStatusManagerScanner removes long dead TransactionStatusManagerItems from the Object Store. These items will remain in the Object Store for a period of time before they are deleted. This time is set by the property:

<entry key="RecoveryEnvironmentBean.transactionStatusManagerExpiryTime">
    number_of_hours
</entry> (default 12 hours)

The AtomicActionExpiryScanner moves transaction logs for AtomicActions that are assumed to have completed. For instance, if a failure occurs after a participant has been told to commit but before the transaction system can update the log, then upon recovery Narayana recovery will attempt to replay the commit request, which will obviously fail, thus preventing the log from being removed. This is also used when logs cannot be recovered automatically for other reasons, such as being corrupt or zero length. All logs are moved to a location based on the old location appended with /Expired.

AtomicActionExpiryScanner is disabled by default. To enable it simply add it to the Narayana properties file. You do not need to enable it in order to cope with (move) corrupt logs.

2.1.10. Application Process

This represents the user transactional program. A Local transaction (hash) table, maintained within the running application process keeps trace of the current status of all transactions created by that application process, The Recovery Manager needs access to the transaction tables so that it can determine whether a transaction is still in progress, if so then recovery does not happen.

The transaction tables are accessed via the TransactionStatusManager object. On application program initialisation the host/port pair that represents the TransactionStatusManager is written to the Object Store in ../Recovery/TransactionStatusManager part of the Object Store file hierarchy and identified by the process Uid of the application process.

The Recovery Manager uses the TransactionStatusConnectionManager object to retrieve the status of a transaction and a TransactionStatusConnector object is used to make a TCP connection to the TransactionStatusManager.

2.1.11. TransactionStatusManager

This object acts as an interface for the Recovery Manager to obtain the status of transactions from running Narayana application processes. One TransactionStatusManager is created per application process by the class com.arjuna.ats.arjuna.coordinator.TxControl. Currently a tcp connection is used for communication between the RecoveryManager and TransactionStatusManager. Any free port is used by the TransactionStatusManager by default, however the port can be fixed with the property:

<entry key="RecoveryEnvironmentBean.transactionStatusManagerPort">
    port
</entry>

On creation the TransactionStatusManager obtains a port which it stores with the host in the Object Store as a TransactionStatusManagerItem. A Listener thread is started which waits for a connection request from a TransactionStatusConnector. When a connection is established a Connection thread is created which runs a Service (AtomicActionStatusService) which accepts a transaction Uid and a transaction type (if available) from a TransactionStatusConnector, the transaction status is obtained from the local thransaction table and returned back to the TransactionStatusConnector

2.1.12. Object Store

All objects are identified by a unique identifier Uid. One of the values of which is a process id in which the object was created. The Recovery Manager uses the process id to locate transaction status manager items when contacting the originator application process for the transaction status. Therefore, exactly one recovery manager per ObjectStore must run on each node and ObjectStores must not be shared by multiple nodes.

2.1.13. Socket free operation

The use of TCP/IP sockets for TransactionStatusManager and RecoveryManager provides for maximum flexibility in the deployment architecture. It is often desirable to run the RecoveryManager in a separate JVM from the Transaction manager(s) for increased reliability. In such deployments, TCP/IP provides for communication between the RecoveryManager and transaction manager(s), as detailed in the preceding sections. Specifically, each JVM hosting a TransactionManager will run a TransactionStatusManager listener, through which the RecoveryManager can contact it to determine if a transaction is still live or not. The RecoveryManager likewise listens on a socket, through which it can be contacted to perform recovery scans on demand. The presence of a recovery listener is also used as a safety check when starting a RecoveryManager, since at most one should be running for a given ObjectStore.

There are some deployment scenarios in which there is only a single TransactionManager accessing the ObjectStore and the RecoveryManager is co-located in the same JVM. For such cases the use of TCP/IP sockets for communication introduces unnecessary runtime overhead. Additionally, if several such distinct processes are needed for e.g. replication or clustering, management of the TCP/IP port allocation can become unwieldy. Therefore it may be desirable to configure for socketless recovery operation.

The property CoordinatorEnvironmentBean.transactionStatusManagerEnable can be set to a value of NO to disable the TransactionStatusManager for any given TransactionManager. Note that this must not be done if recovery runs in a separate process, as it may lead to incorrect recovery behavior in such cases. For an in-process recovery manager, the system will use direct access to the ActionStatusService instead.

The property RecoveryEnvironmentBean.recoveryListener can likewise be used to disable the TCP/IP socket listener used by the recovery manager. Care must be taken not to inadvertently start multiple recovery managers for the same ObjectStore, as this error, which may lead to significant crash recovery problems, cannot be automatically detected and prevented without the benefit of the socket listener.

2.2. How Narayana manages the OTS Recovery Protocol

2.2.1. Recovery Protocol in OTS - Overview

To manage recovery in case of failure, the OTS specification has defined a recovery protocol. Transaction’s participants in a doubt status could use the RecoveryCoordinator to determine the status of the transaction. According to that transaction status, those participants can take appropriate decision either by roll backing or committing.

failure recovery fig3 resource recoverycoordinator
Figure 6. Resource and RecoveryCoordinator relationship

A reference to a RecoveryCoordinator is returned as a result of successfully calling register_resource on the transaction Coordinator. This object, which is implicitly associated with a single Resource, can be used to drive the Resource through recovery procedures in the event of a failure occurring during the transaction.

2.2.2. RecoveryCoordinator in Narayana

On each resource registration a RecoveryCoordinator Object is expected to be created and returned to the application that invoked the register_resource operation. Behind each CORBA object there should be an object implementation or Servant object, in POA terms, which performs operations made on a RecoveryCoordinator object. Rather than to create a RecoveryCoordinator object with its associated servant on each register_resource, Narayana enhances performance by avoiding the creation of servants but it relies on a default RecoveryCoordinator object with it’s associated default servant to manage all replay_completion invocations.

In the next sections we first give an overview of the Portable Object Adapter architecture, then we describe how this architecture is used to provide RecoveryCoordinator creation with optimization as explained above.

Understanding POA

Basically, the Portable Object Adapter, or POA is an object that intercepts a client request and identifies the object that satisfies the client request. The Object is then invoked and the response is returned to the client.

failure recovery fig4 overview of poa
Figure 7. Overview of the POA

The object that performs the client request is referred as a servant, which provides the implementation of the CORBA object requested by the client. A servant provides the implementation for one or more CORBA object references. To retreive a servant, each POA maintains an Active Object Map that maps all objects that have been activated in the POA to a servant. For each incoming request, the POA looks up the object reference in the Active Object Map and tries to find the responsible servant. If none is found, the request is either delegated to a default servant, or a servant manager is invoked to activate or locate an appropriate servant. In addition to the name space for the objects, which are identified by Object Ids, a POA also provides a name space for POAs. A POA is created as a child of an existing POA, which forms a hierarchy starting with the root POA.

Each POA has a set of policies that define its characteristics. When creating a new POA, the default set of policies can be used or different values can be assigned that suit the application requirements. The POA specification defines:

  • Thread policy – Specifies the threading model to be used by the POA. Possible values are:

    • ORB_CTRL_MODEL – (default) The POA is responsible for assigning requests to threads.

    • SINGLE_THREAD_MODEL – the POA processes requests sequentially

  • Lifespan policy - specifies the lifespan of the objects implemented in the POA. The lifespan policy can have the following values:

    • TRANSIENT (Default) Objects implemented in the POA cannot outlive the process in which they are first created. Once the POA is deactivated, an OBJECT_NOT_EXIST exception occurs when attempting to use any object references generated by the POA.

    • PERSISTENT Objects implemented in the POA can outlive the process in which they are first created.

  • Object ID Uniqueness policy - allows a single servant to be shared by many abstract objects. The Object ID Uniqueness policy can have the following values:

    • UNIQUE_ID (Default) Activated servants support only one Object ID.

    • MULTIPLE_ID Activated servants can have one or more Object IDs. The Object ID must be determined within the method being invoked at run time.

  • ID Assignment policy - specifies whether object IDs are generated by server applications or by the POA. The ID Assignment policy can have the following values:

    • USER_ID is for persistent objects, and

    • SYSTEM_ID is for transient objects

  • Servant Retention policy - specifies whether the POA retains active servants in the Active Object Map. The Servant Retention policy can have the following values:

    • RETAIN (Default) The POA tracks object activations in the Active Object Map. RETAIN is usually used with ServantActivators or explicit activation methods on POA.

    • NON_RETAIN The POA does not retain active servants in the Active Object Map. NON_RETAIN is typically used with ServantLocators.

  • Request Processing policy - specifies how requests are processed by the POA.

    • USE_ACTIVE_OBJECT_MAP (Default) If the Object ID is not listed in the Active Object Map, an OBJECT_NOT _EXIST exception is returned. The POA must also use the RETAIN policy with this value.

    • USE_DEFAULT_SERVANT If the Object ID is not listed in the Active Object Map or the NON_RETAIN policy is set, the request is dispatched to the default servant. If no default servant has been registered, an OBJ_ADAPTER exception is returned. The POA must also use the MULTIPLE_ID policy with this value.

    • USE_SERVANT_MANAGER If the Object ID is not listed in the Active Object Map or the NON_RETAIN policy is set, the servant manager is used to obtain a servant.

  • Implicit Activation policy - specifies whether the POA supports implicit activation of servants. The Implicit Activation policy can have the following values:

    • IMPLICIT_ACTIVATION The POA supports implicit activation of servants. Servants can be activated by converting them to an object reference with org.omg.PortableServer.POA.servant_to_reference() or by invoking _this()on the servant. The POA must also use the SYSTEM_ID and RETAIN policies with this value.

    • NO_IMPLICIT_ACTIVATION (Default) The POA does not support implicit activation of servants.

It appears that to redirect replay_completion invocations to a default servant we need to create a POA with the Request Processing policy assigned with the value set to USE_DEFAULT_SERVANT. However to reach that default Servant we should first reach the POA that forward the request to the default servant. Indeed, the ORB uses a set of information to retrieve a POA; these information are contained in the object reference used by the client. Among these information there are the IP address and the port number where resides the server and also the POA name. To perform replay_completion invocations, the solution adopted by Narayana is to provide one Servant, per machine, and located in the RecoveryManager process, a separate process from client or server applications. The next section explains how the indirection to a default Servant located on a separate process is provided for JacORB.

2.2.3. The default RecoveryCoordinator in JacOrb

JacORB does not define additional policies to redirect any request on a RecoveryCoordinator object to a default servant located in the Recovery Manager process. However it provides a set of APIs that allows building object references with specific IP address, port number and POA name in order to reach the appropriate default servant.

How Does it work

When the Recovery Manager is launched it seeks in the configuration the RecoveryActivator that need be loaded. Once done it invokes the startRCservice method of each loaded instances. As seen in in the previous chapter (Recovery Manager ) the class to load that implements the RecoveryActivator interface is the class RecoveryEnablement. This generic class, located in the package com.arjuna.ats.internal.jts.orbspecific.recovery, hides the nature of the ORB being used by the application (JacORB). The following figure illustrates the behavior of the RecoveryActivator that leads to the creation of the default servant that performs replay_completion invocations requests.

In addition to the creation of the default servant, an object reference to a RecoveryCoordinator object is created and stored in the ObjectStore. As we will see this object reference will be used to obtain its IP address, port number and POA name and assign them to any RecoveryCoordinator object reference created on register_resource.

failure recovery fig5 recoverymanager
Figure 8. Recovery Manager

When an application registers a resource with a transaction, a RecoveryCoordinator object reference is expected to be returned. To build that object reference, the Transaction Service uses the RecoveryCoordinator object reference created within the Recovery Manager as a template. The new object reference contains practically the same information to retrieve the default servant (IP address, port number, POA name, etc.), but the Object ID is changed; now, it contains the Transaction ID of the transaction in progress and also the Process ID of the process that is creating the new RecoveryCoordinator object reference, as illustrated in Resource registration and returned RecoveryCoordinator Object reference build from a referencestored in the ObjectStore..

failure recovery fig6 resourceregistration
Figure 9. Resource registration and returned RecoveryCoordinator Object reference build from a referencestored in the ObjectStore.

Since a RecoveryCoordintaor object reference returned to an application contains all information to retrieve the POA then the default servant located in the Recovery Manager, all replay_completion invocation, per machine, are forwarded to the same default RecoveryCoordinator that is able to retreive the Object ID from the incoming request to extract the transaction identifier and the process identifier needed to determine the status of the requested transaction.

2.3. Configuration Options

2.3.1. Recovery Protocol in OTS - Overview

Narayana is highly configurable. For full details of the configuration mechanism used, see the Programmer’s Guide.

The following table shows the configuration features, with default values shown in italics. More details about each option can be found in the relevant sections of this document.

You need to prefix each property in this table with the string com.arjuna.ats.arjuna.recovery. The prefix has been removed for formatting reasons, and has been replaced by …​

Configuration Name Possible Values Description

…​periodicRecoveryPeriod

120/any positive integer

Interval between recovery attempts, in seconds.

…​recoveryBackoffPeriod

10/any positive integer

Interval between first and second recovery passes, in seconds.

…​periodicRecoveryInitilizationOffset

0/any non-negative integer

Interval before first recovery pass, in seconds.

…​expiryScanInterval

12/any integer

Interval between expiry scans, in hours. 0 disables scanning. Negative values postpone the first run.

…​transactionStatusManagerExpiryTime

12/any positive integer

Interval after which a non-contactable process is considered dead. 0 = never.

3. Development Guide

3.1. Transactions

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.

3.1.1. The Java Transaction API (Jakarta Transactions)

The interfaces specified by the many transaction standards tend to be too low-level for most application programmers. Therefore, Sun Microsystems created the Java Transaction API (JTA), which specifies higher-level interfaces to assist in the development of distributed transactional applications. JTA was later renamed Jakarta Transactions and the specification is maintained at https://jakarta.ee/specifications/transactions.

Note, these interfaces are still low-level. You still need to implement state management and concurrency for transactional applications. The interfaces are also optimized for applications which require XA resource integration capabilities, rather than the more general resources which other transactional APIs allow.

With reference to Jakarta Transactions (https://jakarta.ee/specifications/transactions/), distributed transaction services typically involve a number of participants:

application server

provides the infrastructure required to support the application run-time environment which includes transaction state management, such as an EJB server.

transaction manager

provides the services and management functions required to support transaction demarcation, transactional resource management, synchronization, and transaction context propagation.

resource manager

Using a resource adapter, provides the application with access to resources. The resource manager participates in distributed transactions by implementing a transaction resource interface used by the transaction manager to communicate transaction association, transaction completion and recovery.

A resource adapter is used by an application server or client to connect to a Resource Manager. JDBC drivers which are used to connect to relational databases are examples of Resource Adapters.

communication resource manager

supports transaction context propagation and access to the transaction service for incoming and outgoing requests.

From the point of view of the transaction manager, the actual implementation of the transaction services does not need to be exposed. You only need to define high-level interfaces to allow transaction demarcation, resource enlistment, synchronization and recovery process to be driven from the users of the transaction services. Jakarta Transactions is a high-level application interface that allows a transactional application to demarcate transaction boundaries, and also contains a mapping of the X/Open XA protocol.

Compatibility

the Jakarta Transactions support provided by Narayana is compliant with the 1.1 specification.

3.1.2. Introducing the API

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

  • a standard Java mapping of the X/Open XA protocol intended for a transactional resource manager.

All of the Jakarta Transactions classes and interfaces exist within the jakarta.transaction package, and the corresponding Narayana implementations within the com.arjuna.ats.jta package. Note that XA resource API classes are still part of the Java SE (https://jakarta.ee/specifications/transactions/2.0/jakarta-transactions-spec-2.0.html#relationship-to-other-java-apis)

Each Xid created by Narayana needs a unique node identifier encoded within it, because Narayana can only recover transactions and states that match a specified node identifier. The node identifier to use should be provided to Narayana via the CoreEnvironmentBean.nodeIdentifier property. This value must be unique across your Narayana instances. The identifier is alphanumeric and limited to 10 bytes in length. If you do not provide a value, then Narayana generates one and reports the value via the logging infrastructure.

3.1.3. UserTransaction

The UserTransaction interface provides applications with the ability to control transaction boundaries. It provides methods begin, commit, and rollback to operate on top-level transactions.

Nested transactions are not supported, and method begin throws the exception NotSupportedException if the calling thread is already associated with a transaction. UserTransaction automatically associates newly created transactions with the invoking thread.

To obtain a UserTransaction, call the static method com.arjuna.ats.jta.UserTransaction.userTransaction().

Procedure: Selecting the local Jakarta Transactions Implementation
  1. Set property JTAEnvironmentBean.jtaTMImplementation to `com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionManagerImple `.

  2. Set property JTAEnvironmentBean.jtaUTImplementation to com.arjuna.ats.internal.jta.transaction.arjunacore.UserTransactionImple.

3.1.4. TransactionManager

The TransactionManager interface allows the application server to control transaction boundaries on behalf of the application being managed.

To obtain a TransactionManager, invoke the static method com.arjuna.ats.jta.TransactionManager.transactionManager.

The TransactionManager maintains the transaction context association with threads as part of its internal data structure. A thread’s transaction context may be null or it may refer to a specific global transaction. Multiple threads may be associated with the same global transaction. As noted in UserTransaction, nested transactions are not supported.

Each transaction context is encapsulated by a Transaction object, which can be used to perform operations which are specific to the target transaction, regardless of the calling thread’s transaction context.

Table 3. `TransactionManager`Methods

begin

Starts a new top-level transaction and associates the transaction context with the calling thread. If the calling thread is already associated with a transaction, exception NotSupportedException is thrown.

getTransaction

Returns the Transaction object representing the transaction context which is currently associated with the calling thread. You can use this object to perform various operations on the target transaction.

commit

Completes the transaction currently associated with the calling thread. After it returns, the calling thread is associated with no transaction. If commit is called when the thread is not associated with any transaction context, an exception is thrown. In some implementations, the commit operation is restricted to the transaction originator only. If the calling thread is not allowed to commit the transaction, an exception is thrown. Narayana does not currently impose any restriction on the ability of threads to terminate transactions.

rollback

Rolls back the transaction associated with the current thread. After the rollback method completes, the thread is associated with no transaction.

In a multi-threaded environment, multiple threads may be active within the same transaction. If checked transaction semantics have been disabled, or the transaction times out, a transaction may terminated by a thread other than the one that created it. In this case, the creator usually needs to be notified. Narayana notifies the creator during operations commit or rollback by throwing exception IllegalStateException.

3.1.5. Suspend and resuming a transaction

Jakarta Transactions supports the concept of a thread temporarily suspending and resuming transactions in order to perform non-transactional work. Call the suspend method to temporarily suspend the current transaction that is associated with the calling thread. The thread then operates outside of the scope of the transaction. If the thread is not associated with any transaction, a null object reference is returned. Otherwise, a valid Transaction object is returned. Pass the Transaction object to the resume method to reinstate the transaction context.

The resume method associates the specified transaction context with the calling thread. If the transaction specified is not a valid transaction, the thread is associated with no transaction. if resume is invoked when the calling thread is already associated with another transaction, the IllegalStateException exception is thrown.

Using the `suspend`method
Transaction tobj = TransactionManager.suspend();
..
        TransactionManager.

resume(tobj);

Narayana allows a suspended transaction to be resumed by a different thread. This feature is not required by Jakarta Transactions, but is an important feature.

When a transaction is suspended, the application server must ensure that the resources in use by the application are no longer registered with the suspended transaction. When a resource is de-listed this triggers the Transaction Manager to inform the resource manager to disassociate the transaction from the specified resource object. When the application’s transaction context is resumed, the application server must ensure that the resources in use by the application are again enlisted with the transaction. Enlisting a resource as a result of resuming a transaction triggers the Transaction Manager to inform the resource manager to re-associate the resource object with the resumed transaction.

3.1.6. The Transaction interface

The Transaction interface allows you to perform operations on the transaction associated with the target object. Every top-level transaction is associated with one Transaction object when the transaction is created.

Uses of the `Transaction`object
  • enlist the transactional resources in use by the application.

  • register for transaction synchronization call backs.

  • commit or rollback the transaction.

  • obtain the status of the transaction.

The commit and rollback methods allow the target object to be committed or rolled back. The calling thread does not need to have the same transaction associated with the thread. If the calling thread is not allowed to commit the transaction, the transaction manager throws an exception. At present Narayana does not impose restrictions on threads terminating transactions.

Jakarta Transactions does not provide a means to obtain the transaction identifier. However, Narayana provides several ways to view the transaction identifier. Call method toString to print full information about the transaction, including the identifier. Alternatively you can cast the jakarta.transaction.Transaction instance to a com.arjuna.ats.jta.transaction.Transaction, then call either method get_uid, which returns an ArjunaCore Uid representation, or getTxId, which returns an Xid for the global identifier, i.e., no branch qualifier.

3.1.7. Resource enlistment

Typically, an application server manages transactional resources, such as database connections, in conjunction with some resource adapter and optionally with connection pooling optimization. For an external transaction manager to coordinate transactional work performed by the resource managers, the application server must enlist and de-list the resources used in the transaction. These resources, called participants, are enlisted with the transaction so that they can be informed when the transaction terminates, by being driven through the two-phase commit protocol.

As stated previously, Jakarta Transactions is much more closely integrated with the XA concept of resources than the arbitrary objects. For each resource the application is using, the application server invokes the enlistResource method with an XAResource object which identifies the resource in use.

The enlistment request causes the transaction manager to inform the resource manager to start associating the transaction with the work performed through the corresponding resource. The transaction manager passes the appropriate flag in its XAResource.start method call to the resource manager.

The delistResource method disassociates 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 causes the transaction manager to inform 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.

3.1.8. Transaction synchronization

Transaction synchronization allows the application server to be notified before and after the transaction completes. For each transaction started, the application server may optionally register a Synchronization call-back object to be invoked by the transaction manager, which will be one of the following:

beforeCompletion

Called before the start of the two-phase transaction complete process. This call is executed in the same transaction context of the caller who initiates the TransactionManager.commit or the call is executed with no transaction context if Transaction.commit is used.

afterCompletion

Called after the transaction completes. The status of the transaction is supplied in the parameter. This method is executed without a transaction context.

NOTE: If an XAResource throws a RuntimeException, this method will not be called as the transaction has not and cannot complete. Please see JBTM-2148 for more details.

3.1.9. Transaction equality

The transaction manager implements the Transaction object’s equals method to allow comparison between the target object and another Transaction object. The equals method returns true if the target object and the parameter object both refer to the same global transaction.

Method equals
Transaction txObj = TransactionManager.getTransaction();
Transaction someOtherTxObj = ..
        ..

boolean isSame = txObj.equals(someOtherTxObj);      

3.1.10. TransactionSynchronizationRegistry

The jakarta.transaction.TransactionSynchronizationRegistry interface, added to the Jakarta Transactions API in version 1.1, provides for registering Synchronizations with special ordering behavior, and for storing key-value pairs in a per-transaction Map. Full details are available in the Jakarta Transactions API specification and javadoc. Here we focus on implementation specific behavior.

Example 1. Accessing the TransactionSynchronizationRegistry in standalone environments
jakarta.transaction.TransactionSynchronizationRegistry tsr = new com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionSynchronizationRegistryImple();

This is a stateless object and hence is cheap to instantiate.

Accessing the TransactionSynchronizationRegistry via JNDI

In application server environments, the standard JNDI name binding is java:comp/TransactionSynchronizationRegistry.

Ordering of interposed Synchronizations is relative to other local Synchronizations only. In cases where the transaction is distributed over multiple JVMs, global ordering is not guaranteed.

The per-transaction data storage provided by the TransactionSynchronizationRegistry methods getResource and putResource are non-persistent and thus not available in Transactions during crash recovery. When running integrated with an application server or other container, this storage may be used for system purposes. To avoid collisions, use an application-specific prefix on map keys, such as put("myapp_"+key, value). The behavior of the Map on Thread s that have status NO_TRANSACTION or where the transaction they are associated with has been rolled back by another Thread, such as in the case of a timeout, is undefined. A Transaction can be associated with multiple Thread`s. For such cases the `Map is synchronized to provide thread safety.

3.2. The Resource Manager

3.2.1. The XAResource interface

Some transaction specifications and systems define a generic resource which can be used to register arbitrary resources with a transaction, the JTA is much more XA-specific. Interface javax.transaction.xa.XAResource is a Java mapping of the XA interface. The XAResource interface defines the contract between a ResourceManager and a TransactionManager in a distributed transaction processing environment. A resource adapter for a ResourceManager implements the XAResource interface to support association of a top-level transaction to a resource such as a relational database.

The XAResource interface can be supported by any transactional resource adapter designed to be used in an environment where transactions are controlled by an external transaction manager, such a database management system. An application may access data through multiple database connections. Each database connection is associated with an XAResource object that serves as a proxy object to the underlying ResourceManager instance. The transaction manager obtains an XAResource for each ResourceManager participating in a top-level transaction. The start method associates the transaction with the resource, and the end method disassociates the transaction from the resource.

The ResourceManager associates the transaction with all work performed on its data between invocation of start and end methods. At transaction commit time, these transactional ResourceManager s are informed by the transaction manager to prepare, commit, or roll back the transaction according to the two-phase commit protocol.

For better Java integration, the XAResource differs from the standard XA interface in the following ways:

  • The resource adapter implicitly initializes the ResourceManager when the resource (the connection) is acquired. There is no equivalent to the xa_open method of the interface XA.

  • Rmid is not passed as an argument. Each Rmid is represented by a separate XAResource object.

  • Asynchronous operations are not supported, because Java supports multi-threaded processing and most databases do not support asynchronous operations.

  • Error return values caused by the transaction manager’s improper handling of the XAResource object are mapped to Java exceptions via the XAException class.

  • The DTP concept of Thread of Control maps to all Java threads that are given access to the XAResource and Connection objects. For example, it is legal for two different threads to perform the start and end operations on the same XAResource object.

Extended XAResource control

By default, whenever an XAResource object is registered with a JTA-compliant transaction service, there is no way to manipulate the order in which it is invoked during the two-phase commit protocol, with respect to other XAResource objects. Narayana, however, provides support for controlling the order via the two interfaces com.arjuna.ats.jta.resources.StartXAResource and com.arjuna.ats.jta.resources.EndXAResource. By inheriting your XAResource instance from either of these interfaces, you control whether an instance of your class is invoked first or last, respectively.

Only one instance of each interface type may be registered with a specific transaction.

The ArjunaCore Development Guide discusses the Last Resource Commit optimization (LRCO), whereby a single resource that is only one-phase aware, and does not support the prepare phase, can be enlisted with a transaction that is manipulating two-phase aware participants. This optimization is also supported within the Narayana.

In order to use the LRCO, your XAResource implementation must extend the com.arjuna.ats.jta.resources.LastResourceCommitOptimisation marker interface. A marker interface is an interface which provides no methods. When enlisting the resource via method Transaction.enlistResource, Narayana ensures that only a single instance of this type of participant is used within each transaction. Your resource is driven last in the commit protocol, and no invocation of method prepare occurs.

By default an attempt to enlist more than one instance of a LastResourceCommitOptimisation class will fail and false will be returned from Transaction.enlistResource. This behavior can be overridden by setting the com.arjuna.ats.jta.allowMultipleLastResources to true. However, before doing so you should read the section on enlisting multiple one-phase aware resources.

You need to disable interposition support to use the LCRO in a distributed environment. You can still use implicit context propagation.

Enlisting multiple one-phase-aware resources

One-phase commit is used to process a single one-phase aware resource, which does not conform to the two-phase commit protocol. You can still achieve an atomic outcome across resources, by using the LRCO, as explained earlier.

Multiple one-phase-aware resources may be enlisted in the same transaction. One example is when a legacy database runs within the same transaction as a legacy JMS implementation. In such a situation, you cannot achieve atomicity of transaction outcome across multiple resources, because none of them enter the prepare state. They commit or roll back immediately when instructed by the transaction coordinator, without knowledge of other resource states and without a way to undo if subsequent resources make a different choice. This can result in data corruption or heuristic outcomes.

You can approach these situations in two different ways:

  • Wrap the resources in compensating transactions. See the XTS Transactions Development Guide for details.

  • Migrate the legacy implementations to two-phase aware equivalents.

If neither of these options is viable, Narayana support enlisting multiple one-phase aware resources within the same transaction, using LRCO, which is discussed in the ArjunaCore Development Guide in detail.

Even when this support is enabled, Narayana issues a warning when it detects that the option has been enabled: You have chosen to enable multiple last resources in the transaction manager. This is transactionally unsafe and should not be relied upon. Another warning is issued when multiple one-phase aware resources are enlisted within a transaction: This is transactionally unsafe and should not be relied on.

To override the above-mentioned warning at runtime, set the CoreEnvironmentBean.disableMultipleLastResourcesWarning property to true. You will see a warning that you have done this when Narayana starts up and see the warning about enlisting multiple one-phase resources only the first time it happens, but after that no further warnings will be output. You should obviously only consider changing the default value of this property (false) with caution.

3.2.2. Opening a resource manager

The X/Open XA interface requires the transaction manager to initialize a resource manager, using method xa_open, before invoking any other of the interface’s methods. JTA requires initialization of a resource manager to be embedded within the resource adapter that represents the resource manager. The transaction manager does not need to know how to initialize a resource manager. It only informs the resource manager about when to start and end work associated with a transaction and when to complete the transaction. The resource adapter opens the resource manager when the connection to the resource manager is established.

3.2.3. Closing a resource manager

The resource adapter closes a resource manager as a result of destroying the transactional resource. A transaction resource at the resource adapter level is comprised of two separate objects:

  • An XAResource object that allows the transaction manager to start and end the transaction association with the resource in use and to coordinate transaction completion process.

  • A connection object that allows the application to perform operations on the underlying resource, such as JDBC operations on an RDBMS.

Once opened, the resource manager is kept open until the resource is released explicitly. When the application invokes the connection’s close method, the resource adapter invalidates the connection object reference that was held by the application and notifies the application server about the close. The transaction manager invokes the XAResource.end method to disassociate the transaction from that connection.

The close notification triggers the application server to perform any necessary cleanup work and to mark the physical XA connection as free for reuse, if connection pooling is in place.

3.2.4. Thread of control

The X/Open XA interface specifies that the transaction-association-related xa calls must be invoked from the same thread context. This thread-of-control requirement does not apply to the object-oriented component-based application run-time environment, in which application threads are dispatched dynamically as methods are invoked.. Different threads may use the same connection resource to access the resource manager if the connection spans multiple method invocation. Depending on the implementation of the application server, different threads may be involved with the same XAResource object. The resource context and the transaction context operate independent of thread context. This creates the possibility of different threads invoking the start and end methods.

If the application server allows multiple threads to use a single XAResource object and the associated connection to the resource manager, the application server must ensure that only one transaction context is associated with the resource at any point of time. Thus the XAResource interface requires the resource managers to support the two-phase commit protocol from any thread context.

3.2.5. Transaction association

A transaction is associated with a transactional resource via the start method and disassociated from the resource via the end method. The resource adapter internally maintains an association between the resource connection object and the XAResource object. At any given time, a connection is associated with zero or one transaction. JTA does not support nestedtransactions, so attempting to invoke the start method on a thread that is already associated with a transaction is an error.

The transaction manager can Interleave multiple transaction contexts using the same resource, as long as methods start and end are invoked properly for each transaction context switch. Each time the resource is used with a different transaction, the method end must be invoked for the previous transaction that was associated with the resource, and method start must be invoked for the current transaction context.

3.2.6. Externally controlled connections

For a transactional application whose transaction states are managed by an application server, its resources must also be managed by the application server so that transaction association is performed properly. If an application is associated with a transaction, the application must not perform transactional work through the connection without having the connection’s resource object already associated with the global transaction. The application server must ensure that the XAResource object in use is associated with the transaction, by invoking the Transaction.enlistResource method.

If a server-side transactional application retains its database connection across multiple client requests, the application server must ensure that before dispatching a client request to the application thread, the resource is enlisted with the application’s current transaction context. This implies that the application server manages the connection resource usage status across multiple method invocations.

3.2.7. Resource sharing

When the same transactional resource is used to interleave multiple transactions, the application server must ensure that only one transaction is enlisted with the resource at any given time. To initiate the transaction commit process, the transaction manager is allowed to use any of the resource objects connected to the same resource manager instance. The resource object used for the two-phase commit protocol does not need to have been involved with the transaction being completed.

The resource adapter must be able to handle multiple threads invoking the XAResource methods concurrently for transaction commit processing. This is illustrated in Resource sharing example .

Example 2. Resource sharing example
XAResource xares = r1.getXAResource();

xares.

start(xid1); // associate xid1 to the connection

..
        xares.

end(xid1); // disassociate xid1 to the connection
..
        xares.

start(xid2); // associate xid2 to the connection
..
// While the connection is associated with xid2,
// the TM starts the commit process for xid1
status =xares.

prepare(xid1);
..
        xares.

commit(xid1, false);      

A transactional resource r1. Global transaction xid1 is started and ended with r1. Then a different global transaction xid2 is associated with r1. Meanwhile, the transaction manager may start the two phase commit process for xid1 using r1 or any other transactional resource connected to the same resource manager. The resource adapter needs to allow the commit process to be executed while the resource is currently associated with a different global transaction.

3.2.8. Local and global transactions

The resource adapter must support the usage of both local and global transactions within the same transactional connection. Local transactions are started and coordinated by the resource manager internally. The XAResource interface is not used for local transactions. When using the same connection to perform both local and global transactions, the following rules apply:

  • The local transaction must be committed or rolled back before a global transaction is started in the connection.

  • The global transaction must be disassociated from the connection before any local transaction is started.

3.2.9. Transaction timeouts

You can associate timeout values with transactions in order to control their lifetimes. If the timeout value elapses before a transaction terminates, by committing or rolling back, the transaction system rolls it back. The XAResource interface supports a setTransactionTimeout operation, which allows the timeout associated with the current transaction to be propagated to the resource manager and if supported, overrides any default timeout associated with the resource manager. Overriding the timeout can be useful when long-running transactions may have lifetimes that would exceed the default, and using the default timeout would cause the resource manager to roll back before the transaction terminates, and cause the transaction to roll back as well.

If You do not explicitly set a timeout value for a transaction, or you use a value of 0, an implementation-specific default value may be used. In Narayana, property value CoordinatorEnvironmentBean.defaultTimeout represents this implementation-specific default, in seconds. The default value is 60 seconds. A value of 0 disables default transaction timeouts.

Unfortunately, imposing the same timeout as the transaction on a resource manager is not always appropriate. One example is that your business rules may require you to have control over the lifetimes on resource managers without allowing that control to be passed to some external entity. Narayana supports an all-or-nothing approach to whether or not method setTransactionTimeout is called on XAResource instances.

If the JTAEnvironmentBean.xaTransactionTimeoutEnabled property is set to true, which is the default, it is called on all instances. Otherwise, use the setXATransactionTimeoutEnabled method of com.arjuna.ats.jta.common.Configuration .

3.2.10. Dynamic registration

Dynamic registration is not supported in XAResource. There are two reasons this makes sense.

  • In the Java component-based application server environment, connections to the resource manager are acquired dynamically when the application explicitly requests a connection. These resources are enlisted with the transaction manager on an as-needed basis.

  • If a resource manager needs to dynamically register its work to the global transaction, you can implement this at the resource adapter level via a private interface between the resource adapter and the underlying resource manager.

3.3. General Transaction Issues

3.3.1. Advanced transaction issues with ArjunaCore

Atomic actions (transactions) can be used by both application programmers and class developers. Thus entire operations (or parts of operations) can be made atomic as required by the semantics of a particular operation. This chapter will describe some of the more subtle issues involved with using transactions in general and ArjunaCore in particular.

Note: in the past ArjunaCore was also referred to as TxCore.

Checking transactions

In a multi-threaded application, multiple threads may be associated with a transaction during its lifetime, sharing the context. In addition, it is possible that 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 is terminated. By default, ArjunaCore will issue a warning if a thread terminates a transaction when other threads are still active within it. However, it will allow the transaction termination to continue.

Other solutions to this problem are possible. One example would be to block the thread which is terminating the transaction until all other threads have disassociated themselves from the transaction context. Therefore, ArjunaCore provides the com.arjuna.ats.arjuna.coordinator.CheckedAction class, which allows the thread or transaction termination policy to be overridden. Each transaction has an instance of this class associated with it, and application programmers can provide their own implementations on a per transaction basis.

Class CheckedAction
public class CheckedAction {
    public synchronized void check(boolean isCommit, Uid actUid,
                                   Hashtable list);
};

When a thread attempts to terminate the transaction and there are active threads within it, the system will invoke 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 will continue. Obviously the state of the transaction at this point may be different from that when check was called, e.g., the transaction may subsequently have been committed.

A CheckedAction instance is created for each transaction. As mentioned above, the default implementation simply issues warnings in the presence of multiple threads active on the transaction when it is terminated. However, a different instance can be provided to each transaction in one of the following ways:

  • Use the setCheckedAction method on the BasicAction instance.

  • Define an implementation of the CheckedActionFactory interface, which has a single method getCheckedAction (final Uid`txId, final String`actionType) that returns a CheckedAction. The factory class name can then be provided to the Transaction Service at runtime by setting the CoordinatorEnvironmentBean.checkedActionFactory property.

Gathering statistics

By default, the Transaction Service does not maintain any history information about transactions. However, by setting the CoordinatorEnvironmentBean.enableStatistics property variable to YES, the transaction service will maintain information about the number of transactions created, and their outcomes. This information can be obtained during the execution of a transactional application via the com.arjuna.ats.arjuna.coordinator.TxStats class.

Class TxStats
public class TxStats {
    /**
     * @return the number of transactions (top-level and nested) created so far.
     */

    public static int numberOfTransactions();

    /**
     * @return the number of nested (sub) transactions created so far.
     * <p>
     * <p>
     * public static int numberOfNestedTransactions();
     * <p>
     * /**
     * @return the number of transactions which have terminated with heuristic
     * outcomes.
     */

    public static int numberOfHeuristics();

    /**
     * @return the number of committed transactions.
     */

    public static int numberOfCommittedTransactions();

    /**
     * @return the total number of transactions which have rolled back.
     */

    public static int numberOfAbortedTransactions();

    /**
     * @return total number of inflight (active) transactions.
     */

    public static int numberOfInflightTransactions();

    /**
     * @return total number of transactions rolled back due to timeout.
     */

    public static int numberOfTimedOutTransactions();

    /**
     * @return the number of transactions rolled back by the application.
     */

    public static int numberOfApplicationRollbacks();

    /**
     * @return number of transactions rolled back by participants.
     */

    public static int numberOfResourceRollbacks();

    /**
     * Print the current information.
     */

    public static void printStatus(java.io.PrintWriter pw);
}

The class ActionManager gives further information about specific active transactions through the classes getTimeAdded, which returns the time (in milliseconds) when the transaction was created, and inflightTransactions, which returns the list of currently active transactions.

Asynchronously committing a transaction

By default, the Transaction Service executes the commit protocol of a top-level transaction in a synchronous manner. All registered resources will be told to prepare in order by a single thread, and then they will be told to commit or rollback. This has several possible disadvantages:

  • In the case of many registered resources, the prepare operating can logically be invoked in parallel on each resource. The disadvantage is that if an "early" resource in the list of registered resource forces a rollback during prepare, possibly many prepare operations will have been made needlessly.

  • In the case where heuristic reporting is not required by the application, the second phase of the commit protocol can be done asynchronously, since its success or failure is not important.

Therefore, Narayana provides runtime options to enable possible threading optimisations. By setting the CoordinatorEnvironmentBean.asyncPrepare environment variable to YES, during the prepare phase a separate thread will be created for each registered participant within the transaction. By setting CoordinatorEnvironmentBean.asyncCommit to YES, a separate thread will be created to complete the second phase of the transaction if knowledge about heuristics outcomes is not required.

Transaction Logs

Narayana supports a number of different transaction log implementations. They are outlined below.

The ActionStore

This is the original version of the transaction log as provided in prior releases. It is simple but slow. Each transaction has an instance of its own log and they are all written to the same location in the file system

The HashedActionStore

This implementation is based on the ActionStore but the individual logs are striped across a number of sub-directories to improve performance. Check the Configuration Options table for how to configure the HashedActionStore.

LogStore

This implementation is based on a traditional transaction log. All transaction states within the same process (VM instance) are written to the same log (file), which is an append-only entity. When transaction data would normally be deleted, e.g., at the end of the transaction, a delete record is added to the log instead. Therefore, the log just keeps growing. Periodically a thread runs to prune the log of entries that have been deleted.

A log is initially given a maximum capacity beyond which it cannot grow. Once this is reached the system will create a new log for transactions that could not be accommodated in the original log. The new log and the old log are pruned as usual. During the normal execution of the transaction system there may be an arbitrary number of log instances. These should be garbage collected by the system (or the recovery sub-system) eventually.

Check the Configuration Options table for how to configure the LogStore.

3.4. Tools

This chapter describes the various tools for managing transactions.

3.4.1. ObjectStore command-line browsers and editors

There are currently three command-line editors for manipulating the ObjectStore. These tools are used to manipulate the lists of heuristic participants maintained by a transaction log. They allow a heuristic participant to be moved from that list back to the list of prepared participants so that transaction recovery may attempt to resolve them automatically.

Browse and Manage Transactions Using an Application Server

The WildFly Application Server provides a command-line based Management CLI which supports the ability to browse and manipulate transaction records. This functionality is provided by the interaction between the Transaction Manager ™ and the Management API of the application server. To start the CLI on a non-windows based OS type the following command in application server install directory:

./bin/jboss-cli.sh --connect controller=IP_ADDRESS

On Windows platforms use the jboss-cli.bat script

The transaction manager stores information about each active transaction, and the participants involved in the transaction, in a persistent storage area called the object store . The Management API exposes the object store as a resource called the log-store . An API operation called probe reads the transaction logs and creates a node in the management model corresponding to each log. These nodes can be inspected using the CLI. Transaction logs are transient, so these nodes quickly become out of date but you can call the probe command manually whenever you need to refresh the log-store.

Refresh the Log Store

This command refreshes the Log Store for server groups which use the profile default in a managed domain. For a standalone server, remove the profile=default from the command.

/subsystem=transactions/log-store=log-store/:probe
View All Prepared Transactions

To view all prepared transactions, first refresh the log store (see Refresh the Log Store ), then run the following command, which functions similarly to a filesystem ls command.

ls /subsystem=transactions/log-store=log-store/transactions

Each transaction is shown, along with its unique identifier. Individual operations can be run against an individual transaction (see Manage a Transaction).

Manage a Transaction
View a transaction’s attributes.

To view information about a transaction, such as its JNDI name, EIS product name and version, or its status, use the :read-resource CLI command.

/subsystem=transactions/log-store=log-store/transactions=0\:ffff7f000001\:-b66efc2\:4f9e6f8f\:9:read-resource
View the participants of a transaction.

Each transaction log contains a child element called participants. Use the read-resource CLI command on this element to see the participants of the transaction. Participants are identified by their JNDI names (or some other unique identifier if the JNDI name is not available).

/subsystem=transactions/log-store=log-store/transactions=0\:ffff7f000001\:-b66efc2\:4f9e6f8f\:9/participants=java\:\/JmsXA:read-resource

The result may look similar to this:

{
   "outcome" => "success",
   "result" => {
       "eis-product-name" => "HornetQ",
       "eis-product-version" => "2.0",
       "jndi-name" => "java:/JmsXA",
       "status" => "HEURISTIC_HAZARD",
       "type" => "/StateManager/AbstractRecord/XAResourceRecord"
   }
}

The outcome status shown here is in a HEURISTIC_HAZARD state and is eligible for recovery. Refer to [recover_transaction_participant] for more details.

Delete a transaction.

Each transaction log supports a :delete operation, to delete the transaction log representing the transaction.

/subsystem=transactions/log-store=log-store/transactions=0\:ffff7f000001\:-b66efc2\:4f9e6f8f\:9:delete

If failures occur, transaction logs may remain in the object store until crash recovery facilities have resolved the transactions they represent. Therefore, it is very important that the contents of the object store are not deleted inadvertently, as this will make it impossible to resolve in-doubt transactions. In addition, if multiple users share the same object store, they must understand that it is not an exclusive resource, and not delete transaction logs without careful consideration.

Delete a transaction participant.

Each transaction log participant supports a :delete operation which will delete the participant log that represents the participant:

/subsystem=transactions/log-store=log-store/transactions=0\:ffff7f000001\:-b66efc2\:4f9e6f8f\:9/participants=0\:ffff7f000001\:-f30b80c\:58480e0a\:2c:delete

Normally you would leave participant log management to the transaction log that owns it or to the recovery system. However, this delete operation for participant logs is provided for those cases where you know it is safe to do so and, in the case of heuristically completed XA resources, you wish to trigger a forget call so that the XA resource vendors' logs are cleaned correctly. By default, if this forget call fails then the delete operation will still succeed. The system administrator may override this behaviour by setting a system property:

ObjectStoreEnvironmentBean.ignoreMBeanHeuristics

to the value false.

Recover a transaction participant.

Each transaction participant log may support recovery via the :recover CLI command if it is in a heuristic state.

Recovery of Heuristic Transactions and Participants

  • If the transaction participant’s status is HEURISTIC or HEURISTIC_HAZARD or HEURISTIC_MIXED then the recover operation changes the state to PREPARE and triggers a recovery attempt by replaying the commit operation. If successful, the participant is removed from the transaction log. You can verify this by re-running the :probe operation on the log-store and checking that the participant is no longer listed. If this is the last participant, the transaction is also deleted.

    Refresh the status of a transaction which needs recovery.

    If a transaction needs recovery, you can use the :refresh CLI command to be sure it still requires recovery, before attempting the recovery.

    /subsystem=transactions/log-store=log-store/transactions=0\:ffff7f000001\:-b66efc2\:4f9e6f8f\:9:refresh
Browse and Manage Transactions Using JMX

Transaction logs may also be managed using JMX. Each transaction log record is instrumented as an MBean. Any JMX client may be used to manage logs using this mechanism.

The JMX MBean for the object store contains one method and one attribute. The probe operation scans the object store creating JMX MBeans for the various log records contained in the store. The default behaviour is to only create MBeans for particular record types. If there is a need to view everything in the store then set the ExposeAllRecordsAsMBeans attribute to true Note that transaction logs are transient so these beans quickly become out of date and will not be refreshed automatically so you must invoke the probe operation again to get the current up to date list of MBeans.

MBeans can be queried using the standard JMX query mechanism. ObjectStore Object Names are in the format:

domain:key-property-list

where domain is jboss.jta and key-property-list is a comma separated list of key=value pairs.

Table 4. Object Name Keys
Name Meaning

itype

The transaction record type

uid

The unique id of the transaction record

puid

The unique id of a participant record

Transaction record
jboss.jta:type=ObjectStore,itype=StateManager/BasicAction/TwoPhaseCoordinator/ AtomicAction,uid=0_ffff7f000001_-3a612f5d_53f63052_39
A participant record within a transaction
jboss.jta:type=ObjectStore,itype=StateManager/BasicAction/TwoPhaseCoordinator/ AtomicAction,uid=0_ffff7f000001_-3a612f5d_53f63052_39,puid= 0_ffff7f000001_-3a612f5d_53f63052_3c
Manage a Transaction
View a transaction’s attributes.

To view information about a transaction or a transaction participant, such as its JNDI name, EIS product name and version, or its status, use a JMX client or alternatively use the JMX api:

// obtain connection to the MBean server
MBeanServer mbs = ...

// query all ObjectStore MBean instances
ObjectName on = new ObjectName("jboss.jta:type=ObjectStore,*", null);
Set<ObjectInstance> transactions = mbs.queryMBeans(on);

// lookup the attribute names of an ObjectInstance
MBeanInfo info = mbs.getMBeanInfo( oi.getObjectName() );
MBeanAttributeInfo[] attributeArray = info.getAttributes();

// find the values of the attributes of an ObjectInstance
AttributeList attributes = mbs.getAttributes(oi.getObjectName(), attributeNames);
View the participants of a transaction.

A transaction log may contain one or more participants which can be viewed as MBeans using a JMX client or programmatically as follows:

ObjectInstance transaction = ... //
ObjectName on = transaction.getObjectName();
String participantQuery =  on + ",puid=*";
Set<bjectInstance> participants = mbs.queryMBeans(new ObjectName(participantQuery), null)

For example the attributes of an XAResource record might look similar to:

"eis-product-name" => "HornetQ",
"eis-product-version" => "2.0",
"jndi-name" => "java:/JmsXA",
"status" => "HEURISTIC_HAZARD",
"type" => "/StateManager/AbstractRecord/XAResourceRecord"

The status attribute shown in this example is in a HEURISTIC_HAZARD state and is eligible for recovery. Refer to [recover_transaction_participant_jmx] for more details.

Delete a transaction or transaction participant.

MBeans for transaction logs and participants contain a remove operation. Invoke this MBean operation to remove the record from the ObjectStore.

If failures occur, transaction logs may remain in the object store until crash recovery facilities have resolved the transactions they represent. Therefore, it is very important that the contents of the object store are not deleted inadvertently, as this will make it impossible to resolve in-doubt transactions. In addition, if multiple users share the same object store, they must understand that it is not an exclusive resource,

Normally you would leave participant log management to the transaction log that owns it or to the recovery system. However, this remove operation for participant logs is provided for those cases where you know it is safe to do so and, in the case of heuristically completed XA resources, you wish to trigger a forget call so that the XA resource vendors' logs are cleaned correctly. By default, if this forget call fails then the delete operation will still succeed. The system administrator may override this behaviour by setting a system property:

ObjectStoreEnvironmentBean.ignoreMBeanHeuristics

to the value false.

Recover a transaction.

Transaction participants support recovery via the clearHeuristic operation.

  • Recovery of Heuristic Participants

    • If the transaction participant’s status is HEURISTIC or HEURISTIC_HAZARD or HEURISTIC_MIXED then the clearHeuristic operation changes the state to PREPARED.

    • Subsequent runs of the recovery manager (periodic recovery) will try to replay the commit operation. If successful, the participant is removed from the transaction log.

    • You can verify the transaction is completed by re-running the probe operation on the ObjectStore MBean. If this is the last participant, the transaction will have been also deleted.

LogEditor

The LogEditor tool is started by executing the following command:

java -Dcom.arjuna.ats.arjuna.common.ObjectStoreEnvironmentBean.objectStoreDir="path to file based object store" com.arjuna.ats.arjuna.tools.log.LogBrowser

This command works with the file based object store. If you want to work with the Hornetq store instead then you need to specify a different property for the location of the log store and you also need to explicity provide the class name of the Hornetq Object Store:

java -Dcom.arjuna.ats.internal.arjuna.objectstore.hornetq.HornetqJournalEnvironmentBean.storeDir="directory path" -Dcom.arjuna.ats.arjuna.common.ObjectStoreEnvironmentBean.objectStoreType="com.arjuna.ats.internal.arjuna.objectstore.hornetq.HornetqObjectStoreAdaptor"

The tool supports the following options that can be provided on the command-line:

Table 5. LogEditor Options
Option Description

-tx id

Specifies the transaction log to work on.

-type name

The transaction type to work on.

-dump

Print out the contents of the log identified by the other options.

-forget index

Move the specified target from the heuristic list to the prepared list.

-help

Print out the list of commands and options.

LogBrowser

The LogBrowser, invoked by calling com.arjuna.ats.arjuna.tools.log.LogBrowser, is similar to the LogEditor, but allows multiple log instances to be manipulated. It presents a shell-like interface, with the following options:

Table 6. LogBrowserOptions
Option Description

ls [type]

List the logs for the specified type. If no type is specified, the editor must already be attached to the transaction type.

select [type]

Browse a specific transaction type. If already attached to a transaction type, you are detached from that type first.

attach log

Attach the console to the specified transaction log. If you are attached to another log, the command will fail.

detach

Detach the console from the current log.

forget pid

Move the specified heuristic participant back to the prepared list. The console must be attached.

delete pid

Delete the specified heuristic participant. The console must be attached.

types

List the supported transaction types.

quit

Exit the console tool.

help

Print out the supported commands.

3.4.2. GUI Based Tools

Embedded Console

Transaction management is integrated into the WildFly Application Server.

Performance Graphing

There is a transaction statistics graphing tool which can run standalone or inside a jconsole tab (jconsole is a tool for managing JVMs and is distributed with the reference JDK):

The tool depends on the JFree graphing library. Download and unpack orson from http://www.jfree.org/orson. Set the env variable ORSON_HOME to the directory where you plan to unpack the downloaded zip. If you intend to use the tool with jconsole you will also need to put the JDK tools and jconsole jars on the classpath:

export CLASSPATH="$JDK_HOME/lib/tools.jar:$JDK_HOME/lib/jconsole.jar:$ORSON_HOME/orson-0.5.0.jar:$ORSON_HOME/lib/jfreechart-1.0.6.jar:$ORSON_HOME/lib/jcommon-1.0.10.jar:$INSTALL_ROOT/lib/narayana-jta.jar>"
Standalone Usage
java com.arjuna.ats.arjuna.tools.stats.TxPerfGraph

(note that standalone usage does not require the JDK tools and jconsole jars)

Usage with jconsole
jconsole -J-Djava.class.path="$CLASSPATH" -pluginpath $INSTALL_ROOT/lib/narayana-jta.jar

This command will launch the jconsole GUI in which there will be an extra tab for displaying transaction performance statistics.

3.4.3. View Transaction Statistics using an Application Server

If you are using the Transaction Manager ™ inside the WildFly Application Server and if the TM statistics are enabled, then you can view statistics about the TM and transaction subsystem using tools provide by the application server.

You can view statistics either via the web-based Management Console or the command-line Management CLI. In the web-based Management Console, Transaction statistics are available via Runtime  Subsystem Metrics  Transactions. Transaction statistics are available for each server in a managed domain, as well. You can specify the server in the Server selection box at the top left.

The following table shows each available statistic, its description, and the CLI command to view the statistic.

Table 7. Transaction Subsystem Statistics
Statistic Description CLI Command

Total

The total number of transactions processed by the TM on this server.

/subsystem=transactions/:read-attribute(name=number-of-transactions,include-defaults=true)

Committed

The number of committed transactions processed by the TM on this server.

/subsystem=transactions/:read-attribute(name=number-of-committed-transactions,include-defaults=true)

Aborted

The number of aborted transactions processed by the TM on this server.

/subsystem=transactions/:read-attribute(name=number-of-aborted-transactions,include-defaults=true)

Timed Out

The number of timed out transactions processed by the TM on this server.

/subsystem=transactions/:read-attribute(name=number-of-timed-out-transactions,include-defaults=true)

Heuristics

Not available in the Management Console. Number of transactions in a heuristic state.

/subsystem=transactions/:read-attribute(name=number-of-heuristics,include-defaults=true)

In-Flight Transactions

Not available in the Management Console. Number of transactions which have begun but not yet terminated.

/subsystem=transactions/:read-attribute(name=number-of-inflight-transactions,include-defaults=true)

Failure Origin - Applications

The number of failed transactions whose failure origin was an application.

/subsystem=transactions/:read-attribute(name=number-of-application-rollbacks,include-defaults=true)

Failure Origin - Resources

The number of failed transactions whose failure origin was a resource.

/subsystem=transactions/:read-attribute(name=number-of-resource-rollbacks,include-defaults=true)

3.5. Configuration options

3.5.1. Loading a configuration

Each module of the system contains a module propertyManager class, which provides static getter methods for one or more name EnvironmentBean classes. An example is com.arjuna.ats.arjuna.commmon.arjPropertyManager. These environment beans are standard JavaBean containing properties for each configuration option in the system. Typical usage is of the form:

int defaultTimeout = arjPropertyManager.getCoordinatorEnvironmentBean().getDefaultTimeout();

These beans are singletons, instantiated upon first access, using the following algorithm.

Procedure: Algorithm for environment bean instantiation
  1. The properties are loaded and populated from a properties file named and located as follows:

    1. If the properties file name property com.arjuna.ats.arjuna.common.propertiesFile is set, its value is used as the file name.

    2. If not, the default file name jbossts-properties.xml is used. The definition of the used value can be found at Narayana distribution jar file under META-INF/MANIFEST.MF at property arjuna-properties-file.

  2. The file thus named is searched for by, in order

    1. absolute path

    2. user.dir

    3. user.home

    4. java.home

    5. directories contained on the classpath

    6. a default file embedded in the product .jar file

      if you use Narayana dependency org.jboss.narayana.jts:narayana-jts-idlj you can check the default properties settings in the Narayana repository at github.

  3. The file is treated as being of standard java.util.Properties xml format and loaded accordingly. The entry names are of the form EnvironmentBeanClass.propertyName.

    An example is <entrykey="CoordinatorEnvironmentBean.commitOnePhase">YES</entry>

    In specific cases when you want to set properties on configuration beans other that the default bean instances the form is EnvironmentBeanClass.<storeType>.propertyName.

    An example is <entry key="ObjectStoreEnvironmentBean.communicationStore.objectStoreType"> com.arjuna.ats.internal.arjuna.objectstore.VolatileStore</entry>

    Valid values for Boolean properties are case-insensitive, and may be one of NO/YES, FALSE/TRUE, OFF/ON.

    In the case of properties that take multiple values, they are white-space-delimited.

    Example recovery modules of Recovery Environment Bean
    <entry key="RecoveryEnvironmentBean.recoveryModuleClassNames">
        com.arjuna.ats.internal.arjuna.recovery.AtomicActionRecoveryModule
        com.arjuna.ats.internal.txoj.recovery.TORecoveryModule
    </entry>
  4. After the file is loaded, it is cached and is not re-read until the JVM is restarted. Changes to the properties file require a restart in order to take effect.

  5. After the properties are loaded, the EnvironmentBean is then inspected and, for each field, if the properties contains a matching key in the search order as follows, the setter method for that field is invoked with the value from the properties, or the system properties if different.

    • Fully.Qualified.NameEnvironmentBean.propertyName

      for example com.arjuna.ats.arjuna.common.CoordinatorEnvironmentBean.commitOnePhase

    • NameEnvironmentBean.propertyName (this is the preferred form used in the properties file)

      for example CoordinatorEnvironmentBean.commitOnePhase

    • the old com.arjuna…​ properties key defined at bean by annnotations @PropertyPrefix or @FullPropertyName (deprecated, for backwards compatibility only).

      for example com.arjuna.ats.arjuna.coordinator.commitOnePhase

  6. The bean is then returned to the caller, which may further override values by calling setter methods.

The implementation reads most bean properties only once, as the consuming component or class is instantiated. This usually happens the first time a transaction is run. As a result, calling setter methods to change the value of bean properties while the system is running typically has no effect, unless it is done prior to any use of the transaction system. Altered bean properties are not persisted back to the properties file.

You can configure the system using a bean wiring system such as JBoss Microcontainer or Spring. Take care when instantiating beans, to obtain the singleton via the static getter (factory) method on the module property manager. Using a new bean instantiated with the default constructor is ineffective, since it is not possible to pass this configured bean back to the property management system.

3.5.2. ArjunaCore Options

The canonical reference for configuration options is the Javadoc of the various EnvironmentBean classes. For ArjunaCore these are:

  • com.arjuna.common.internal.util.logging.LoggingEnvironmentBean

  • com.arjuna.common.internal.util.logging.basic.BasicLogEnvironmentBean

  • com.arjuna.ats.txoj.common.TxojEnvironmentBean

  • com.arjuna.ats.arjuna.common.CoordinatorEnvironmentBean

  • com.arjuna.ats.arjuna.common.ObjectStoreEnvironmentBean

  • com.arjuna.ats.arjuna.common.RecoveryEnvironmentBean

  • com.arjuna.ats.arjuna.common.CoreEnvironmentBean

  • com.arjuna.ats.internal.arjuna.objectstore.hornetq.HornetqJournalEnvironmentBean

3.5.3. Narayana JTA Configuration options

The canonical reference for configuration options is the javadoc of the various EnvironmentBean classes. For Narayana JTA, these classes are the ones provided by ArjunaCore, as well as:

  • com.arjuna.ats.jdbc.common.JDBCEnvironmentBean

  • com.arjuna.ats.jta.common.JTAEnvironmentBean

3.5.4. Narayana JTS Options

The canonical reference for configuration options is the javadoc of the various EnvironmentBean classes. For Narayana JTS these are the ones provided by ArjunaCore, as well as:

  • com.arjuna.orbportability.common.OrbPortabilityEnvironmentBean

  • com.arjuna.ats.jts.common.JTSEnvironmentBean

3.5.5. Narayana WS-AT/WS-BA Options

For Narayana WebService transaction protocols these are the ones provided by ArjunaCore, as well as:

  • org.jboss.jbossts.xts.environment.WSCEnvironmentBean

  • org.jboss.jbossts.xts.environment.WSCFEnvironmentBean

  • org.jboss.jbossts.xts.environment.WSTEnvironmentBean

  • org.jboss.jbossts.xts.environment.XTSEnvironmentBean

  • org.jboss.jbossts.xts.environment.RecoveryEnvironmentBean

3.6. Important Log Messages

The transaction manager can generate a lot of logging information when configured to log in trace level. Here is a list of some of the log messages to check for.

3.6.1. Transaction State Change

The following table

Transaction Begin

When a transaction begins the following code is executed: ` com.arjuna.ats.arjuna.coordinator.BasicAction::Begin:1342

tsLogger.logger.trace("BasicAction::Begin() for action-id "+ get_uid()); `

Transaction Commit

When a transaction commits the following code is executed: ` com.arjuna.ats.arjuna.coordinator.BasicAction::End:1342

tsLogger.logger.trace("BasicAction::End() for action-id "+ get_uid()); `

Transaction Rollback

When a transaction commits the following code is executed: ` com.arjuna.ats.arjuna.coordinator.BasicAction::Abort:1575

tsLogger.logger.trace("BasicAction::Abort() for action-id "+ get_uid()); `

Transaction Timeout

When a transaction times out the following code is executed: ` com.arjuna.ats.arjuna.coordinator.TransactionReaper::doCancellations:349

tsLogger.logger.trace("Reaper Worker " + Thread.currentThread() + " attempting to cancel " + e._control.get_uid()); ` You will then see the same thread rolling back the transaction as shown above

There are many more logging messages to check for, above are those that we are often asked about.

3.6.2. Multi cause log message

The following table shows some log messages that you may see with an explanation of alternate reasons

INFO [com.arjuna.ats.arjuna] ObjectStore record was deleted during restoration, users should not deleted records manually

If you manually deleted a transaction log then this applies to you - you deleted a transaction that was in flight and so may have caused a data integrity issue in so far as one of the resources may be committed and without the log you will not be able to infer this.

If a transaction is committed at the same time as a resource adapter or remote server attempts recovery then you may see the message in the log due to intentional but unavoidable interaction between distributed transaction managers and the local recovery manager.

The log message will indicate the path of the removed file something like: /ShadowNoFileLockStore/defaultStore/StateManager/BasicAction/TwoPhaseCoordinator/AtomicAction/SubordinateAtomicAction/JCA/: java.io.FileNotFoundException: /ShadowNoFileLockStore/defaultStore/StateManager/BasicAction/TwoPhaseCoordinator/AtomicAction/SubordinateAtomicAction/JCA/ (No such file or directory)

There are many more logging messages to check for, above are those that we are often asked about.

3.7. Troubleshooting

This chapter covers issues that you may hit when developing applications with Narayana.

3.7.1. WS-BA Participant-Completion Race Condition

The WS-BA participant-completion protocol has a benign race condition that, in unusual circumstances, can cause some Business Activities to be cancelled that would have otherwise been able to close. This is safe as no inconsistency arrises, but it can be annoying for users. This section explains why this can happen, under what conditions, and what you can do to tolerate it.

What’s happening, in a nutshell

Imagine a scenario where the client begins a business activity and then invokes a Web service. If the Web service uses participant completion, it will notify the coordinator when it has completed its work and then return control to the client. This notification is asynchronous, so it’s possible that the client will then ask the coordinator to close the activity before the coordinator processes (or even receives) the completed notification from the participant. In this situation the coordinator will cancel the activity as not all participants (from its perspective) have completed their work. As a result all completed participants are compensated (including, eventually, the participant with the late 'completed' notification) and the client receives a TransactionRolledBackException.

When is it most likely to happen?

Typically this happens when the client, coordinator and participant are running inside the same VM. This scenario is unlikely to happen in production, but can happen regularly during development where a single VM is used to keep things simple.

How do I know if this is affecting my application?

If the client is occasionally receiving a TransactionRolledbackException when calling UserBusinessActivity#close(), but none of the machines involved in running the transaction have crashed, you could be affected by this. Especially if you are running the client, coordinator and participant(s) in the same server.

The following log message will help you identify this issue:

Example Environment Bean
WARN [com.arjuna.mw.wstx] (TaskWorker-2) ARJUNA045062: Coordinator cancelled the activity

This is only an indication that you are seeing this issue as the coordinator can elect to cancel the activity for other reasons. For example, network problems might mean the coordinator cannot tell the web service to close the activity.

Why can’t it be avoided?

For the protocol to avoid this issue, it would need to make the complete message synchronous, throttling throughput by slowing down both the participant and coordinator and holding sockets open for longer.

What can the application do to tolerate this?

A real, distributed deployment will rarely see this problem because communication latency between client, participant and coordinator will dominate the race condition. Even if it does happen your application should tolerate it. Transaction rollbacks and activity cancelations are inevitable in a distributed environment and can happen for many reasons. When handling TransactionRolledBack exceptions you can either retry the Transaction/Activity or notify the caller of the failure. What you choose to do will depend on the requirements of your application.

Why exactly does this happen?

First consider the following client code:

Client Code Example
UserBusinessActivity uba = UserBusinessActivityFactory.userBusinessActivity();
uba.begin();
myWebServiceClient.invoke();
uba.close();

The client code is very simple, it just begins a business activity, invokes a Web service and then closes the business activity. The Web service uses the Participant-Completion protocol and so notifies the coordinator of completion just before returning control to the client.

Here’s a diagram showing the pertinent message exchanges that occur under a normal situation.

development guide fig pcp race success
Figure 10. Successful close of activity

The messages are numbered to indicate the order in which they are sent:

  • 1.request. This represents the application request made by the client.

  • 2.completed. After the participant has completed its work, it notifies the coordinator that it has completed.

  • 3.response. This represents the response to the client’s application request.

  • 4.close. The client notifies the coordinator that it wishes to close the activity. It then waits for a closed or failure response from the coordinator.

  • 5a.close and 5b.closed. The coordinator has processed the 2.completed message so can close the activity. It starts by sending the close message to the participant and waits for the closed response as confirmation. These two messages are asynchronous.

  • 6.closed. The coordinator now has all closed acknowledgments so notifies the client that the activity successfully closed.

Messages '2.completed' and '4.close' are asynchronous (or 'one way' in Web services parlance) so effectively, there is a race condition with the following competing parties:

  • Party 1. The completed message 2.completed.

  • Party 2. The response 3.response followed by 4.close.

When running in the same VM, or on a low latency network, 3.response will be sent very quickly. This is because it is simply travelling on the HTTP response over an already open socket. This just leaves messages 2.completed and 4.close which will take much longer relative to 3.response. To understand this, lets take a look at what happens when an asynchronous Web service call is made:

  1. The client sends the message to the Web service.

  2. The server-side SOAP stack uses an existing thread from a pool dedicated to receiving SOAP messages.

  3. As the service is asynchronous, the message will be passed to another thread to be processed.

  4. The receiving thread will now return the HTTP response.

The race condition occurs because steps 1-3 can happen relatively quickly in a single VM, and thus it’s likely that both messages 2 and 4, will be waiting to be processed at the same time. The order in which they are processed is dependent on the implementation of the thread pool and is also at the mercy of thread scheduling in the VM, so it’s possible that either could be processed first.

This race condition is much less likely to happen in a distributed environment as the network costs will be significantly higher. As a result message 3.response will take long enough to send, so as to give message 2.completed enough of a head start. But it is still possible so the client application must be coded defensively to catch and handle a TransactionRollbackException. The client code ought to be doing this anyway to deal with server crashes.

The following diagram shows what messages are exchanged when the race condition occurs. Notice that the activity ends in a consistent state.

development guide fig pcp race failure
Figure 11. Failure to close the activity

Messages 1-3 are omitted from the following explanation as they are the same as in the success case.

  • 4.close. This message is processed by the coordinator before message 2.completed

  • 5a.cancel. The coordinator has not yet processed the 2.completed message so cannot close the activity. The coordinator then sends a 'cancel' message to the participant as it thinks it has not yet completed. This message and subsequent retires, are dropped by the participant as they are not valid for a completed participant.

  • 5b.compensate/5c.compensated. After one or more unacknowledged cancel messages, the coordinator switches to sending compensate messages which will cause the participant to compensate the work. The participant acknowledges with a compensated reply.

  • 6. Transaction rolledback exception. The coordinator notifies the client that the activity failed to close.

As you can see from the steps above, when this race condition arises, any work done by participants is compensated and the client is notified of the outcome. Thus a consistent outcome is achieved.

4. XTS Guide

4.1. Introduction

The XML Transaction Service (XTS) component of Narayana supports the coordination of private and public Web Services in a business transaction. Therefore, to understand XTS, you must be familiar with Web Services, and also understand something about transactions. This chapter introduces XTS and provides a brief overview of the technologies that form the Web Services standard. Additionally, this chapter explores some of the fundamentals of transactioning technology and how it can be applied to Web Services. Much of the content presented in this chapter is detailed throughout this guide. However, only overview information about Web Services is provided. If you are new to creating Web services, please consult your Web Services platform documentation.

Narayana provides the XTS component as a transaction solution for Web Services. Using XTS, business partners can coordinate complex business transactions in a controlled and reliable manner. The XTS API supports a transactional coordination model based on the WS-Coordination, WS-Atomic Transaction, and WS-Business Activity specifications.

Protocols Included in XTS* WS-Coordination (WS-C) is a generic coordination framework developed by IBM, Microsoft and BEA.
  • WS-Atomic Transaction (WS-AT) and WS-Business Activity (WS-BA) together comprise the WS-Transaction (WS-T) transaction protocols that utilize this framework.

Narayana implements versions 1.1, and 1.2 of these three specifications. Version specifications are available from http://www.oasis-open.org/specs/ .

The 1.1, and 1.2 specifications only differ in a small number of details. The rest of this document employs version 1.1 of these specifications when providing explanations and example code. On the few occasions where the modifications required to adapt these to the 1.1 specifications are not obvious, an explanatory note is provided.

Web Services are modular, reusable software components that are created by exposing business functionality through a Web service interface. Web Services communicate directly with other Web Services using standards-based technologies such as SOAP and HTTP. These standards-based communication technologies enable customers, suppliers, and trading partners to access Web Services, independent of hardware operating system, or programming environment. The result is a vastly improved collaboration environment as compared to today’s EDI and business-to-business (B2B) solutions, an environment where businesses can expose their current and future business applications as Web Services that can be easily discovered and accessed by external partners.

Web Services, by themselves, are not fault-tolerant. In fact, some of the reasons that the Web Services model is an attractive development solution are also the same reasons that service-based applications may have drawbacks.

Properties of Web Services
  • Application components that are exposed as Web Services may be owned by third parties, which provides benefits in terms of cost of maintenance, but drawbacks in terms of having exclusive control over their behavior.

  • Web Services are usually remotely located, increasing risk of failure due to increased network travel for invocations.

Applications that have high dependability requirements need a method of minimizing the effects of errors that may occur when an application consumes Web Services. One method of safeguarding against such failures is to interact with an application’s Web Services within the context of a transaction. A transaction is a unit of work which is completed entirely, or in the case of failures is reversed to some agreed consistent state. The goal, in the event of a failure, is normally to appear as if the work had never occurred in the first place. With XTS, transactions can span multiple Web Services, meaning that work performed across multiple enterprises can be managed with transactional support.

4.1.1. Managing service-Based Processes

XTS allows you to create transactions that drive complex business processes, spanning multiple Web Services. Current Web Services standards do not address the requirements for a high-level coordination of services. This is because in today’s Web Services applications, which use single request/response interactions, coordination is typically not a problem. However, for applications that engage multiple services among multiple business partners, coordinating and controlling the resulting interactions is essential. This becomes even more apparent when you realize that you generally have little in the way of formal guarantees when interacting with third-party Web Services.

XTS provides the infrastructure for coordinating services during a business process. By organizing processes as transactions, business partners can collaborate on complex business interactions in a reliable manner, insuring the integrity of their data - usually represented by multiple changes to a database – but without the usual overheads and drawbacks of directly exposing traditional transaction-processing engines directly onto the web. An Evening On the Town demonstrates how an application may manage service-based processes as transactions:

An Evening On the Town

The application in question allows a user to plan a social evening. This application is responsible for reserving a table at a restaurant, and reserving tickets to a show. Both activities are paid for using a credit card. In this example, each service represents exposed Web Services provided by different service providers. XTS is used to envelop the interactions between the theater and restaurant services into a single (potentially) long-running business transaction. The business transaction must insure that seats are reserved both at the restaurant and the theater. If one event fails the user has the ability to decline both events, thus returning both services back to their original state. If both events are successful, the user’s credit card is charged and both seats are booked. As you may expect, the interaction between the services must be controlled in a reliable manner over a period of time. In addition, management must span several third-party services that are remotely deployed.

Without the backing of a transaction, an undesirable outcome may occur. For example, the user credit card may be charged, even if one or both of the bookings fail.

An Evening On the Town describes the situations where XTS excels at supporting business processes across multiple enterprises. This example is further refined throughout this guide, and appears as a standard demonstrator (including source code) with the XTS distribution.

4.1.2. Servlets

The WS-Coordination, WS-Atomic Transaction, and WS-Business Activity protocols are based on one-way interactions of entities rather than traditional synchronous request/response RPC-style interactions. One group of entities, called transaction participants, invoke operations on other entities, such as the transaction coordinator, in order to return responses to requests. The programming model is based on peer-to-peer relationships, with the result that all services, whether they are participants, coordinators or clients, must have an active component that allows them to receive unsolicited messages.

In XTS, the active component is achieved through deployment of JaxWS endpoints. Each XTS endpoint that is reachable through SOAP/XML is published via JaxWS, without developer intevention. The only requirement is that transactional client applications and transactional web services must reside within a domain capable of hosting JaxWS endpoints, such as an application server. WildFly Application Server can provide this functionality.

4.1.3. SOAP

SOAP has emerged as the de facto message format for XML-based communication in the Web Services arena. It is a lightweight protocol that allows the user to define the content of a message and to provide hints as to how recipients should process that message.

4.1.4. Web Services Description Language (WDSL)

Web Services Description Language (WSDL) is an XML-based language used to define Web service interfaces. An application that consumes a Web service parses the service’s WSDL document to discover the location of the service, the operations that the service supports, the protocol bindings the service supports (SOAP, HTTP, etc), and how to access them. For each operation, WSDL describes the format that the client must follow.

4.2. Getting Started

4.2.1. EnableXTS on WildFly Application Server

XTS, which is the Web Services component of Narayana, provides WS-AT and WS-BA support for Web Services hosted on the WildFly Application Server. XTS is available as an optional SubSystem, enabled using the standalone-xts.xml configuration.

Procedure: Starting WildFly Application Server with XTS Enabled
  1. Change to the WildFly Application Server directory:

    cd $JBOSS_HOME

  2. Copy the example XTS configuration into the configurations directory:

    cp docs/examples/configs/standalone-xts.xml standalone/configuration

  3. Start WildFly Application Server, specifying the xts configuration:

    Linux:

    bin/standalone.sh --server-config=standalone-xts.xml

    Windows:

    bin\standalone.bat --server-config=standalone-xts.xml

4.2.2. Working With WS-AT

Creating Client Applications

XTS integrates WS-AT transactions with JTA. To invoke a web service inside a WS-AT transaction, simply start a new JTA transaction and invoke the web service. By default, XTS will create a WS-AT context and pass it with your request. See our quickstarts for an example: WS-AT Multi-Service and WS-AT Multi-Hop

Creating Transactional Web Services

Similarly to the client-side, the service-side is also integrated with JTA. To make your web service WS-AT compliant, annotate your web service class or method with the EJB 3 jakarta.ejb.TransactionAttribute annotation or the JTA jakarta.transaction.Transactional annotation. XTS will automatically translate WS-AT context, received with the request, to JTA. See our quickstarts for an example: WS-AT Multi-Service and WS-AT Multi-Hop

Using Raw XTS API

Sometimes more control is needed over the client and the server applications. Also JTA transactions are not always wanted in the application. In such case it is possible to create client and service applications using the Raw XTS API.

This is not a recommended way to work with WS-AT. Please take a look at Creating Client Applications and Creating Transactional Web Services for the recommended and easier XTS usage for WS-AT applications.

Creating Client Applications

There are two aspects to a client application using Raw XTS, the transaction declaration aspects, and the business logic. The business logic includes the invocation of Web Services.

Transaction declaration aspects are handled automatically with the XTS client API. This API provides simple transaction directives such as begin, commit, and rollback, which the client application can use to initialize, manage, and terminate transactions. Internally, this API uses SOAP to invoke operations on the various WS-C and WS-AT services, in order to create a coordinator and drive the transaction to completion.

User Transactions

A client uses the UserTransactionFactory and UserTransaction classes to create and manage WS-AT transactions. These classes provide a simple API which operates in a manner similar to the JTA API. A WS-AT transaction is started and associated with the client thread by calling the begin method of the UserTransaction class. The transaction can be committed by calling the commit method, and rolled back by calling the rollback method.

More complex transaction management, such as suspension and resumption of transactions, is supported by the TransactionManagerFactory and TransactionManager classes.

Full details of the WS-AT APIs are provided in the XTS API.

Creating Transactional Web Services

The two parts to implementing a Web service using XTS are the transaction management and the business logic.

The bulk of the transaction management aspects are organized in a clear and easy-to-implement model by means of the XTS’s Participant API, provides a structured model for negotiation between the web service and the transaction coordinator. It allows the web service to manage its own local transactional data, in accordance with the needs of the business logic, while ensuring that its activities are in step with those of the client and other services involved in the transaction. Internally, this API uses SOAP to invokes operations on the various WS-C and WS-AT services, to drive the transaction to completion.

A participant is a software entity which is driven by the transaction manager on behalf of a Web service. When a web service wants to participate in a particular transaction, it must enroll a participant to act as a proxy for the service in subsequent negotiations with the coordinator. The participant implements an API appropriate to the type of transaction it is enrolled in, and the participant model selected when it is enrolled. For example, a Durable2PC participant, as part of a WS-Atomic Transaction, implements the Durable2PCParticipant interface. The use of participants allows the transactional control management aspects of the Web service to be factored into the participant implementation, while staying separate from the rest of the Web service’s business logic and private transactional data management.

The creation of participants is not trivial, since they ultimately reflect the state of a Web service’s back-end processing facilities, an aspect normally associated with an enterprise’s own IT infrastructure. Implementations must use one of the following interfaces: com.arjuna.wst11.Durable2PCParticipant, com.arjuna.wst11.Volatile2PCParticipant.

A full description of XTS’s participant features is provided in the XTS API.

4.2.3. Working With WS-BA

Creating Client Applications

There are two aspects to a client application using XTS, the transaction declaration aspects, and the business logic. The business logic includes the invocation of Web Services.

Transaction declaration aspects are handled automatically with the XTS client API. This API provides simple transaction directives such as begin, close, and cancel, which the client application can use to initialize, manage, and terminate transactions. Internally, this API uses SOAP to invoke operations on WS-BA services, in order to create a coordinator and drive the transaction to completion.

Business Activities

A client creates and manages Business Activities using the UserBusinessActivityFactory and UserBusinessActivity classes. A WS-BA activity is started and associated with the client thread by calling the begin method of the UserBusinessActivity class. A client can terminate a business activity by calling the close method, and cancel it by calling the cancel method.

If any of the Web Services invoked by the client register for the BusinessActivityWithCoordinatorCompletion protocol, the client can call the completed method before calling the close method, to notify the services that it has finished making service invocations in the current activity.

More complex business activity management, such as suspension and resumption of business activities, is supported by the BusinessActivityManagerFactory and BusinessActivityManager classes.

Full details of the WS-BA APIs are provided in the XTS API.

Creating Transactional Web Services

The theory behind creating WS-BA web services is similar to the WS-AT Raw API Creating Transactional Web Services. However, different participant classes are used: com.arjuna.wst11.BusinessAgreementWithParticipantCompletionParticipant , or com.arjuna.wst11.BusinessAgreementWithCoordinatorCompletionParticipant.

A full description of XTS’s participant features is provided in the XTS API.

New Compensating Transactions API

There is a new Compensating Transactions API available to work with WS-BA applications. Please consult our quickstarts how to use it: non-transactional resource with compensating transactions API and travel agent with compensating transactions API

4.2.4. Configuration of The Transaction Context Propagation

You can enable transaction propagation for all Web service calls that are invoked within a JTA, WS-AT or WS-BA transaction. This is done with the default-context-propagation property in the XTS subsystem config of the standalone-xts.xml.

As this is enabled by default (for standalone-xts.xml), calls to all Web services that support WS-AT or WS-BA will automatically receive the transaction context allowing them to participate in the distributed transaction.

The transaction context is simply ignored if the service does not support WS-AT or WS-BA. This is done by setting MustUnderstand="false" on the CoordinationContext SOAP header. Unfortunately, this may cause issues when invoking WS-AT or WS-BA enabled Web services on other vendors' application servers. This is because the WS-Coordination specification states that MustUnderstand must be set to true. If you are affected by this issue, you will need to explicitly enable the transaction propagation for every port.

The default context propagation policy can also be overridden on a per Web Service port basis. This allows the developer to easily state which Web Service clients must and must-not propagate the transaction context. This is done through the standard JAX-WS WebServiceFeature facility. A JAX-WS WebServiceFeature allows meta-information to be added to a port that describe cross-cutting behaviour, such as logging, security or compression. In our case we use the JTAOverWSATFeature and WSTXFeature features.

JTAOverWSATFeature states that any JTA, WS-AT, or WS-BA transactions should be distributed via calls on this client. This feature is recommended to use, if you have a JTA transactions which should be propagated.

WSTXFeature states that any WS-AT or WS-BA transaction should be distributed via calls on this client. You should use this feature, if you use Raw XTS or WS-BA APIs.

Calls to the service will fail if the Web service does not support WS-AT or WS-BA (in this case, XTS sets MustUnderstand=true on the CoordinationContext SOAP header as the developer has explicitly stated that it is required).

The developer may also state that the transaction must-not be distributed over calls to this Web service. This is done by setting the JTAOverWSATFeature or WSTXFeature feature to disabled.

The use of JTAOverWSATFeature and WSTXFeature overrides whatever default context propagation is set to in the standalone-xts.xml.

4.2.5. Summary

This chapter gives a high-level overview of each of the major software pieces used by the Web Services transactions component of Narayana. The Web Services transaction manager provided by Narayana is the hub of the architecture and is the only piece of software that user-level software does not bind to directly. XTS provides header-processing infrastructure for use with Web Services transactions contexts for both client applications and Web Services. XTS provides a simple interface for developing transaction participants, along with the necessary document-handling code.

This chapter is only an overview, and does not address the more difficult and subtle aspects of programming Web Services. For fuller explanations of the components, please continue reading.

4.3. The XTS API

This chapter discusses the XTS API. You can use this information to write client and server applications which consume transactional Web Services and coordinate back-end systems.

4.3.1. Participants

Overview

The participant is the entity that performs the work pertaining to transaction management on behalf of the business services involved in an application. The Web service (in the example code, a theater booking system) contains some business logic to reserve a seat and inquire about availability, but it needs to be supported by something that maintains information in a durable manner. Typically this is a database, but it could be a file system, NVRAM, or other storage mechanism.

Although the service may talk to the back-end database directly, it cannot commit or undo any changes, since committing and rolling back are ultimately under the control of a transaction. For the transaction to exercise this control, it must communicate with the database. In XTS, participant does this communication, as shown in Transactions, Participants, and Back-End Transaction Control.

xts guide fig participant backend control
Figure 12. Transactions, Participants, and Back-End Transaction Control
Atomic Transaction

This section is relevant for WS-AT applications only if Raw XTS API is used.

All Atomic Transaction participants are instances of the Durable2PCParticipant or Volatile2PCParticipant .

Business Activity

All Business Activity participants are instances one or the other of the interfaces described in BusinessAgreementWithParticipantCompletionParticipant or BusinessAgreementWithCoordinatorCompletion interface.

Participant Creation and Deployment

The participant provides the plumbing that drives the transactional aspects of the service. This section discusses the specifics of Participant programming and usage.

Implementing Participants

Implementing a participant is a relatively straightforward task. However, depending on the complexity of the transactional infrastructure that the participant needs to manage, the task can vary greatly in complexity and scope. Your implementation needs to implement one of the interfaces found under com.arjuna.wst.

Deploying Participants

Transactional web services and transactional clients are regular Jakarta EE applications and can be deployed into the application server in the same way as any other Jakarta EE application. The XTS Subsystem exports all the client and web service API classes needed to manage transactions and enroll and manage participant web services. It provides implementations of all the WS-C and WS-T coordination services, not just the coordinator services. In particular, it exposes the client and web service participant endpoints which are needed to receive incoming messages originating from the coordinator.

Normally, a transactional application client and the transaction web service it invokes will be deployed in different application servers. As long as XTS is enabled on each of these containers it will transparently route coordination messages from clients or web services to their coordinator and vice versa. When the client begins a transaction by default it creates a context using the coordination services in its local container. The context holds a reference to the local Registration Service which means that any web services enlisted in the transaction enrol with the coordination services in the same container.

The coordinator does not need to reside in the same container as the client application. By configuring the client deployment appropriately it is possible to use the coordinator services co-located with one of the web services or even to use services deployed in a separate, dedicated container. See Chapter 8 Stand-Alone Coordination for details of how to configure a coordinator located in a different container to the client.

In previous releases, the XTS and Transaction Manager .jar, .war and configuration files needed to be bundled with the application. This deployment method is no longer supported in the WildFly Application Server as XTS is pre-installed as a SubSystem.

4.3.2. API for the Atomic Transaction Protocol

Durable2PCParticipant

All participants which support Durable2PC protocol have to implement com.arjuna.wst.Durable2PCParticipant interface.

Durable2PCParticipant Methods
prepare

The participant should perform any work necessary, so that it can either commit or roll back the work performed by the Web service under the scope of the transaction. The implementation is free to do whatever it needs to in order to fulfill the implicit contract between it and the coordinator.

The participant indicates whether it can prepare by returning an instance of Vote.

commit

The participant should make its work permanent. How it accomplishes this depends upon its implementation. For instance, in the theater example, the reservation of the ticket is committed. If commit processing cannot complete, the participant should throw a SystemException error, potentially leading to a heuristic outcome for the transaction.

rollback

The participant should undo its work. If rollback processing cannot complete, the participant should throw a SystemException error, potentially leading to a heuristic outcome for the transaction.

unknown

This method has been deprecated and is slated to be removed from XTS in the future.

error

In rare cases when recovering from a system crash, it may be impossible to complete or roll back a previously prepared participant, causing the error operation to be invoked.

Volatile2PCParticipant

All participants which support Volatile2PC protocol have to implement com.arjuna.wst.Volatile2PCParticipant interface.

Volatile2PCParticipant Methods
prepare

The participant should perform any work necessary to flush any volatile data created by the Web service under the scope of the transaction, to the system store. The implementation is free to do whatever it needs to in order to fulfill the implicit contract between it and the coordinator.

The participant indicates whether it can prepare by returning an instance of Vote.

commit

The participant should perform any cleanup activities required, in response to a successful transaction commit. These cleanup activities depend upon its implementation. For instance, it may flush cached backup copies of data modified during the transaction. In the unlikely event that commit processing cannot complete, the participant should throw a SystemException error. This will not affect the outcome of the transaction but will cause an error to be logged. This method may not be called if a crash occurs during commit processing.

rollback

The participant should perform any cleanup activities required, in response to a transaction abort. In the unlikely event that rollback processing cannot complete, the participant should throw a SystemException error. This will not affect the outcome of the transaction but will cause an error to be logged. This method may not be called if a crash occurs during commit processing.

unknown

This method is deprecated and will be removed in a future release of XTS.

error

This method should never be called, since volatile participants are not involved in recovery processing.

Vote

During the two-phase commit protocol, a participant is asked to vote on whether it can prepare to confirm the work that it controls. It must return an instance of one of the subtypes of com.arjuna.wst.Vote.

Subclasses of com.arjuna.wst.Vote
Prepared

Indicates that the participant can prepare if the coordinator requests it. Nothing has been committed, because the participant does not know the final outcome of the transaction.

Aborted

The participant cannot prepare, and has rolled back. The participant should not expect to get a second phase message.

ReadOnly

The participant has not made any changes to state, and it does not need to know the final outcome of the transaction. Essentially the participant is resigning from the transaction.

Example Implementation of 2PC Participant’s `prepare`method
public Vote prepare() throws WrongStateException, SystemException {
    // Some participant logic here

    if (/* some condition based on the outcome of the business logic */) {
        // Vote to confirm
        return new com.arjuna.wst.Prepared();
    } else if (/*another condition based on the outcome of the business logic*/) {
        // Resign
        return new com.arjuna.wst.ReadOnly();
    } else {
        // Vote to cancel
        return new com.arjuna.wst.Aborted();
    }
}
TXContext

com.arjuna.mw.wst.TxContext is an opaque representation of a transaction context. It returns one of two possible values, as listed below.

TxContext Return Values
valid

Indicates whether the contents are valid.

equals

Can be used to compare two instances for equality.

UserTransaction

com.arjuna.mw.wst11.UserTransaction is the class that clients typically employ. Before a client can begin a new atomic transaction, it must first obtain a UserTransaction from the UserTransactionFactory. This class isolates the user from the underlying protocol-specific aspects of the XTS implementation. A UserTransaction does not represent a specific transaction. Instead, it provides access to an implicit per-thread transaction context, similar to the UserTransaction in the JTA specification. All of the UserTransaction methods implicitly act on the current thread of control.

`UserTransaction`Methods
begin

Used to begin a new transaction and associate it with the invoking thread.

Parameters
timeout

This optional parameter, measured in milliseconds, specifies a time interval after which the newly created transaction may be automatically rolled back by the coordinator

Exceptions
WrongStateException

A transaction is already associated with the thread.

commit

Volatile2PC and Durable2PC participants enrolled in the transaction are requested first to prepare and then to commit their changes. If any of the participants fails to prepare in the first phase then all other participants are requested to abort.

Exceptions
UnknownTransactionException

No transaction is associated with the invoking thread.

TransactionRolledBackException

The transaction was rolled back either because of a timeout or because a participant was unable to commit.

rollback

Terminates the transaction. Upon completion, the rollback method disassociates the transaction from the current leaving it unassociated with any transactions.

Exceptions
UnknownTransactionException

No transaction is associated with the invoking thread.

UserTransactionFactory

Call the getUserTransaction method to obtain a UserTransaction instance from a UserTransactionFactory.

TransactionManager

Defines the interaction between a transactional web service and the underlying transaction service implementation. A TransactionManager does not represent a specific transaction. Instead, it provides access to an implicit per-thread transaction context.

Methods
currentTransaction

Returns a TxContext for the current transaction, or null if there is no context. Use the currentTransaction method to determine whether a web service has been invoked from within an existing transaction. You can also use the returned value to enable multiple threads to execute within the scope of the same transaction. Calling the currentTransaction method does not disassociate the current thread from the transaction.

suspend

Dissociates a thread from any transaction. This enables a thread to do work that is not associated with a specific transaction.

The suspend method returns a TxContext instance, which is a handle on the transaction.

resume

Associates or re-associates a thread with a transaction, using its TxContext. Prior to association or re-association, the thread is disassociated from any transaction with which it may be currently associated. If the TxContext is null, then the thread is associated with no transaction. In this way, the result is the same as if the suspend method were used instead.

Parameters
txContext

A TxContext instance as return by suspend, identifying the transaction to be resumed.

Exceptions
UnknownTransactionException

The transaction referred to by the TxContext is invalid in the scope of the invoking thread.

enlistForVolitaleTwoPhase

Enroll the specified participant with the current transaction, causing it to participate in the Volatile2PC protocol. You must pass a unique identifier for the participant.

Parameters
participant

An implementation of interface Volatile2PCParticipant whose prepare, commit and abort methods are called when the corresponding coordinator message is received.

id

A unique identifier for the participant. The value of this String should differ for each enlisted participant. It should also be possible for a given identifier to determine that the participant belongs to the enlisting web service rather than some other web service deployed to the same container.

Exceptions
UnknownTransactionException

No transaction is associated with the invoking thread.

WrongStateException

The transaction is not in a state that allows participants to be enrolled. For instance, it may be in the process of terminating.

enlistForDurableTwoPhase

Enroll the specified participant with the current transaction, causing it to participate in the Durable2PC protocol. You must pass a unique identifier for the participant.

Exceptions
UnknownTransactionException

No transaction is associated with the invoking thread.

WrongStateException

The transaction is not in a state that allows participants to be enrolled. For instance, it may be in the process of terminating.

TransactionManagerFactory

Use the getTransactionManager method to obtain a TransactionManager from a TransactionManagerFactory.

WSTXFeature

Use this JAX-WS feature to enable or disable WS-AT context propagation for specific port. Pass an instance of this feature when creating web service port.

Methods
WSTXFeature

WSTXFeature created with default constructor will enable WS-AT context propagation.

WSTXFeature

Parametrised constructor will either enabled or disable WS-AT context propagation.

Parameters
enabled

Boolean value saying to either enable or disable WS-AT context propagation.

JTAOverWSATFeature

Use this JAX-WS feature to enable or disable JTA context propagation for specific port. Pass an instance of this feature when creating web service port.

Methods
JTAOverWSATFeature

JTAOverWSATFeature created with default constructor will enable JTA context propagation.

JTAOverWSATFeature

Parametrised constructor will either enabled or disable JTA context propagation.

Parameters
enabled

Boolean value saying to either enable or disable JTA context propagation.

4.3.3. API for the Business Activity Protocol

Compatibility

Previous implementations of XTS locate the Business Activity Protocol classes in the com.arjuna.mw.wst package. In the current implementation, these classes are located in the com.arjuna.mw.wst11 package.

BusinessAgreementWithParticipantCompletionParticipant

Participant which support business agreement with participant completion protocol have to implement com.arjuna.wst.BusinessAgreementWithParticipantCompletionParticipant interface.

BusinessAgreementWithParticipantCompletion Methods
close

The transaction has completed successfully. The participant has previously informed the coordinator that it was ready to complete.

cancel

The transaction has canceled, and the participant should undo any work. The participant cannot have informed the coordinator that it has completed.

compensate

The transaction has canceled. The participant previously informed the coordinator that it had finished work but could compensate later if required, and it is now requested to do so. If compensation cannot be performed, the participant should throw a FaultedException error, potentially leading to a heuristic outcome for the transaction. If compensation processing cannot complete because of a transient condition then the participant should throw a SystemException error, in which case the compensation action may be retried or the transaction may finish with a heuristic outcome.

status

Return the status of the participant.

unknown

This method is deprecated and will be removed a future XTS release.

error

In rare cases when recovering from a system crash, it may be impossible to compensate a previously-completed participant. In such cases the error operation is invoked.

BusinessAgreementWithCoordinatorCompletion

Participant which support business agreement with coordinator completion protocol have to implement com.arjuna.wst.BusinessAgreementWithCoordinatorCompletionParticipant interface.

BusinessAgreementWithCoordinatorCompletion Methods
close

The transaction completed successfully. The participant previously informed the coordinator that it was ready to complete.

cancel

The transaction canceled, and the participant should undo any work.

compensate

The transaction canceled. The participant previously informed the coordinator that it had finished work but could compensate later if required, and it is now requested to do so. In the unlikely event that compensation cannot be performed the participant should throw a FaultedException error, potentially leading to a heuristic outcome for the transaction. If compensation processing cannot complete because of a transient condition, the participant should throw a SystemException error, in which case the compensation action may be retried or the transaction may finish with a heuristic outcome.

complete

The coordinator is informing the participant all work it needs to do within the scope of this business activity has been completed and that it should make permananent any provisional changes it has made.

status

Returns the status of the participant.

unknown

This method is deprecated and will be removed in a future release of XTS.

error

In rare cases when recovering from a system crash, it may be impossible to compensate a previously completed participant. In such cases, the error method is invoked.

BAParticipantManager

In order for the Business Activity protocol to work correctly, the participants must be able to autonomously notify the coordinator about changes in their status. Unlike the Atomic Transaction protocol, where all interactions between the coordinator and participants are instigated by the coordinator when the transaction terminates, the BAParticipantManager interaction pattern requires the participant to be able to talk to the coordinator at any time during the lifetime of the business activity.

Whenever a participant is registered with a business activity, it receives a handle on the coordinator. This handle is an instance of interface com.arjuna.wst11.BAParticipantManager.

BAParticipantManager Methods
exit

The participant uses the method exit to inform the coordinator that is has left the activity. It will not be informed when and how the business activity terminates. This method may only be invoked while the participant is in the active state (or the completing state, in the case of a participant registered for the ParticipantCompletion protocol). If it is called when the participant is in any other state, a WrongStateException error is thrown. An exit does not stop the activity as a whole from subsequently being closed or canceled/compensated, but only ensures that the exited participant is no longer involved in completion, close or compensation of the activity.

completed

The participant has completed its work, but wishes to continue in the business activity, so that it will eventually be informed when, and how, the activity terminates. The participant may later be asked to compensate for the work it has done or learn that the activity has been closed.

fault

The participant encountered an error during normal activation and has done whatever it can to compensate the activity. The fault method places the business activity into a mandatory cancel-only mode. The faulted participant is no longer involved in completion, close or compensation of the activity.

UserBusinessActivity

com.arjuna.wst11.UserBusinessActivity is the class that most clients employ. A client begins a new business activity by first obtaining a UserBusinessActivity from the UserBusinessActivityFactory. This class isolates them from the underlying protocol-specific aspects of the XTS implementation. A UserBusinessActivity does not represent a specific business activity. Instead, it provides access to an implicit per-thread activity. Therefore, all of the UserBusinessActivity methods implicitly act on the current thread of control.

Methods
begin

Begins a new activity, associating it with the invoking thread.

Parameters
timeout

The interval, in milliseconds, after which an activity times out. Optional.

Exceptions
WrongStateException

The thread is already associated with a business activity.

close

First, all Coordinator Completion participants enlisted in the activity are requested to complete the activity. Next all participants, whether they enlisted for Coordinator or Participant Completion, are requested to close the activity. If any of the Coordinator Completion participants fails to complete at the first stage then all completed participants are asked to compensate the activity while any remaining uncompleted participants are requested to cancel the activity.

Exceptions
UnknownTransactionException

No activity is associated with the invoking thread.

TransactionRolledBackException

The activity has been cancelled because one of the Coordinator Completion participants failed to complete. This exception may also be thrown if one of the Participant Completion participants has not completed before the client calls close.

cancel

Terminates the business activity. All Participant Completion participants enlisted in the activity which have already completed are requested to compensate the activity. All uncompleted Participant Completion participants and all Coordinator Completion participants are requested to cancel the activity.

Exceptions
UnknownTransactionException

No activity is associated with the invoking thread. Any participants that previous completed are directed to compensate their work.

UserBusinessActivityFactory

Use the getUserBusinessActivity method to obtain a UserBusinessActivity instance from a userBusinessActivityFactory.

BusinessActivityManager

com.arjuna.mw.wst11.BusinessActivityManager is the class that web services typically employ. Defines how a web service interacts with the underlying business activity service implementation. A BusinessActivityManager does not represent a specific activity. Instead, it provides access to an implicit per-thread activity.

Methods
currentTransaction

Returns the TxContext for the current business activity, or NULL if there is no TxContext. The returned value can be used to enable multiple threads to execute within the scope of the same business activity. Calling the currenTransaction method does not dissociate the current thread from its activity.

suspend

Dissociates a thread from any current business activity, so that it can perform work not associated with a specific activity. The suspend method returns a TxContext instance, which is a handle on the activity. The thread is then no longer associated with any activity.

resume

Associates or re-associates a thread with a business activity, using its TxContext. Before associating or re-associating the thread, it is disassociated from any business activity with which it is currently associated. If the TxContext is NULL, the thread is disassociated with all business activities, as though the suspend method were called.

Parameters
txContext

A TxContext instance as returned by suspend, identifying the transaction to be resumed.

Exceptions
UnknownTransactionException

The business activity to which the TxContext refers is invalid in the scope of the invoking thread.

enlistForBusinessAgreementWithParticipantCompletion

Enroll the specified participant with current business activity, causing it to participate in the BusinessAgreementWithParticipantCompletion protocol. A unique identifier for the participant is also required.

The return value is an instance of BAParticipantManager which can be used to notify the coordinator of changes in the participant state. In particular, since the participant is enlisted for the Participant Completion protcol it is expected to call the completed method of this returned instance when it has completed all the work it expects to do in this activity and has made all its changes permanent. Alternatively, if the participant does not need to perform any compensation actions should some other participant fail it can leave the activity by calling the exit method of the returned BAParticipantManager instance.

Parameters
participant

An implementation of interface BusinessAgreementWithParticipantCompletionParticipant whose close, cancel, and compensate methods are called when the corresponding coordinator message is received.

id

A unique identifier for the participant. The value of this String should differ for each enlisted participant. It should also be possible for a given identifier to determine that the participant belongs to the enlisting web service rather than some other web service deployed to the same container.

Exceptions
UnknownTransactionException

No transaction is associated with the invoking thread.

WrongStateException

The transaction is not in a state where new participants may be enrolled, such as when it is terminating.

enlistForBusinessAgreementWithCoordinatorCompletion

Enroll the specified participant with current activity, causing it to participate in the BusinessAgreementWithCoordinatorCompletion protocol. A unique identifier for the participant is also required.

The return value is an instance of BAParticipantManager which can be used to notify the coordinator of changes in the participant state. Note that in this case it is an error to call the completed method of this returned instance. With the Coordinator Completion protocol the participant is expected to wait until its completed method is called before it makes all its changes permanent. Alternatively, if the participant determiens that it has no changes to make, it can leave the activity by calling the exit method of the returned BAParticipantManager instance.

Parameters
participant

An implementation of interface BusinessAgreementWithCoordinatorCompletionParticipant whose completed, close, cancel and compensate methods are called when the corresponding coordinator message is received.

id

A unique identifier for the participant. The value of this String should differ for each enlisted participant. It should also be possible for a given identifier to determine that the participant belongs to the enlisting web service rather than some other web service deployed to the same container.

Exceptions
UnknownTransactionException

No transaction is associated with the invoking thread.

WrongStateException

The transaction is not in a state where new participants may be enrolled, such as when it is terminating.

BusinessActivityManagerFactory

Use the getBusinessActivityManager method to obtain a BusinessActivityManager instance from a BusinessActivityManagerFactory.

4.4. Stand-Alone Coordination

4.4.1. Introduction

By default, coordination contexts are obtained from the local coordinator. Therefore, WS-AT transactions or WS-BA activities created by a locally-deployed client application are supplied with a context which identifies the Registration Service running on the client’s machine. Any Web Services invoked by the client are coordinated by the Transaction Protocol services running on the client’s host. This is the case whether the Web Services are running locally or remotely. Such a configuration is called local coordination.

You can reconfigure this setting globally for all clients, causing context creation requests to be redirected to an Activation Coordinator Service running on a remote host. Normally, the rest of the coordination process is executed from the remote host. This configuration is called stand-alone coordination.

Reasons for Choosing a Stand-Alone Coordinator
  • Efficiency: if a client application invokes Web Services on a remote WildFly Application Server, coordinating the transaction from the remote server might be more efficient, since the protocol-specific messages between the coordinator and the participants do not need to travel over the network.

  • Reliability: if the coordinator service runs on a dedicated host, there is no danger of failing applications or services affecting the coordinator and causing failures for unrelated transactions.

  • A third reason might be to use a coordination service provided by a third party vendor.

4.4.2. Configuring the Activation Coordinator

The simplest way to configure a stand-alone coordinator is to provide a complete URL for the remote coordinator. This can be done by changing the 'url' property of the 'xts-environment' element of the XTS Subsystem configuration in the standalone-xts.xml. Example standalone-xts.xml configuration settings shows the snippet of XML that you should change.

Example standalone-xts.xml configuration settings
<?xml version='1.0' encoding='UTF-8'?>

<server xmlns="urn:jboss:domain:1.4">
    . . .
    <subsystem xmlns="urn:jboss:domain:xts:1.0">
        <xts-environment url="http://${jboss.bind.address:127.0.0.1}:8080/ws-c11/ActivationService"/>
        . . .
    </subsystem>
</server>

The XTS module (_modules/system/layers/base/org/jboss/xts/main/jbossxts-${XTS_VERSION}.jar) in the WildFly Application Server includes a configuration file, xts-properties.xml, in the root of the jar. These properties can be edited and then re-packaged in the jar. The changes will take affect on next boot of the WildFly Application Server. Example _xts-properties.xml_configuration settings shows a fragment of this file which details the options for changing the coordinator URL.

Example _xts-properties.xml_configuration settings
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
    . . .
    <!-- coordinator URL
        the following entries are used in the client container only to
        identify the URL used to address the ActivationCoordinator service.
        This is the XTS service which is contacted when a begin operation
        is invoked to start a  WS-AT or WS-BA transaction.

        If a full URL is provide then it will be used as given.
        Otherwise a URL will be constructed using any URL components
        such as scheme, host etc which have been specified as properties
        and defaulting any remaining unspecified properties.
        if no URL or components are specified the URL defaults to that
        of the local coordinator service.
    -->

    <!-- 1.1 properties : only set if you want to use a non-local coordinator
    -->
    <!--
    <entry key="org.jboss.jbossts.xts11.coordinatorURL">http://localhost:8080/ws-c11/ActivationService</entry>
    <entry key="org.jboss.jbossts.xts11.coordinator.scheme">http</entry>
    <entry key="org.jboss.jbossts.xts11.coordinator.address">localhost</entry>
    <entry key="org.jboss.jbossts.xts11.coordinator.port">8080</entry>
    <entry key="org.jboss.jbossts.xts11.coordinator.path">ws-c11/ActivationService</entry>
    -->
</properties>

You can also specify the individual elements of the URL using the properties coordinator.scheme, coordinator.address, and so forth. These values only apply when the coordinator.url is not set. The URL is constructed by combining the specified values with default values for any missing elements. This is particularly useful for two specific use cases.

  1. The first case is where the client is expected to use an XTS coordinator deployed in another WildFly Application Server. If, for example, this WildFly Application Server is bound to address 10.0.1.99 , setting property coordinator.address to 10.0.1.99 is normally all that is required to configure the coordinator URL to identity the remote WildFly Application Server’s coordination service. If the Web service on the remote WildFly Application Server were reset to 9090 then it would also be necessary to set property coordinator.port to this value.

  2. The second common use case is where communications between client and coordinator, and between participant and coordinator, must use secure connections. If property coordinator.scheme is set to value https, the client’s request to begin a transaction is sent to the coordinator service over a secure https connection. The XTS coordinator and participant services will ensure that all subsequent communications between coordinator and client or coordinator and web services also employ secure https connections. Note that this requires configuring the trust stores in the WildFly Application Server running the client, coordinator and participant web services with appropriate trust certificates.

The property names have been abbreviated in order to fit into the table. They should each start with prefix org.jboss.jbossts.xts11.coordinator.

Table 8. Command-Line Options Passed with the -DParameter, Ordered by Priority
Category Property Format

Absolute URL

...coordinatorURL

http://coord.host:coord.port/ws-c11/ActivationService

Coordinator Scheme, Host, Port, and Path

...coordinator.scheme, ...coordinator.address, ...coordinator.port, ...coordinator.path,

http, server.bind.address, jboss.web.bind.port

4.5. Participant Crash Recovery

A key requirement of a transaction service is to be resilient to a system crash by a host running a participant, as well as the host running the transaction coordination services. Crashes which happen before a transaction terminates or before a business activity completes are relatively easy to accommodate. The transaction service and participants can adopt a presumed abort policy.

Procedure: Presumed Abort Policy
  1. If the coordinator crashes, it can assume that any transaction it does not know about is invalid, and reject a participant request which refers to such a transaction.

  2. If the participant crashes, it can forget any provisional changes it has made, and reject any request from the coordinator service to prepare a transaction or complete a business activity.

Crash recovery is more complex if the crash happens during a transaction commit operation, or between completing and closing a business activity. The transaction service must ensure as far as possible that participants arrive at a consistent outcome for the transaction.

WS-AT Transaction

The transaction needs to commit all provisional changes or roll them all back to the state before the transaction started.

WS-Business Activity Transaction

All participants need to close the activity or cancel the activity, and run any required compensating actions.

On the rare occasions where such a consensus cannot be reached, the transaction service must log and report transaction failures.

XTS includes support for automatic recovery of WS-AT and WS-BA transactions, if either or both of the coordinator and participant hosts crashes. The XTS recovery manager begins execution on coordinator and participant hosts when the XTS service restarts. On a coordinator host, the recovery manager detects any WS-AT transactions which have prepared but not committed, as well as any WS-BA transactions which have completed but not yet closed. It ensures that all their participants are rolled forward in the first case, or closed in the second.

On a participant host, the recovery manager detects any prepared WS-AT participants which have not responded to a transaction rollback, and any completed WS-BA participants which have not yet responded to an activity cancel request, and ensures that the former are rolled back and the latter are compensated. The recovery service also allows for recovery of subordinate WS-AT transactions and their participants if a crash occurs on a host where an interposed WS-AT coordinator has been employed.

4.5.1. WS-AT Recovery

WS-AT Coordinator Crash Recovery

The WS-AT coordination service tracks the status of each participant in a transaction as the transaction progresses through its two-phase commit. When all participants have been sent a prepare message and have responded with a prepared message, the coordinator writes a log record storing each participant’s details, indicating that the transaction is ready to complete. If the coordinator service crashes after this point has been reached, completion of the two-phase commit protocol is still guaranteed, by reading the log file after reboot and sending a commit message to each participant. Once all participants have responded to the commit with a committed message, the coordinator can safely delete the log entry.

Since the prepared messages returned by the participants imply that they are ready to commit their provisional changes and make them permanent, this type of recovery is safe. Additionally, the coordinator does not need to account for any commit messages which may have been sent before the crash, or resend messages if it crashes several times. The XTS participant implementation is resilient to redelivery of the commit messages. If the participant has implemented the recovery functions described in WS-AT Participant Crash Recovery APIs, the coordinator can guarantee delivery of commit messages if both it crashes, and one or more of the participant service hosts also crash, at the same time.

If the coordination service crashes before the prepare phase completes, the presumed abort protocol ensures that participants are rolled back. After system restart, the coordination service has the information about about all the transactions which could have entered the commit phase before the reboot, since they have entries in the log. It also knows about any active transactions started after the reboot. If a participant is waiting for a response, after sending its prepared message, it automatically re-sends the prepared message at regular intervals. When the coordinator detects a transaction which is not active and has no entry in the log file after the reboot, it instructs the participant to abort, ensuring that the web service gets a chance to roll back any provisional state changes it made on behalf of the transaction.

A web service may decide to unilaterally commit or roll back provisional changes associated with a given participant, if configured to time-out after a specified length of time without a response. In this situation, the the web service should record this action and log a message to persistent storage. When the participant receives a request to commit or roll back, it should throw an exception if its unilateral decision action does not match the requested action. The coordinator detects the exception and logs a message marking the outcome as heuristic. It also saves the state of the transaction permanently in the transaction log, to be inspected and reconciled by an administrator.

WS-AT Participant Crash Recovery

This part is relevant only if Raw XTS API is used. JTA integration does the recovery automatically.

WS-AT participants associated with a transactional web service do not need to be involved in crash recovery if the Web service’s host machine crashes before the participant is told to prepare. The coordinator will assume that the transaction has aborted, and the Web service can discard any information associated with unprepared transactions when it reboots.

When a participant is told to prepare, the Web service is expected to save to persistent storage the transactional state it needs to commit or roll back the transaction. The specific information it needs to save is dependent on the implementation and business logic of the Web Service. However, the participant must save this state before returning a prepared vote from the prepare call. If the participant cannot save the required state, or there is some other problem servicing the request made by the client, it must return an aborted vote.

The XTS participant services running on a Web Service’s host machine cooperate with the Web service implementation to facilitate participant crash recovery. These participant services are responsible for calling the participant’s prepare, commit, and rollback methods. The XTS implementation tracks the local state of every enlisted participant. If the prepare call returns a prepared vote, the XTS implementation ensures that the participant state is logged to the local transaction log before forwarding a prepared message to the coordinator.

A participant log record contains information identifying the participant, its transaction, and its coordinator. This is enough information to allow the rebooted XTS implementation to reinstate the participant as active and to continue communication with the coordinator, as though the participant had been enlisted and driven to the prepared state. However, a participant instance is still necessary for the commit or rollback process to continue.

Full recovery requires the log record to contain information needed by the Web service which enlisted the participant. This information must allow it to recreate an equivalent participant instance, which can continue the commit process to completion, or roll it back if some other Web Service fails to prepare . This information might be as simple as a String key which the participant can use to locate the data it made persistent before returning its Prepared vote. It may be as complex as a serialized object tree containing the original participant instance and other objects created by the Web service.

If a participant instance implements the relevant interface, the XTS implementation will append this participant recovery state to its log record before writing it to persistent storage. In the event of a crash, the participant recovery state is retrieved from the log and passed to the Web Service which created it. The Web Service uses this state to create a new participant, which the XTS implementation uses to drive the transaction to completion. Log records are only deleted after the participant’s commit or rollback method is called.

If a crash happens just before or just after a commit method is called, a commit or rollback method may be called twice.

WS-AT Participant Crash Recovery APIs
Saving Participant Recovery State

When a Business Activity participant web service completes its work, it may want to save the information which will be required later to close or compensate actions performed during the activity. The XTS implementation automatically acquires this information from the participant as part of the completion process and writes it to a participant log record. This ensures that the information can be restored and used to recreate a copy of the participant even if the web service container crashes between the complete and close or compensate operations.

For a Participant Completion participant, this information is acquired when the web service invokes the completed method of the BAParticipantManager instance returned from the call which enlisted the participant. For a Coordinator Completion participant this occurs immediately after the call to it’s completed method returns. This assumes that the completed method does not throw an exception or call the participant manager’s cannotComplete or fail method.

A participant may signal that it is capable of performing recovery processing, by implementing the java.lang.Serializable interface. An alternative is to implement the PersistableATParticipant Interface.

PersistableATParticipant Interface
public interface PersistableATParticipant {
    byte[] getRecoveryState() throws Exception;
}

If a participant implements the Serializable interface, the XTS participant services implementation uses the serialization API to create a version of the participant which can be appended to the participant log entry. If it implements the PersistableATParticipant interface, the XTS participant services implementation call the getRecoveryState method to obtain the state to be appended to the participant log entry.

If neither of these APIs is implemented, the XTS implementation logs a warning message and proceeds without saving any recovery state. In the event of a crash on the host machine for the Web service during commit, the transaction cannot be recovered and a heuristic outcome may occur. This outcome is logged on the host running the coordinator services.

Recovering Participants at Reboot

A Web service must register with the XTS implementation when it is deployed, and unregister when it is undeployed, in order to participate in recovery processing. Registration is performed using class XTSATRecoveryManager defined in package org.jboss.jbossts.xts.recovery.participant.at.

Registering for Recovery
public abstract class XTSATRecoveryManager {
    ...

    public static XTSATRecoveryManager getRecoveryManager();

    public void registerRecoveryModule(XTSATRecoveryModule module);

    public abstract void unregisterRecoveryModule(XTSATRecoveryModule module)
            throws NoSuchElementException;
    ...
}

The Web service must provide an implementation of interface XTSBARecoveryModule in package org.jboss.jbossts.xts.recovery.participant.ba, as an argument to the register and unregister calls. This instance identifies saved participant recovery records and recreates new, recovered participant instances:

XTSBARecoveryModule Interface
public interface XTSATRecoveryModule {
    public Durable2PCParticipant
    deserialize(String id, ObjectInputStream stream)
            throws Exception;

    public Durable2PCParticipant
    recreate(String id, byte[] recoveryState)
            throws Exception;

    public void endScan();
}

If a participant’s recovery state was saved using serialization, the recovery module’s deserialize method is called to recreate the participant. Normally, the recovery module is required to read, cast, and return an object from the supplied input stream. If a participant’s recovery state was saved using the PersistableATParticipant interface, the recovery module’s recreate method is called to recreate the participant from the byte array it provided when the state was saved.

The XTS implementation cannot identify which participants belong to which recovery modules. A module only needs to return a participant instance if the recovery state belongs to the module’s Web service. If the participant was created by another Web service, the module should return null. The participant identifier, which is supplied as argument to the deserialize or recreate method, is the identifier used by the Web service when the original participant was enlisted in the transaction. Web Services participating in recovery processing should ensure that participant identifiers are unique per service. If a module recognizes that a participant identifier belongs to its Web service, but cannot recreate the participant, it should throw an exception. This situation might arise if the service cannot associate the participant with any transactional information which is specific to the business logic.

Even if a module relies on serialization to create the participant recovery state saved by the XTS implementation, it still must be registered by the application. The deserialization operation must employ a class loader capable of loading classes specific to the Web service. XTS fulfills this requirement by devolving responsibility for the deserialize operation to the recovery module.

4.5.2. WS-BA Recovery

WS-BA Coordinator Crash Recovery

The WS-BA coordination service implementation tracks the status of each participant in an activity as the activity progresses through completion and closure. A transition point occurs during closure, once all CoordinatorCompletion participants receive a complete message and respond with a completed message. At this point, all ParticipantCompletion participants should have sent a completed message. The coordinator writes a log record storing the details of each participant, and indicating that the transaction is ready to close. If the coordinator service crashes after the log record is written, the close operation is still guaranteed to be successful. The coordinator checks the log after the system reboots and re-sends a close message to all participants. After all participants respond to the close with a closed message, the coordinator can safely delete the log entry.

The coordinator does not need to account for any close messages sent before the crash, nor resend messages if it crashes several times. The XTS participant implementation is resilient to redelivery of close messages. Assuming that the participant has implemented the recovery functions described below, the coordinator can even guarantee delivery of close messages if both it, and one or more of the participant service hosts, crash simultaneously.

If the coordination service crashes before it has written the log record, it does not need to explicitly compensate any completed participants. The presumed abort protocol ensures that all completed participants are eventually sent a compensate message. Recovery must be initiated from the participant side.

A log record does not need to be written when an activity is being canceled. If a participant does not respond to a cancel or compensate request, the coordinator logs a warning and continues. The combination of the presumed abort protocol and participant-led recovery ensures that all participants eventually get canceled or compensated, as appropriate, even if the participant host crashes.

If a completed participant does not detect a response from its coordinator after resending its completed response a suitable number of times, it switches to sending getstatus messages, to determine whether the coordinator still knows about it. If a crash occurs before writing the log record, the coordinator has no record of the participant when the coordinator restarts, and the getstatus request returns a fault. The participant recovery manager automatically compensates the participant in this situation, just as if the activity had been canceled by the client.

After a participant crash, the participant recovery manager detects the log entries for each completed participant. It sends getstatus messages to each participant’s coordinator host, to determine whether the activity still exists. If the coordinator has not crashed and the activity is still running, the participant switches back to resending completed messages, and waits for a close or compensate response. If the coordinator has also crashed or the activity has been canceled, the participant is automatically canceled.

WS-BA Participant Crash Recovery APIs
Saving Participant Recovery State

A participant may signal that it is capable of performing recovery processing, by implementing the java.lang.Serializable interface. An alternative is to implement the `PersistableBAParticipant`Interface.

`PersistableBAParticipant`Interface
public interface PersistableBAParticipant {
    byte[] getRecoveryState() throws Exception;
}

If a participant implements the Serializable interface, the XTS participant services implementation uses the serialization API to create a version of the participant which can be appended to the participant log entry. If the participant implements the PersistableBAParticipant, the XTS participant services implementation call the getRecoveryState method to obtain the state, which is appended to the participant log entry.

If neither of these APIs is implemented, the XTS implementation logs a warning message and proceeds without saving any recovery state. If the Web service’s host machine crashes while the activity is being closed, the activity cannot be recovered and a heuristic outcome will probably be logged on the coordinator’s host machine. If the activity is canceled, the participant is not compensated and the coordinator host machine may log a heuristic outcome for the activity.

Recovering Participants at Reboot

A Web service must register with the XTS implementation when it is deployed, and unregister when it is undeployed, so it can take part in recovery processing.

Registration is performed using the XTSBARecoveryManager, defined in the org.jboss.jbossts.xts.recovery.participant.ba package.

XTSBARecoveryManager Class
public abstract class XTSBARecoveryManager {
    ...

    public static XTSBARecoveryManager getRecoveryManager();

    public void registerRecoveryModule(XTSBARecoveryModule module);

    public abstract void unregisterRecoveryModule(XTSBARecoveryModule module)
            throws NoSuchElementException;
    ...
}

The Web service must provide an implementation of the XTSBARecoveryModule in the org.jboss.jbossts.xts.recovery.participant.ba, as an argument to the register and unregister calls. This instance identifies saved participant recovery records and recreates new, recovered participant instances:

`XTSBARecoveryModule`Interface
public interface XTSBARecoveryModule {
    public BusinessAgreementWithParticipantCompletionParticipant
    deserializeParticipantCompletionParticipant(String id,
                                                ObjectInputStream stream)
            throws Exception;

    public BusinessAgreementWithParticipantCompletionParticipant
    recreateParticipantCompletionParticipant(String id,
                                             byte[] recoveryState)
            throws Exception;

    public BusinessAgreementWithCoordinatorCompletionParticipant
    deserializeCoordinatorCompletionParticipant(String id,
                                                ObjectInputStream stream)
            throws Exception;

    public BusinessAgreementWithCoordinatorCompletionParticipant
    recreateCoordinatorCompletionParticipant(String id,
                                             byte[] recoveryState)
            throws Exception;

    public void endScan();
}

If a participant’s recovery state was saved using serialization, one of the recovery module’s deserialize methods is called, so that it can recreate the participant. Which method to use depends on whether the saved participant implemented the ParticipantCompletion protocol or the CoordinatorCompletion protocol. Normally, the recovery module reads, casts and returns an object from the supplied input stream. If a participant’s recovery state was saved using the PersistableBAParticipant interface, one of the recovery module’s recreate methods is called, so that it can recreate the participant from the byte array provided when the state was saved. The method to use depends on which protocol the saved participant implemented.

The XTS implementation does not track which participants belong to which recovery modules. A module is only expected to return a participant instance if it can identify that the recovery state belongs to its Web service. If the participant was created by some other Web service, the module should return null. The participant identifier supplied as an argument to the deserialize or recreate calls is the identifier used by the Web service when the original participant was enlisted in the transaction. Web Services which participate in recovery processing should ensure that the participant identifiers they employ are unique per service. If a module recognizes a participant identifier as belonging to its Web service, but cannot recreate the participant, it throws an exception. This situation might arise if the service cannot associate the participant with any transactional information specific to business logic.

A module must be registered by the application, even when it relies upon serialization to create the participant recovery state saved by the XTS implementation. The deserialization operation must employ a class loader capable of loading Web service-specific classes. The XTS implementation achieves this by delegating responsibility for the deserialize operation to the recovery module.

Securing Web Service State Changes

When a BA participant completes, it is expected to commit changes to the web service state made during the activity. The web service usually also needs to persist these changes to a local storage device. This leaves open a window where the persisted changes may not be guarded with the necessary compensation information. The web service container may crash after the changes to the service state have been written but before the XTS implementation is able to acquire the recovery state and write a recovery log record for the participant. Participants may close this window by employing a two phase update to the local store used to persist the web service state.

A participant which needs to persist changes to local web service state should implement interface ConfirmCompletedParticipant in package com.arjuna.wst11. This signals to the XTS implementation that it expects confirmation after a successful write of the participant recovery record, allowing it to roll forward provisionally persisted changes to the web service state. Delivery of this confirmation can be guaranteed even if the web service container crashes after writing the participant log record. Conversely, if a recovery record cannot be written because of a fault or a crash prior to writing, the provisional changes can be guaranteed to be rolled back.

ConfirmCompletedParticipant Interface
public interface ConfirmCompletedParticipant {
    public void confirmCompleted(boolean confirmed);
}

When the participant is ready to complete, it should prepare its persistent changes by temporarily locking access to the relevant state in the local store and writing the changed data to disk, retaining both the old and new versions of the service state. For a Participant Completion participant, this prepare operation should be done just before calling the participant manager’s completed method. For a Coordinator Completion participant, it should be done just before returning from the call to the participant’s completed method. After writing the participant log record, the XTS implementation calls the participant’s confirmCompleted method, providing value true as the argument. The participant should respond by installing the provisional state changes and releasing any locks. If the log record cannot be written, the XTS implementation calls the participant’s confirmCompleted method, providing value false as the argument. The participant should respond by restoring the original state values and releasing any locks.

If a crash occurs before the call to confirmCompleted, the application’s recovery module can make sure that the provisional changes to the web service state are rolled forward or rolled back as appropriate. The web service must identify all provisional writes to persistent state before it starts serving new requests or processing recovered participants. It must reobtain any locks required to ensure that the state is not changed by new transactions. When the recovery module recovers a participant from the log, its compensation information is available. If the participant still has prepared changes, the recovery code must call confirmCompleted, passing value true. This allows the participant to finish the complete operation. The XTS implementation then forwards a completed message to the coordinator, ensuring that the participant is subsequently notified either to close or to compensate. At the end of the first recovery scan, the recovery module may find some prepared changes on disk which are still unaccounted for. This means that the participant recovery record is not available. The recovery module should restore the original state values and release any locks. The XTS implementation responds to coordinator requests regarding the participant with an unknown participant fault, forcing the activity as a whole to be rolled back.

4.6. Web Service Transaction Service (XTS) Management

The basic building blocks of a transactional Web Services application include the application itself, the Web services that the application consumes, the Transaction Manager, and the transaction participants which support those Web services. Although it is likely that different developers will be responsible for each piece, the concepts are presented here so that you can see the whole picture. Often, developers produce services, or applications that consume services, and system administrators run the transaction-management infrastructure.

4.6.1. Transaction manager overview

The transaction manager is a Web service which coordinates XTS transactions. It is the only software component in XTS that is designed to be run directly as a network service, rather than to support end-user code. The transaction manager runs as a JAXM request/response Web service.

When starting up an application server instance that has XTS transaction manager deployed within it, you may see various error messages in the console or log. For example, 16:53:38,850 ERROR [STDERR] Message Listener Service: started, message listener jndi name activationcoordinator. These are for information purposes only and are not actual errors.

4.6.2. Configuring the transaction manager

You can configure the Transaction Manager and related infrastructure by using two properties files. The standalone-xts.xml file contains the common configuration options. More advanced options can be configured in the xts-properties.xml_.

The XTS module (modules/system/layers/base/org/jboss/xts/main/jbossxts-${XTS_VERSION}.jar) in the WildFly Application Server includes the configuration file, xts-properties.xml, in the root of the jar. These properties can be edited and then re-packaged in the jar. The changes will take affect on next boot of the WildFly Application Server.

4.6.3. Deployment descriptors

In general, changing the contents of the various deployment descriptors used by XTS is not necessary. However, if you do need to modify them they are all included in modules/system/layers/base/org/jboss/xts/main/jbossxts-${XTS_VERSION}.jar.

4.7. Quickstarts Overview

There are multiple quickstarts provided on Narayana GitHub repository which should give you a better understanding of how to use our software. This chapter will give you a brief overview where to find them and what technologies they demonstrate.

4.7.1. WS-AT Multi-Service

This quickstart uses JTA to manage WS-AT applications. The quickstart is composed of a client (the test) and two Web services (FirstServiceAT and SecondServiceAT). Both services are invoked by the test from within the same JTA transaction.

The Client begins a JTA transaction and then invokes an operation on each service. Transaction context propagation is enabled by default. Therefore XTS automatically bridges the JTA transaction to a WS-AT transaction before each invocation is made.

Each service uses JPA to persist its data (the value of a counter). Therefore, the service class is annotated with jakarta.ejb.TransactionAttribute which tells XTS to automatically bridge WS-AT transaction to JTA.

4.7.2. WS-AT Multi-Hop

This quickstart uses JTA to manage WS-AT applications. The quickstart is composed of a client (the test) and two Web services (FirstServiceAT and SecondServiceAT).

The Client begins a JTA transaction and then invokes an operation on FirstServiceAT. Transaction context propagation is enabled by default. Therefore XTS automatically bridges the JTA transaction to a WS-AT transaction before the invocation is made.

FirstServiceAT uses JPA to persist its data. Therefore, the service class is annotated with jakarta.ejb.TransactionAttribute which tells XTS to automatically bridge WS-AT transaction to JTA. The FirstServiceAT Web Service updates some local data and then invokes the SecondServiceAT Web services.

Similarly, to when invoking FirstServiceAT, the JTA transaction is bridged to a WS-AT transaction when invoking SecondServiceAT. SecondServiceAT also uses JPA for persistence, so the incoming WS-AT transaction is again bridged to JTA.

4.7.3. XTS with SSL

This example walks you through the steps required to setup two servers (client and server) that communicate via Web services over a secure connection. The example show how this can be done for WS-Atomic Transaction, but the same applies for WS Business Activity.

4.7.4. Raw XTS API Demo

This example demonstrates the whole range of XTS possibilities, including WS-AT and WS-BA.

This example uses the Raw XTS API. It is only recommended for scenarios where the WS-AT to JTA integration is not appropriate; or where the Compensating Transactions API support for WS-BA is not appropriate.

4.7.5. Non-transactional Resource with Compensating Transactions API

This example demonstrates the simple use case of our API for developing applications that use Compensating Transactions. It shows how a non-transactional activity (such as sending an email, or printing a document) can be coordinated in a compensating transaction.

4.7.6. Travel Agent with Compensating Transactions API

This example demonstrates the more complex use case of our API for developing applications that use Compensating Transactions. It shows how a long running compensating transaction can be composed of a series of short-running ACID transactions. The example also involves multiple organisations and forms a distributed transaction over Web Services.

5. TXBridge Guide

5.1. Introduction

5.1.1. Contextual Overview

Transactions provide a structuring mechanism for business logic. Use of transactions allows for grouping of data manipulations into constructs with certain properties. Traditional ACID transactions provide for properties of Atomicity, Consistency, Isolation and Durability.

In JavaEE applications, transaction support is provided via the Java Transaction API (JTA). The classes and interfaces in the jakarta.transaction and javax.transaction.xa packages provide a means by which the programmer may manage transaction demarcation (begin, commit, rollback) and, where necessary, interact with the transaction management system (e.g. enlistResource). In many JavaEE applications, further abstractions are provided on top of the JTA. For example, EJB3 @TransactionAttribute annotations may be used for transaction boundary demarcation in preference to explicit calls to the JTA’s UserTransaction interface.

In distributed applications, the JTA implementation may provide propagation of transaction context and transaction control calls between containers (JVMs) using either a propriety transport or JTS, the Java mapping of the CORBA OTS standard on an RMI/IIOP transport. In Narayana, both local and distributed (JTS) implementations of the JTA are available.

In Web Services applications, ACID transaction management and interoperable context propagation is provided for by the WS-AT standard. Narayana XTS provides an implementation of both the 1.1 and 1.2 versions of this standard. Bridging is provided only on the more recent version. At the time of writing the standard covers only the web services API and protocol, not the Java API through which the protocol may be driven. Therefore, XTS provides a custom Java API to users, with characteristics broadly similar to the JTA.

For applications that combine traditional JavaEE transaction management and Web Service transaction management, it is often desirable to have some mechanism for linking these transaction types, such that a single transaction may span business logic written for either transaction type. Examples include exposing existing JavaEE transactional business logic (e.g. EJBs) as transactional Web Services, or allowing JavaEE transactional components to utilize transactional Web Services.

5.1.2. Transaction Bridging

We use the term Transaction Bridging to describe the process of linking the JavaEE and Web Services transaction domains. The transaction bridge component (txbridge) of Narayana provides bi-directional linkage, such that either type of transaction may encompass business logic designed for use with the other type.

The technique used by the bridge is a combination of interposition and protocol mapping.

Interposition is used in transaction systems to allow a tree of transaction coordinators to be constructed, usually for performance reasons. Interposed coordinators function as transaction managers for nodes below them in the tree, whilst appearing as resources (participants in WS-AT terminology) to the node above them.

Within a single transaction domain, interposition may be used to allow remote nodes to minimize the number of network calls necessary at transaction termination. The top level node is known as the root coordinator, whilst interposed coordinators are termed subordinate. This name indicates that they are not autonomously responsible for determining the transaction outcome, but rather are driven by their parent coordinator. Therefore, whilst a top level coordinator exposes only the commit and rollback methods for transaction termination and handles the 2PC internally, the subordinates additionally expose the prepare method to their parent, behaving much like resources during the termination protocol.

txbridge guide interposition
Figure 13. Transaction interposition in a distributed JTA environment

In the transaction bridge, an interposed coordinator is registered into the existing transaction and performs the additional task of protocol mapping. That is, it appears to its parent coordinator to be a resource of its native transaction type, whilst appearing to its children to be a coordinator of their native transaction type, even though these transaction types differ.

txbridge guide bridgeinterposition
Figure 14. Transactional bridging interposition

The interposed coordinator is responsible for performing mapping between the transaction protocols. There is a strong correspondence between the API and protocol used by the JTA and WS-AT transaction types, which is unsurprising given their common heritage and shared problem domain. However, method signatures, exception types and such do differ. The bridge provides a abstraction layer to mask these distinctions as far as possible.

The net result of this is that existing business logic perceives its expected transaction environment, even though the transaction in which it is executing may be subordinate to one of a different type. No changes are necessary to existing transactional applications to allow them to operate in the scope of foreign transactions. This facilitates reuse of existing business logic components in new environments and increases the possibilities for new architectures and interoperability.

5.2. Transaction Bridge Architecture

5.2.1. Overview

The transaction bridge resides in the package org.jboss.jbossts.txbridge and its subpackages.. It consists of two distinct sets of classes, one for bridging in each direction.

The process of inflowing a WS-AT transaction context on a Web Service call into the container and converting it to a local JTA transaction context such that existing transactional JavaEE code (e.g. EJBs) may be called within its scope, is termed Inbound Transaction Bridging. When using inbound bridging, a parent WS-AT transaction coordinator has a subordinate JTA coordinator interposed into it via the transaction bridge.

The process of outflowing a WS-AT transaction context on a call to a transactional Web Service from a business logic method operating in a JavaEE transaction scope, is termed Outbound Transaction Bridging. When using outbound bridging, a parent JTA transaction coordinator has a subordinate WS-AT coordinator interposed into it via the transaction bridge.

For the purpose of understanding this naming convention, it is simplest to view the JTA as being local to the container in which it operates, whilst the Web Service protocol provides for transaction context propagation between servers. This is an accurate representation of the situation that exists where the local JTA version of Narayana is being used alongside Narayana XTS in an application server. However, it is an oversimplification of the situation where the JTS option is used. We will return to this case later.

txbridge guide architecture
Figure 15. Simplified Bridge Architecture

5.2.2. Shared Design Elements

The design of the inbound and outbound bridges is conceptually very similar. Each provides the following:

  • A BridgeManager, essentially a factory singleton, providing a means of managing Bridge and resource/participant instances. The chief role of the BridgeManager is to ensure a distinct mapping of a parent transaction context to a single Bridge and resource/participant instance.

  • A Bridge, which provides Thread to transaction context association and disassociation functions for the subordinate transaction. The Bridge is usually called from the Handler, but may optionally be driven directly.

  • A Handler, which is registered into the JAX-WS processing pipeline to provide minimally invasive management of Thread to transaction context bindings via the Bridge, an appropriate instance of which it obtains from the BridgeManager. Whilst the bridge provides handlers only for JAX-WS, it’s possible to use these as a model for the implementation of JAX-RPC versions if desired.

  • A VolatileParticipant and DurableParticipant (in the case of the InboundBridge) or Synchronization and XAResource (in the case of the OutboundBridge) which are enlisted into the parent transaction and wrap the Subordinate transaction coordinator, providing mapping of the transaction termination protocol operations.

  • A RecoveryManager, which is responsible for automatically restoring the state of crashed transactions and allowing them to complete correctly.

5.2.3. Inbound Bridging

The process flow when using the inbound bridge is as follows:

  1. A remote client starts a WS-AT transaction and invokes a transactional Web Service in the scope of that transaction. The inbound WS invocation therefore has SOAP headers containing the WS-AT transaction context. The coordinator used for this transaction is the root coordinator. It may be remote from either or both of the client and the service it is invoking. The client needs access to a WS-AT implementation, but not a JTA or the transaction bridge deployed.

  2. The call arrives at a web service container, which must have Narayana JTA or JTS, XTS and the transaction bridge deployed. The JAX-WS handler chain for the web service should have both the XTS WS-AT transaction header processor and the inbound bridge handler registered, such that they are invoked in that order.

  3. The transaction header processor takes the WS-AT transaction context from XML, creates a corresponding WS-AT TxContext and associates it to the Thread. The bridge handler calls the InboundBridgeManager to obtain an InboundBridge instance corresponding to the TxContext.

  4. As the BridgeManager is seeing the TxContext for the first time, it creates a new Bridge instance. It also creates a new Bridge, VolatileParticipant, and DurableParticipant and registers them with the WS-AT transaction coordinator. These Participants wrap a subordinate JTA transaction.

  5. The bridge header processor starts the bridge, which associates the JTA subordinate transaction context to the Thread. At this point the Thread has transaction contexts for both WS-AT and JTA.

  6. The JAX-WS pipeline processing continues, eventually calling whatever business logic is exposed. This may be e.g. an EJB using JSR-181 annotations. The business logic may use the JTA transaction in the normal manner e.g. enlisting Synchronizations and XAResources or performing other transactional activity either directly or though the usual JavaEE abstractions.

  7. On the return path, the bridge header processor disassociates the JTA transaction context from the Thread via the Bridge. The XTS context processor then does likewise for the WS-AT TxContext.

  8. On subsequent web services calls to the same or other web services from the same client, the process is repeated. However, the BridgeManager will, upon seeing the same WS-AT transaction context again, return the existing Bridge instance and not register further Participant instances. This allows substantially better performance than registering one Participant per web service invocation.

  9. Upon transaction termination by the client, the WS-AT transaction coordinator will drive the enlisted bridge Participants through the transaction termination protocol. The Participants maps these calls down to the JTA subtransaction coordinator, which in turn passes them on to any Synchronizations or XAResources enlisted in the transaction. This process is not visible to the business logic, except in so far as it may have registered its own Synchronizations, XAResources or Participants with the transaction.

5.2.4. Outbound Bridging

The process flow when using the outbound bridge is as follows:

  1. A client starts a JTA transaction and invokes a remote transactional Web Service in the scope of that transaction. The client must have Narayana JTA (or JTS) and XTS deployed, as well as the transaction bridge. The coordinator used for the JTA transaction is the root coordinator. The server hosting the target web service needs a WS-AT transaction implementation but not a JTA or the transaction bridge.

  2. The outbound WS invocation flows though a handler chain that has the outbound transaction bridge handler and XTS header context processor registered, such that they are invoked in that order.

  3. The bridge handler calls the outbound bridge manager to obtain an outbound bridge instance corresponding to the JTA transaction context. As the BridgeManager is seeing the context for the first time, it creates a new Bridge instance. It also creates a Synchronization and XAResource instance to wrap the subordinate WS-AT transaction and registers these with the JTA transaction.

  4. The bridge handler starts the bridge, which associates the subordinate WS-AT transaction context to the Thread. The WS-AT header context processor then serializes this into XML in the headers of the outbound Web Services call.

  5. The receiving Web Service sees a WS-AT context and can work with it in the normal manner, without knowing it is a subordinate context.

  6. On the return path, the bridge handler disassociates the WS-AT TxContext from the Thread via the Bridge.

  7. On subsequent calls to the same or other transactional Web Services in the scope of the same JTA transaction, the process is repeated. However, the BridgeManager will, upon seeing the same JTA transaction context again, return the existing Bridge and not register another Synchronization or XAResource with the parent JTA transaction. This allows substantially better performance than registering once per web service invocation.

  8. Upon transaction termination by the client, the JTA transaction coordinator will drive the enlisted bridge Synchronization and XAResource through the transaction termination protocol. The XAResource maps these calls down to the WS-AT subtransaction coordinator, which in turn passes them on to any Volatile or Durable Participants enlisted in the transaction. This process is not visible to the business logic, except in so far as it may have registered its own Participants, XAResources or Synchronizatons with the transaction.

5.2.5. Crash Recovery

The bridge includes independent crash recovery systems for the inbound and outbound sides. These are automatically installed and activated as part of the bridge deployment. They rely upon the recovery mechanisms in the JTA and XTS components, which are likewise deployed and activated by default as part of their respective components.

It is the responsibility of the application(s) to use suitable XAResources (inbound) or DurableParticipants (outbound). In general the former will be from XA datasources or messaging systems, whilst the latter will be custom implementations. In either case it is important to ensure recovery is correctly configured for the resource manager(s) before using them in production, via the bridge or otherwise. The Narayana documentation set details crash recovery configuration, as does the application server administration guide. For resource manager specific information e.g. Oracle db permissions settings for recovery connections, please consult the vendor’s documentation.

A bridged transaction will involve several distinct log writes, potentially on multiple hosts. Resolving the transaction may require more than one crash recovery cycle, due to ordering constrains on the events taking place during recovery. If a transaction fails to recover after all servers have been restored to service for more than two recovery cycles duration, the Narayana objectstore browser and server logs may be useful for diagnosing the issue. Where a transaction involves multiple bridges the number of recovery cycles required to resolve it may further increase. For systems requiring maximum availability it is therefore not recommended to span a transaction through more than one bridge.

Note that the 1PC commit optimization should not be used with outbound bridged transactions in which the subordinate may contain more than one Participant. Even where only one Participant is used, crash recovery logs may not correctly reflect the actual transaction outcome. The 1PC optimization is on be default and may be disabled by setting <property name="commitOnePhase">false </property> on CoordinatorEnvironmentBean.

See the 'Design Notes' appendix for detailed information on potential crash recovery scenarios and how each is handled.

5.3. Using the Transaction Bridge

5.3.1. Introduction

This section describes how to use the transaction bridge in your applications. It is recommended you first read the preceding chapters for a theoretical background in the way the bridge functions.

5.3.2. Enabling

TXBridge is integrated with the XTS subsystem of the WildFly Application Server. The XTS subsystem is enabled using the standalone-xts.xml configuration

Procedure: Starting WildFly Application Server with XTS Enabled
  1. Change to the WildFly Application Server directory:

    cd $JBOSS_HOME

  2. Copy the example XTS configuration into the configurations directory:

    cp docs/examples/configs/standalone-xts.xml standalone/configuration

  3. Start WildFly Application Server, specifying the xts configuration:

    Linux:

    bin/standalone.sh --server-config=standalone-xts.xml

    Windows:

    bin\standalone.bat --server-config=standalone-xts.xml

5.3.3. Inbound Bridging

To use the inbound bridge, register the JAX-WS handler into the handler chain of any Web Service as follows:

Registering the handler for Inbound Bridging
<handler-chain>
    <protocol-bindings>##SOAP11_HTTP</protocol-bindings>
    <handler>
        <handler-name>TransactionBridgeHandler</handler-name>
        <handler-class>org.jboss.jbossts.txbridge.inbound.JaxWSTxInboundBridgeHandler</handler-class>
    </handler>

    <handler>
        <handler-name>WebServicesTxContextHandler</handler-name>
        <handler-class>com.arjuna.mw.wst11.service.JaxWSHeaderContextProcessor</handler-class>
    </handler>
</handler-chain>

The web service may then operate as though running in the scope of a JTA transaction, as indeed it is. For example, it can call (or indeed simply be) an EJB3 business logic method annotated with @TansactionAttribute(TransactionAttributeType.MANDATORY).

Note that the handlers expect a WS-AT transaction context to be present on all inbound invocations. If you wish deploy your service in such a way as to make transactional invocation optional, you must expose it though two different endpoints, one transactional and one not, with the handlers registered only on the former. This limitation may be addressed in future versions.

If WS-AT transaction context contains transaction timeout then the bridged JTA transaction is created with this timeout. If the context does not provide the information then the bridged JTA transaction is created with the default timeout defined by the container.

5.3.4. Outbound Bridging

To use the outbound bridge, register the JAX-WS handler into the handler chain of any Web Service client application as follows:

Registering the handler for Outbound Bridging
<handler-chain>
    <protocol-bindings>##SOAP11_HTTP</protocol-bindings>
    <handler>
        <handler-name>TransactionBridgeHandler</handler-name>
        <handler-class>org.jboss.jbossts.txbridge.outbound.JaxWSTxOutboundBridgeHandler</handler-class>
    </handler>

    <handler>
        <handler-name>WebServicesTxContextHandler</handler-name>
        <handler-class>com.arjuna.mw.wst11.client.JaxWSHeaderContextProcessor</handler-class>
    </handler>
</handler-chain>

The web service client may then make calls to web service implementations that expect to be invoked in the scope of a WS-AT transaction.

Note that the handlers expect a JTA transaction context to be present on the client thread used to make the outbound web service invocation. If the context is not always present, different stubs must be used for the transactional and non-transactional cases and the handler chain registered only on the former. This limitation may be addressed in future versions.

5.3.5. Loops and Diamonds

In distributed environments that utilize transaction bridging, it is possible to construct arrangements of servers such that a transaction context passes though more than one interposition. These can give rise to some undesirable issues, including locking and performance problems.

A simple case would be a loop in which a JTA transaction context is bridged outbound to a WS-AT context, passed though one or more remote servers and inflowed back to the original server through an inbound bridge. This may result in a new subordinate JTA context, rather than reuse of the existing parent context in the original server.

This situation has two main observable effects. Firstly, the parent JTA transaction and indirectly subordinate JTA transaction are considered distinct and XAResources may not be shared between them. In most cases this will cause isolation between the transactions, such that they do not share locks or see eachother’s changes. This may cause deadlocks in the application. Secondly, performance will be poor relative to reuse of the original context, particularly if the interposition chain becomes long.

A similar problem exists where a transaction context is propagated from a single source to a single destination server via two or more separate routes, the abstract paths forming a diamond shape. In such case the intermediate nodes operate independently and will bridge the original context to two separate interposed contexts. To the destination server these will appear unrelated, rather than as representations of the same transaction. Thus instead of recombining into a single shared transaction context at the destination, they will behave as different transactions, giving rise once again to potential deadlock and performance issues.

These problems may be partially addressed by having a shared context mapping service available on the network, which each bridge consults when working with a previously unseen transaction context for the first time. Using such a mechanism, bridge instances may identify transactions for which an established mapping already exists and reuse that relationship rather than creating a new one.

This shared service model does however cause some issues of its own with regard to performance and availability. It is not currently implemented. Therefore, users are urged to be cautious when constructing distributed applications. Whilst location abstraction is sometimes desirable, is is important to maintain a clear understanding of the deployment relationships between transactional components in the system.

5.3.6. Distributed JTA and the JTS

The JavaEE transaction engine in Narayana comes in two varieties. These are the local only JTA, which does not support propagation of transaction context or transaction control calls between JVMs and the JTAX, which provides the JTA API implemented by a JTS engine that does support distributed usage.

WildFly Application Server

uses the local JTA implementation by default, but can be reconfigured to use the JTS via the JTA API, such that it supports distributed transactions without requiring any changes to business applications.

In environments requiring transaction propagation of JTA transactions, it is feasible to use either the JTS or an outbound and inbound bridge pair to achieve this. In the former case the transport is RMI/IIOP for the transaction control and RMI/IIOP or JRMP for the transactional business logic calls. In the latter case the transport is Web Services for both transaction control and business logic.

From a transaction management perspective the JTS solution is preferred, due to simplicity (no protocol mapping is needed), maturity (Narayana JTS was the world’s first JTS implementation and has been extensively used and tested in production environments) and performance (binary vs. xml).

It is possible to use transactions that propagate context on some calls via JTS and on others via Web Services, such as a client invoking both EJBs via RMI/IIOP and Web services with WS-AT context. In such cases it’s possible for a transaction to have multiple representations that the infrastructure cannot determine are related, even if they actually represent different contexts in the same interposition hierarchy. Care must therefore be taken to avoid the problems described previously in 'Loops and Diamonds'.

5.3.7. Logging

The transaction bridge uses the jboss-logging system. When running inside WildFly Application Server, logging is configured via logging subsystem’s configuration in standalone-xts.xml file. To enable full logging for the transaction bridge, which may be useful for debug purposes, the following logger should be added:

Configuring Transaction Bridge Logging
<logger category="org.jboss.jbossts.txbridge">
    <level name="ALL"/>
</logger>

Note that the transaction bridge is a thin layer on top of the XTS and JTA/JTS components of Narayana, and that it also interacts with other parts of the application server. To gain a comprehensive understanding of the system’s operation, it may be necessary to enable verbose logging for some of these other components also. The Narayana logging system is discussed in detail in the accompanying documentation set, but for ease of reference the following may be used to enable verbose logging:

Configuring verbose logging
<logger category="com.arjuna">
    <level name="ALL"/>
</logger>

Note also that deployment ordering issues can result in Narayana components, including the transaction bridge, becoming active before the logging system is fully configured. In such cases a default logging level may apply during startup, resulting in some more detailed debug messages being missed.

5.4. Known Limitations

The current transaction bridge release has the following limitations:

  • The bridge operates only on WS-AT 1.2, not 1.0, although XTS includes implementations of both versions of WS-AT. Care must therefore be taken to deploy and configure the system correctly.

  • The bridge provides JAX-WS handlers only, not JAX-RPC, although it is possible to create such if required.

  • Long running activities that occur during the transaction termination process may cause timeouts in the transaction system, which can in turn cause inconsistent transaction outcomes or incomplete transaction termination. To minimize this problem, it is advised to manually flush data that would otherwise be flushed by Synchronizations during termination, such as hibernate session state.

  • A transaction context must always be present on the Thread in order for the context processors to operate correctly, as detailed previously in 'Using the Transaction Bridge'.

  • A subordinate transaction context will be created and registered into the parent transaction unconditionally, which can cause unnecessary overhead in situations where no transactional activity takes place in the scope of the subordinate. Care should be taken to register the bridge handlers only on methods that do require them. In future releases this may be addressed by the use of WS-Policy or lazy initialization techniques.

  • Transaction mappings are local to BridgeManagers, which are singletons. This means mappings are classloader scoped and not shared across JVMs. This gives rise to issues where transactional resources are accessed indirectly though multiple bridges or transaction context transports, as described in 'Loops and Diamonds'.

  • Crash recovery is subject to certain timing issues, due to the interaction between recovery of the JTA/XA and XTS sides of the transaction. It may take more than one crash recovery cycle for a bridged transaction to recover fully. Note that recovery of subordinate transactions is dependent on the recovery of their parent, so care must be taken to ensure the correct recovery of any external transaction manager used in that role. The transaction bridge does not currently provide dedicated tooling for the manual resolution of orphaned subordinates, instead relying on the general purpose objectstore maintenance tooling provided by Narayana.

  • Note that crash recovery will not behave correctly for outbound bridged transactions if 1PC commit optimization is used in the parent JTA transaction. This is not specific to the bridge, but rather is a generic issue with any transaction in which a single resource is an interposed subordinate coordinator. Inbound bridges transactions are unaffected as XTS (WS-AT) does not utilize a 1PC optimization.

5.5. Design Notes

5.5.1. General Points

This section records key design points relating to the bridge implementation. The target audience for this section is software engineers maintaining or extending the transaction bridge implementation. It is unlikely to contain material useful to users, except in so far as they wish to contribute to the project. An in-depth knowledge of Narayana internals may be required to make sense of some parts of this appendix.

The txbridge is written as far as possible as a user application layered on top of the JTA and XTS implementations. It accesses these underlying components through standard or supported APIs as far as possible. For example, XAResource is favored over AbstractRecord, the JCA standard XATerminator is used for driving subordinates and so on. This facilitates modularity and portability.

It follows that functionality required by the bridge should first be evaluated for inclusion in one of the underlying modules, as experience has shown it is often also useful for other user applications. For example, improvements to allows subordinate termination code portability between JTA and JTS, and support for subordinate crash recovery have benefited from this approach. The txbridge remains a thin layer on top of this functionality, containing only purpose specific code.

The 'loops and diamonds' problem boils down to providing deterministic, bi-directional 1:1 mapping between an Xid (which is fixed length) and a WS-AT context (which is unbounded length in the spec, although bounded for instances created by the XTS). Consistent hashing techniques get you so far with independent operation, but the only 100% solution is to have a shared service on the network providing the mapping lookup. Naturally this then becomes a single point of failure as well as a scalability issue. For some scenarios it may be possible to use interceptors to propagate the Xid on the web services call as extra data, instead of trying to reproduce the mapping at the other end. Unfortunately XA does not provide for this kind of extensibility, although CORBA does, leading to the possibility of solving the issue without a centralized approach in mixed JTS+WS-AT environments.

Requiring a tx context on all calls is a bit limiting, but JBossWS native lacks a WS-Policy implementation. Things may change with the move to CXF. This is really a wider issue with XTS, not just the bridge.

5.5.2. Crash Recovery Considerations

As usual with transactions, it’s the crash recovery that provides for the most complexity. Recovery for the inbound and outbound sides is handled independently. Because of event ordering between recovery modules (JTA, XTS), it requires two complete cycles to resolve some of these crash recovery situations.

Inbound Crash Recovery

An inbound transaction involves at least four log writes. Top down (i.e. in reverse order of log creation) these are: The WS-AT coordinator log (assumed here to be XTS, but may be 3rd party), the XTS Participant log in the receiving server, the JCA Subordinate transaction log and at least one XA Resource Manager log (which are 3rd party e.g. Oracle).

There is no separate log created by the txbridge. The XTS Participant log inlines the Serializable BridgeDurableParticipant via its writeObject method. Recorded state includes its identity (the Xid) and the identity of the separately logged JTA subordinate tx (a Uid).

XTS is responsible for the top level coordinator log. Narayana is responsible for the JTA subordinate tx log and 3rd party RMs are each responsible for their own.

The following situations may exist at recovery time, according to the point in time at which the crash occurred:

RM log only: In this case, the InboundBridgeRecoveryManager’s `XAResourceOrphanFilter implementation will be invoked via Narayana XARecoveryModule, will recognize the orphaned Xids by their formatId (which they inherit from the JCA subordinate, which the txbridge previously created with a specially constructed inflowed Xid) and will vote to have the XARecoveryModule roll them back as no corresponding JCA subordinate log exists, so presumed abort applies.

RM log and JTA subordinate tx log: The InboundBridgeRecoverytManager’s scan of indoubt subordinate JTA transactions identifies the JTA subordinate as being orphaned and rolls it back, which in turn causes the rollback of the RM’s `XAResource.

RM log, JTA subordinate log and XTS Participant log: XTS is responsible for detecting that the Participant is orphaned (by re-sending Prepared to the Coordinator and receiving 'unknown tx' back) and initiating rollback under the presumed abort convention.

WS-AT coordinator log and all downstream logs: The coordinator re-sends Commit to the Participant and the transaction completes.

Outbound Crash Recovery

An outbound transaction involves log writes for the JTA parent transaction and the XTS BridgeWrapper coordinator. There is not a separate log created by the txbridge. The JTA tx log inlines the Serializable BridgeXAResource via its writeObject method. Recorded state includes the JTA tx id and BridgeWrapper id String. In addition a Web Service participating in the subordinate transaction will create a log. Assuming it’s XTS, the participant side log will inline any Serializable Durable2PCParticipant, effectively forming the RM log.

The following situations may exist at recovery time, according to the point in time at which the crash occurred:

RM log (i.e. XTS Participant log, inlining Serializable Durable2PCParticipant) only: XTS is responsible for detecting that the Participant is orphaned (its direct parent, the subordinate coordinator, is missing) and rolling it back. The bridge recovery code is not involved – XTS recovery deserializes and drives any app DurableParticipants directly.

RM log and XTS subordinate log: The DurableParticipant(s) (i.e. client side) and XTS subordinate coordinator / BridgeWrapper (i.e. server side) and reinstantiated by XTS. The BridgeWrapper, being subordinate to a missing parent, must be identified and explicitly rolledback by the bridge recovery code. The bridge recovery manager is itself a RecoveryModule, thus invoked periodically to perform this task. It identified its own BridgeWrapper instance from amongst all those awaiting recovery by means of an id prefix specific to the txbridge code. See JBTM-725 for further details.

RM log, XTS subordinate log and JTA parent log (with inlined BridgeXAResource): Top down recovery by the JTA recovery module drives tx to completion, taking the normal JTA parent→`BridgeXAResource`→XTS subordinate→`DurableParticipant` path. Note that if the bridge is the only XAResource in the parent, the JTA must have 1PC commit optimization disabled or it won’t write a log for recovery.

5.5.3. Test framework

The test suite for the txbridge is split along two axis. Firstly, the inbound and outbound sides of the bridge have their own test suites in a parallel code package hierarchy. These are largely mirrors, containing tests which have matching intent but different implementation details. Secondly, the tests are split between those for normal execution and those for crash recovery.

The tests use a framework consisting of a basic servlet acting as client (the code pre-dates the availability of XTS lightweight client), a basic web service as server and a set of utility classes implementing the appropriate interfaces (Participant/Synchronization/XAResource). These classes contain the bare minimum of test logic. In order to make the tests as easy to understand and modify as possible, an attempt is made to capture the entirety of the test logic within the junit test function instead of splitting it over the framework classes. To facilitate this, extensive use is made of byteman and its associated dtest library, which provides basic distributed mock-like execution tracing and configuration. You probably need to take a detour and read the dtest docs before proceeding further.

The basic tests all follow the same pattern: make a call through the bridge, following different logic paths in each test, and verify that the test resources see the expected method calls. For example, in a test that runs a transaction successfully, expect to see commit called on enlisted resources and rollback not called. For a test that configures the prepare to fail, expect to see rollback called and commit not called. The tests verify behavior in the presence of 'expected' errors e.g. prepare failures, but generally don’t cover unexpected failures e.g. exceptions thrown from commit.

Test normal execution targets in the tests/build.xml assume the server is started manually with byteman installed and has XTS, txbridge and the test artifacts deployed. Note that it also contains targets that may be called to achieve the last of these steps.

The crash rec tests start (and subsequently restart) the server automatically, but assume the that XTS, txbridge and the test artifacts are deployed. To manage the server they need to be provided with JBOSS_HOME and JAVA_HOME values in the build.xml.