• No results found

his transaction design pattern is most applicable when using the Command Pattern or Server Delegate Design Pattern in your ap- plication architecture. With this pattern the Server Delegate component, which is the remote entry point into the server, owns the transaction and is responsible for all transaction manage- ment. No other component, including the client components, domain services components, or persistence objects, manages transactions or even knows that they are being used.

The Command Pattern is a useful design pattern that solves many issues with regards to client-based transaction manage- ment and EJB in general. The basic principle behind this pattern is that client functionality is placed in a command and sent to the server for execution. That command may contain one or more Domain Service method invocations. However, those Domain Service method invocations are all executed on the server via a corresponding Command Implementation object rather than on the client. Use of the Command Pattern allows you to make sin- gle requests to the Domain Services components from the client and also allows transaction processing to be managed by the server rather than the client.

The Server Delegate Design pattern is a similar concept, only rather than using a framework like the Command Pattern, this pattern simply places the client-side business delegate logic in Server-based delegate objects on the server. The end results are the same; transaction processing is moved to the server and mul-

T

If you like the free online version, Please support the author & InfoQ.

Buy the printed book:

tiple requests to the server for a single client request are reduced to one.

The Server Delegate Owner transaction design pattern is a spe- cial case of the Domain Service Owner Transaction Design Pattern. The main difference between the patterns is that when used with the Command Pattern this pattern has a single object that owns the transaction rather than a component type that owns the transaction. For example, if your application has 40 Domain Service Components, with the Domain Service Owner pattern you would have 40 beans managing transactions, whereas you would only have one bean (the Command Processor) managing transactions with this pattern.

Context

Consider the following code example in EJB where a client ob- ject must make multiple calls to the server to fulfill as single business request:

public class ClientModel {

public void placeFixedIncomeTrade(TradeData trade) throws Exception {

InitialContext ctx = new InitialContext(); UserTransaction txn = (UserTransaction) ctx.lookup("java:comp/UserTransaction"); try { txn.begin(); ... Placement placement = placementService.placeTrade(trade); executionService.executeTrade(placement); txn.commit(); } catch (TradeUpdateException e) { txn.rollback(); log.fatal(e); throw e; } } }

In this case the client must use programmatic transactions to en- sure ACID properties are met within a single transactional unit of work. In this situation, not only is the client responsible for transaction management, but performance is impacted because of the multiple calls to (remote) domain services. Furthermore, in this example Domain Service objects are written in EJB as Stateless SessionBeans, further complicating the architecture. In a move towards simplifying this type of situation, we would refactor the Stateless SessionBean Domain Services to POJOs, remove transaction logic from the client, and only make a single call to the server for any given client request. We could apply either the Command Pattern or Server Delegate Design Pattern to achieve any or all of these goals. When applying either of these patterns, transaction processing that originally resided in the client layer is now moved to the server layer. The following example shows the transformed client using the Command Pat- tern:

public class ClientModel {

public void placeFixedIncomeTrade(TradeData trade) throws Exception { PlaceFITradeCommand command = new PlaceFITradeCommand(); command.setTrade(trade); CommandHandler.execute(command); } }

This is a much more simplified version of the previous code. However, the question remains as to where to place the transac- tion processing logic. In this scenario the Server Delegate Owner Transaction Design Pattern can be used to identify the compo- nents that should be responsible for transaction management and what the declarative transaction settings should be for those components.

Forces

• The Command Pattern or Server Delegate Design Pattern is used in the application architecture for client/server communication.

• The client always makes a single request to a Server Delegate to fulfill a single client request.

• ACID properties must be maintained, meaning that transaction processing is required to maintain data integ- rity.

• Domain service objects are implemented as POJOs and may be remote or local.

• The Command Processor or Server Delegate is the only entry point into the domain services from the client.

Solution

When using the Command Pattern or Server Delegate Design Pattern, the Server Delegate Owner Transaction Design Pattern can be used to specify the overall transaction design strategy for this type of application architecture. This pattern uses a compo- nent responsibility model that places the entire responsibility of transaction management on the Server Delegate component. When using the Command Pattern the Server Delegate compo- nent is implemented as a single Command Processor component that locates the corresponding command implementation object and executes the command. In EJB this component would typi- cally be implemented as a Stateless SessionBean. In Spring, it would be implemented as a Spring-managed bean (POJO). When using the Server Delegate Design pattern each functional group of client requests would be implemented as a separate Server Delegate (either a POJO in Spring or a SLSB in EJB).

The following diagram illustrates this pattern for both the EJB and Spring Frameworks:

The Server Delegate component uses declarative transactions and is assigned a transaction attribute of Required for update

methods and Supports for all read methods. The Server Delegate

