Java EE and .NET Interoperability: Integration Strategies, Patterns, and Best Practices
After having discussed the technologies of building distributed transactions across the Java EE and .NET space, the chapter now takes a look at the patterns that can be leveraged in this space when designing enterprise applications. There are a couple of patterns that can simplify the application architecture, including Transaction Handler and the Coarse-Grained Transaction Façade. Transaction Handler
Problem Domain
When building distributed transactions, it is often necessary to have a transaction coordinator at the application level. For example, in order to create a Purchase Order, an Atomic Transaction may have to encapsulate multiple calls spanned across Java EE and .NET services, which requires the need for a transaction coordinator that resides at the application level. This may become necessary when the Java EE and .NET applications are integrated using Web services and do not rely on third-party transaction support. Solutions
Global Transaction Handler
One solution to this problem is to create a distributed transaction coordinator, which can be realized in the form of the Global Transaction Handler. This component knows what services need to be invoked as part of a distributed transaction. The handler implements logic to create a purchase order to cancel the order in case there is an error. It also is responsible for invoking application logic components in a particular order. The Global Transaction Handler is implemented as part of the system that originates the transaction. If a Java EE application initiates a distributed transaction, then the Global Transaction Handler will be implemented in Java. The handler acts as a core manager responsible for the transaction workflow. This coordinator is agnostic to what technology is used to achieve transactional interoperability. Its core logic is to control application-level transactional lifecycles. A Global Transaction Handler can be implemented as a Singleton and should encapsulate a transaction identifier to uniquely identify a transaction. The Purchase Order Transaction Handler will have the following methods defined: createOrder(TxnID txnId, PurchaseOrder order), cancelOrder(TxnID txnId), and commitOrder(TxnID txnId). A disadvantage of this solution is that the Java EE or a .NET transaction handler has to have an explicit knowledge of when and how to cancel an ongoing transaction. More importantly, because the Global Transaction Handler is defined at the initiator side, the supplier Web service provider depends on the ability and the goodwill of the initiator to perform the cancellation when appropriate. This opens up opportunities for denial-of-service style attacks and implies a significant level of trust between initiator and supplier services. Compensating Transaction Handler
An alternative solution would encompass a compensating transaction for the application-level two-phase commit. This solution can be implemented with a Compensating Transaction Handler pattern. In this scenario, if a failure or a time out occurs at any endpoint, the handler that coordinates the transaction issues a compensating transaction. A compensating transaction does not undo the failed transactions but negates their effect by compensating for it. In this example, a decrement to the product count succeeds where the purchase order creation fails. This would be followed by an instruction to reverse, or compensate, creation of the purchase order. A compensating transaction can be applied when the initiator does not know when and how to cancel the endpoint transaction or if the cancel logic is not exposed to the client application in the first place. A compensating transaction also contributes toward better performance compared to the distributed two-phase commit protocol. The disadvantage of this approach is that the compensation occurs after the initial transaction has been committed and is visible to other applications and users, thus giving up isolation of the distributed transaction. Coarse-Grained Transaction Façade
Problem Domain
In an application design where a distributed transaction encapsulates multiple calls to remote systems or services, it is important to ensure that those calls are fairly coarse-grained. Should a .NET application make multiple calls to the Java EE application as part of the transaction, it is important to evaluate the use case and possibly consolidate those calls into a single call. The main force for this pattern is to address performance and scalability concerns when building a distributed transaction. Solution
To reduce a number of operations within an Atomic Transaction, it is useful to consolidate multiple transaction calls into a single call represented by a Transaction Façade. This approach is similar to a number of documented patterns such as Session Façade from the Core Java EE Pattern Catalog or a Transaction Script from Martin Fowler's "Patterns of Enterprise Application Architecture" [POEAA]. The main difference is that the Transaction Façade acts as a gateway to the .NET or Java EE business component rather than a database or an Entity Bean. |
Категории