Section 16.5. Some Common Programming Scenarios


16.5. Some Common Programming Scenarios

In this section, we'll look at some of the most common transaction scenarios and we'll examine ways to leverage transactions effectively.

The subsection "Using a Session Façade" provides a concrete example of how to use CMTD effectively with an EJB component by minimizing the number of unnecessary transactions and increasing performance.

The subsection "Using Transaction Attributes with CMTD" illustrates an approach for utilizing transaction attributes with CMTD EJBs. This approach can help avoid resorting to BMTD in some situations.

The subsection "Distributed Transactions Involving a JMS Destination and Database" provides a detailed example of a distributed transaction using both JMS and JDBC resources.

16.5.1. Using a Session Façade

Consider the code fragment in Example 16-3, which uses a Person EJB component. Assume that the EJB has been deployed using the Required transaction attribute applied to all of its methods. How many transactions does the user invoke in total? The answer is four. Each EJB method, create( ), setWorkPhone( ), setHomePhone( ), and getPersonId( ), is invoked in a different transaction. This is most likely not the intended behavior. This code is not only very expensive but also may be incorrect. For example, if there is some error setting the home phone number, the client might expect the creation of a person bean instance to fail.

Example 16-3. Direct usage
     PersonHome aPersonHome =       (PersonHome) aInitialContext.lookup("java:comp/env/ejb/Person");     Person p = aPersonHome.create       (aPersonValue.getEmail( ), aPersonValue.getPassword( ));     p.setWorkPhone(aPersonValue.getWorkPhone( ));     p.setHomePhone(aPersonValue.getHomePhone( ));     sLogger.info("Created a person with id : " + p.getPersonId( )); 

The most common solution to this problem is using the session façade pattern. In brief, this pattern involves creating a stateless session bean that acts as a simple frontend, or façade, to hide the complexity behind it. You refactor the code from the client into a stateless session bean as illustrated in Example 16-4. This session bean would also be deployed using the Required transaction attribute on its methods. If a client invokes the createPersonSameTransaction( ) method, a transaction begins and the methods of the Person bean, create( ), setWorkPhone( ), setHomePhone( ), and getPersonId( ), are now invoked in one single transaction.

Example 16-4. Code fragment from session façade
     public PersonValue createPersonSameTransaction(PersonValue aPersonValue) {         return createPerson(aPersonValue);     }     protected PersonValue createPerson(PersonValue aPersonValue) {         sLogger.info("5 creating person in manager cmtd bean ...");         try {             InitialContext aInitialContext = new InitialContext( );             PersonHome aPersonHome =               (PersonHome) aInitialContext.lookup("java:comp/env/ejb/Person");             Person p = aPersonHome.create(aPersonValue.getEmail( ),                                           aPersonValue.getPassword( ));             p.setWorkPhone(aPersonValue.getWorkPhone( ));             p.setHomePhone(aPersonValue.getHomePhone( ));             sLogger.info("Created a person with id : " + p.getPersonId( ));             aPersonValue.setPersonId(p.getPersonId( ));         } catch (Exception e) {             String aMessage =               "exception in manager cmtd bean.createPersonNewTransaction ";             sLogger.log(Level.SEVERE, aMessage, e);             throw new EJBException(aMessage, e);         }         return aPersonValue;     } 