component also invokes the setRollbackOnly() in update meth-

ods for application exceptions.

The application architectures that are used with this pattern are very unique. In the case of the Command Pattern, the Server Delegate is usually implemented as a Command Processor and simply accepts a Command object from the client and executes that command. Use of interfaces throughout the Command Pat- tern framework ensures that the Command Handler component,

Command Processor component, Command Implementation In- terface, and Command Interface all remain generic and

application agnostic. The transaction context established by the Server Delegate is propagated to all objects that are invoked by the Server Delegate.

In the Server Delegate Design Pattern, the Server Delegate com- ponents act as a client façade to the Domain Services

components of the application architecture. In this design pattern the client logic is essentially moved to the server and placed in the Server Delegate components.

The main drawback of these design patterns is that the Server Delegate component contains client-based logic rather than pure server-based logic. In addition, it is often difficult to implement this design pattern because the client business delegate is often times tightly bound with the web framework being used. A good example of this is in Struts, where the Action class can (and most of the times does) act as the client business delegate. Fur- thermore, it may be difficult to move client logic because code containing references to client-based objects such as HTTPSes- sion, HTTPRequest, and HTTPResponse cannot be easily moved to

the server.

However, one clear advantage of either of these design patterns is that the Domain Services components, which contain most of the business logic to process a request, are implemented as POJOs (Plain Old Java Objects) rather than EJBs. Domain Ser- vice components are therefore decoupled from the EJB

framework, making them much easier to test. Another unique aspect about the Server Delegate Owner transaction design pat- tern is that since the server delegate is usually implemented as a singleton Stateless SessionBean component, the transaction logic for the entire application resides in a single object. As a result, this is the simplest transaction design pattern to implement and maintain. Furthermore, this transaction design pattern places the burden and responsibility of transaction management a level above the Domain Service components, freeing the core server

functionality of the application from infrastructure-related as- pects such as transaction management. With this transaction design pattern Domain Service components can be written as POJOs, and since they do not contain transaction logic they are easier to test outside of the container environment.

Consequences

• The client (regardless of its type) does not contain any transaction logic and does not manage any aspect of the transaction processing.

• Since the Server Delegate component is starting and managing the transaction, update methods must invoke the setRollbackOnly() method on application exceptions.

• The transaction established by the Server Delegate is propagated to the POJO-based Domain Services objects as well as the Persistence objects used by the Domain Service (regardless of the persistence framework). Fur- thermore, none of these components contain any transaction or rollback logic.

• Server Delegate objects use declarative transactions and use a transaction attribute of Required for update-related

methods and Supports for read operations.

• To maintain ACID properties client-based objects can never start a transaction, commit a transaction, or mark a transaction for rollback.

• Persistence objects and Domain Services do not contain any transaction or rollback logic.

• If EJB 2.1 Entity Beans are used, the transaction attribute for update operations must be set to Mandatory and no

rollback logic is used. For read operations the Entity Bean method should have a transaction attribute setting of Required for Container-managed Persistence (CMP)

Entity Beans or Supports for Bean-managed Persistence

(BMP) Entity Beans.

Implementation

The following source code illustrates the implementation of this pattern for both EJB and Spring. For purposes of the coding ex- amples I will assume the Command Pattern is used. For EJB I will assume the Command Processor is implemented as Stateless SessionBean, and for Spring I will assume that the Command Processor is managed under the Spring Framework.

Enterprise JavaBeans (EJB)

Under the Command Pattern this transaction design pattern has only one component that contains transaction code (the Com- mand Processor component). Therefore, since the client does not contain any transaction code, it is only necessary to show the Server Delegate (Command Processor) code for this pattern im- plementation. The source code for the EJB Domain Service component for update and read operations is as follows (transac- tion logic is in bold):

@Stateless

public class CommandProcessorImpl implements CommandProcessor {

@TransactionAttribute(

TransactionAttributeType.SUPPORTS)

public BaseCommand executeRead(BaseCommand command) throws Exception { CommandImpl implementationClass = getCommandImpl(command); return implementationClass.execute(command); } @TransactionAttribute( TransactionAttributeType.REQUIRED)

public BaseCommand executeUpdate(BaseCommand command) throws Exception {

CommandImpl implementationClass = getCommandImpl(command); return implementationClass.execute(command); } catch (Exception e) { sessionCtx.setRollbackOnly(); throw e; } } }

The getCommandImpl() method in the above example uses reflec-

tion to load and instantiate the command implementation object. It is then executed, and the results passed back to the client via the Command object. Notice that this implementation is very much

like the Domain Service Owner transaction design pattern in that we use a transaction attribute of Supports for read operations and

a transaction attribute of Required coupled with the setRoll- backOnly() method for update-related methods.