Java EE and .NET Interoperability: Integration Strategies, Patterns, and Best Practices

A transaction is often defined as a unit of work that results in either success or failure and fulfills Atomic, Consistent, Isolated, and Durable (ACID) principals [ACID]. For instance, in the procurement system depicted in Figure 12-1, the purchase order processing depends on the inventory check service, which verifies that the selected product is in stock. Once the selected product availability is positively checked, the stock inventory is updated and a purchase order is created. Following is a discussion regarding what individual ACID properties mean and how they apply in the purchase order scenario.

Figure 12-1. Distributed transaction scenario

Atomicity

Individual operations of a transaction should all be successfully completed or rolled back as if they are a single operation. In the preceding example, changes to the product count and the purchase order creation must be all successfully completed or be rolled back, thus appearing as a single, Atomic, unit of work. In case of an application error, the system should restore all modified data to its original state. Similarly, if a purchase order gets cancelled, there should be a corresponding update to the product count in the inventory.

Consistency

Modified or rolled back data must remain in a consistent state across application components that access the data. These application components include objects and records. Consistency helps to ensure that referential and integrity constraints remain in a coherent state. In this example, the inventory system references the Supply Chain Management system, and a new product request is generated when the product count is low. If the product count does not decrement correctly, the Supply Chain Management may not request new products on time. Therefore it is important to maintain consistency across application data by encapsulating business requirements into the application logic or enforcing corresponding constraints at the database level. Transaction systems don't give the guarantee of consistencyit is the responsibility of the application level to handle this.

Isolation

Isolation implies that concurrent users or applications should have the impression of being the only users of the data. At the system level, Isolation is usually implemented with locks. In the purchase order example, when decrementing the product counter, a write lock should be set to avoid potentially overselling a product. An application should deny requests for the product count information while this product count is being modified. Only after all changes are committed or rolled back should the data be available to the rest of the requests. The Isolation property helps to protect uncommitted changes from being accessed by other application components. For performance reasons, so-called Isolation levels allow this property to be relaxed for particular applications. The Isolation level determines how isolated this transaction is from the rest of the transactions. Individual transaction Isolation levels and their effects are discussed in the next section.

Durability

Any modifications to the data have to be permanent regardless of any software or hardware failures occurring after transaction completion. This is often achieved by storing individual transaction steps in a persistent store. For instance, in Figure 12-1, the purchase order is being saved into the database. Once the purchase order transaction commits, all changes made to the data are permanent, and critical information will not be lost. If an error occurs prior to modifications committed to the database, changes should roll back, thus leaving the system in the original state, as per the Atomicity property. There is never a 100 percent guarantee of durability and that the rollback will restore everything perfectly, as there are a number of factors that can cause failures, but transactable managed systems are the best way of getting the best possible durability.

Distributed Transaction

A transaction can span across different applications and resources. In the Distributed Transaction Scenario diagram, Figure 12-1, a transaction encapsulates calls to Java EE and .NET applications. Another example of a distributed transaction involves different resources, that is, databases or file systems. The .NET application can be configured with MSSQL server for storing inventory data, while the Java EE application can be configured with Oracle RDBMS for coordinating a purchase order. Managing a transaction distributed across multiple systems significantly complicates an implementation to adhere to the basic ACID tenets. Synchronizing ACID qualities across multiple transaction managers can be achieved with the Two-Phase Commit (2PC) protocol to ensure atomicity and durability, in combination with two-phase locking (2PL) to ensure isolation. The RDBMS and the program logic are responsible for the consistency. In the context of the Java EE and .NET interoperability, support for distributed transaction varies depending on the integration technology.

Two-Phase Commit (2PC) Protocol

The two-phase commit protocol enables the Atomicity in a distributed transaction scenario. The system module responsible for this protocol is usually called a transaction manager or a coordinator. As the name implies, there are two phases to the protocol. In the first phase, the coordinator asks each participant to vote on a commit or a rollback. This is accomplished by sending a so-called prepare request to each participant. When a participant votes for a commit, it loses its right to roll back independently, meaning that it has to wait for the final outcome received from the coordinator. The first phase ends when the coordinator receives all votes or if a timeout occurs. The second phase starts with the final decision made by the coordinator. In the case of a timeout or at least one "rollback" vote, the decision to roll back is sent to each participant that voted for "commit" in the first phase. As a result, all data modifications at all places involved are rolled back. Should all participants vote to commit, then and only then, the coordinator decides to perform a global commit and sends a commit notification to all participants. Consequently, all the work at all places is committed.

The complexity of the two-phase commit relates not only to the distributed nature of a transaction, but also to a possible non-atomic outcome of a transaction, i.e. heuristics. For example, the first participant may commit changes during phase two, while the second participant encounters a hardware failure when saving changes to the disk. Being able to roll back or at least notify the errors to recover the system into the original state is an important part of the process.

By persisting intermediate steps of the 2PC, that is, logging abort, ready to commit, and commit messages, the protocol provides a certain degree of reliability in case the coordinator or participants fail in the midst of transaction processing. The two-phase commit protocol can be implemented in a synchronous or asynchronous manner with variations to its actual execution.

Architect's Note

For the Java EE-.NET integration it is important to determine which transactional characteristics have to be carried out. It is fairly common that not all of the ACID qualities need to be fulfilled at the same time. Business requirements and the Service Level Agreement (SLA) often act as core drivers for selecting or eliminating support for some of the ACID properties. In the purchase order example, overselling a product may be perfectly acceptable from the business, data availability, and performance standpoints. Assessing technical artifacts against well-defined business requirements is essential in determining to which individual characteristics of a transaction the integration scenario has to adhere. Additionally, defining boundaries of a transaction can impact the level of complexity required during the actual implementation.

Категории