Is there another way to approach this problem? An alternative is to use client-managed transaction demarcation as illustrated in Example 16-5. The EJB methods are called directly from the client, but the client begins and ends its own singular transaction. Example 16-5 illustrates this approach. While this does solve the problem, the client code has become more complex by taking on programmatic transaction management. Unless this is strictly necessary (e.g., the client has very specific transaction boundary needs that don't apply in general), the session façade approach is preferable.

Example 16-5. Client-managed transaction demarcation usage
     InitialContext aInitialContext = new InitialContext( );     UserTransaction aUserTransaction = (UserTransaction)         aInitialContext.lookup("java:comp/UserTransaction");     try {         aUserTransaction.begin( );         PersonHome aPersonHome =           (PersonHome) aInitialContext.lookup("java:comp/env/ejb/Person");         Person p = aPersonHome.create(aPersonValue.getEmail( ),                                       aPersonValue.getPassword( ));         p.setWorkPhone(aPersonValue.getWorkPhone( ));         p.setHomePhone(aPersonValue.getHomePhone( ));         sLogger.info(" created a person with id : " + p.getPersonId( ));         aUserTransaction.commit( );     } catch (Exception e) {         try {             aUserTransaction.rollback( );         } catch (Exception aException) {             String aMessage =               "Exception occured in client command.execute transaction rollback";             sLogger.log(Level.SEVERE, aMessage, aException);             throw aException;         }         String aMessage = "Exception occured in client command.execute ";         sLogger.log(Level.SEVERE, aMessage, e);         throw e;     } 

16.5.2. Using Transaction Attributes with CMTD

Consider the following example. In a very simple object model, there is a Person EJB and a PersonStatus bean. You would like to create a Person with PersonStatus. However, you would like the creation of Person to succeed regardless of whether the PersonStatus is valid. Suppose this part of the EJB is implemented in the form of a createPersonAndStatus( ) method, as shown in Example 16-6.

Example 16-6. Create Person and PersonStatus
     public PersonValue createPersonAndStatus(         PersonValue aPersonValue,         PersonStatusValue aPersonStatusValue) {         aPersonValue = createPersonNewTransaction(aPersonValue);         aPersonStatusValue = createPersonStatus(aPersonValue,                              aPersonStatusValue);         return aPersonValue;     } 

If your bean is using CMTD and you wanted to enforce the requirements as detailed, you might set the transaction attribute for the createPersonAndStatus( ) method to Required and the transaction attribute for createPersonNewTransaction( ) method to RequiresNew. You might expect that this would cause a new transaction to be created for the createPersonNewTransaction( ) method, suspending the one on createPersonAndStatus( ).

But does the code fragment in Example 16-6 work as intended? Is the createPersonNewTransaction( ) method executed in a new transaction? No! The container uses the same transaction for both methods because it never has an opportunity to intercept the second method call and start a new transaction. Example 16-7 illustrates how to invoke the second EJB method through the container, allowing it to apply the intended transaction attributes.

Example 16-7. Create Person with interception
     public PersonValue createPersonAndStatusNew(         PersonValue aPersonValue,         PersonStatusValue aPersonStatusValue     ) throws RemoteException {         aPersonValue = ((ManagerCMTD) mSessionContext.getEJBObject( ))           .createPersonNewTransaction(aPersonValue);         aPersonStatusValue = createPersonStatus(aPersonValue,                              aPersonStatusValue);         return aPersonValue;    } 

Using the session context, you obtain a client reference to the EJBObject being invoked. You cast the EJBObject stub to the correct type (ManagerCMTD, in this example) and then invoke the createPersonNewTransaction( ) method. Since you invoke the method on a client stub acquired from the container (just like any other client), the method request will be intercepted by the container, and it has an opportunity to apply the requested transaction attributes.

16.5.3. Distributed Transactions Involving a JMS Destination and Database

As discussed in the "Database and message queue" section earlier in this chapter, a distributed transaction involving a message destination and a database is a common use of distributed transactions in enterprise applications. Here is a detailed example of such a case. In this example, the application retrieves and processes a message from a queue and inserts the data into the database. The entire process, as illustrated in Figure 16-10, from the message retrieval to the database insert, happens in one transaction.

Figure 16-10. Distributed transaction detailed example


An instance of a message-driven bean, CreatePersonBean retrieves a message from PersonQueue. The message is of type javax.jms.ObjectMessage. In the onMessage( ) callback, the message-driven bean retrieves an instance of PersonValue from the object message. The bean invokes the createPersonSameTransaction( ) method on the ManagerCMTD stateless session bean as shown in Example 16-8. The ManagerCMTD bean persists the data to the database using the Person entity bean.

Example 16-8. CreatePersonBean message-driven bean
     ObjectMessage aObjectMessage = (ObjectMessage) aMessage;     PersonValue aPersonValue = (PersonValue) aObjectMessage.getObject( );     InitialContext aInitialContext = new InitialContext( );     ManagerCMTDHome aManagerCMTDHome =         (ManagerCMTDHome) aInitialContext.lookup           ("java:comp/env/ejb/ManagerCMTD");     ManagerCMTD aManagerCMTD = aManagerCMTDHome.create( );     aPersonValue = aManagerCMTD.createPersonSameTransaction(aPersonValue);     sLogger.info("Created a person with id : " + aPersonValue.getPersonId( )); 

To ensure that the message retrieval happens in a transaction, you use CMTD for the CreatePersonBean as shown in an excerpt from the EJB deployment descriptor in Example 16-9. If there are any errors or exceptions in the entire process, the entire set of operations in the transaction is rolled back, including message retrieval from the JMS destination. If configured this way, the container redelivers the message so that the application makes another attempt to process the message.

Example 16-9. CMTD configuration for CreatePersonBean
 <container-transaction>     <description>       Specify all create person bean methods to run in a transaction     </description>     <method>         <description>All methods of create person Bean</description>         <ejb-name>CreatePerson</ejb-name>         <method-name>*</method-name>     </method>     <trans-attribute>Required</trans-attribute> </container-transaction> 



Java Enterprise in a Nutshell
Java Enterprise in a Nutshell (In a Nutshell (OReilly))
ISBN: 0596101422
EAN: 2147483647
Year: 2004
Pages: 269

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net