Using JDO in CMT Session Beans


In CMT session beans (whether stateless or stateful), each business method should begin by obtaining a persistence manager and end by closing it. The persistence manager should not be cached in a bean's member field between business method invocations. Obtaining a persistence manager from the factory at the start of the business method in a CMT bean ensures that the persistence manager is enlisted in the managed transaction.

Although the EJB container is managing transactions, it may, or may not, end the transaction when the business method returns. If the container started the transaction, it will end the transaction; otherwise, the originator of the transaction controls when the transaction ends.

When the application code closes the persistence manager, the close affects the persistence manager only when the transaction ends. The closing is in effect delayed until the transaction ends. If the client calls the bean again in the same transactional context, the persistence manager associated with the transactional context will be reused. On the other hand, when the transaction ends, the close allows either the persistence manager or its resources to be reused in another transaction. In short, closing the persistence manager at the end of the business method in a CMT session bean ensures that resources are recycled.

Likewise, managed persistent objects cannot be cached in the bean's member fields after the persistence manager is closed. (Recall that JDO does not define the behavior of managed objects after the persistence manager is closed.) If desired, unmanaged application data objects can be stored in a bean's member fields either as the service state of a stateless session bean or as the conversational state of a stateful session bean.

Listing 6-6 contains an example of a session bean that uses CMT. This session bean could be either stateful or stateless. As far as the JDO issues are concerned, the code is the same for both. The example bean implements, as do all of the other EJB examples in this chapter, the QuoteServer business interface. The QuoteServer interface has two methods, getQuote and addQuote. The getQuote method returns a Quote object. The addQuote method creates a Quote object and makes it persistent.

Listing 6-6: Example of a CMT Session Bean That Uses JDO

start example
 // CMT Session bean package com.ysoft.jdo.book.sayings.service.session; import com.ysoft.jdo.book.sayings.persistent.*; import com.ysoft.jdo.book.sayings.service.*; import com.ysoft.jdo.book.factory.JndiLocator; import com.ysoft.jdo.book.sayings.persistent.QuoteManager.QuoteManagerOID; import com.ysoft.jdo.book.common.ejb.EJBHelper; import javax.jdo.*; import javax.ejb.*; import java.util.*; public class QuoteServerEJB implements SessionBean, QuoteServer    {    // state that passivation preserves    private SessionContext              sessionContext;    private PersistenceManagerFactory   pmf;    public void ejbCreate() throws CreateException       {       }    public void ejbRemove()       {       }    public void setSessionContext(SessionContext sc)       {       sessionContext = sc;       try          {          pmf = JndiLocator.getPMF("EE_PMF",                "com/ysoft/jdo/book/sayings/service/factory.properties");          }       catch (Exception e)          {          throw new EJBException("Unable to get PMF using \"EE_PMF\" name: ", e);          }       }    public void ejbActivate()       {       }    public void ejbPassivate()       {       }    public Quote getQuote() throws QuoteServerException       {       PersistenceManager pm = null;       try          {          pm = getPersistenceManager();          QuoteManager qm = getQuoteManager(pm);          return (Quote) EJBHelper.respond(getQuote(pm, qm));          }       finally          {          if (pm != null)             {             pm.close();             }          }       }    public void addQuote(String q, String s) throws QuoteServerException       {       q = normalizeString(q);       s = normalizeString(s);       PersistenceManager pm = null;       try          {          pm = getPersistenceManager();          QuoteManager qm = getQuoteManager(pm);          Quote quote = qm.newQuote(q, s);          pm.makePersistent(quote);          }       finally          {          if (pm != null)             {             pm.close();             }          }       }    private PersistenceManager getPersistenceManager()       {       return pmf.getPersistenceManager();       }    private String normalizeString(String s) throws QuoteServerException       {       if (s != null)          {          s = s.trim();          if (s.length() <= 0)             s = null;          }       if (s == null)          throw new QuoteServerException(                "Neither the quotation nor the source can be null or empty");       return s;       }    private QuoteManager getQuoteManager(PersistenceManager pm)       {       return getQuoteManager(pm, true);       }    private QuoteManager getQuoteManager(PersistenceManager pm,          boolean createIfNone)       {       return getQuoteManager(pm, createIfNone,             new QuoteManagerOID(QuoteManager.getSingletonKey()));       }    private QuoteManager getQuoteManager(PersistenceManager pm,          boolean createIfNone, QuoteManagerOID key)       {       QuoteManager quoteManager = null;       try          {          quoteManager = (QuoteManager) pm.getObjectById(key, true);          }       catch (JDODataStoreException e)          {          // do nothing here, creation follows next          }       // create one and only QuoteManager, if it doesn't exist,       // but only if correct key is used       if (quoteManager == null && createIfNone)          {          if (!QuoteManager.getSingletonKey().equals(key.toInteger()))             throw new EJBException("Cannot create a quote manager with key " +                   key + "; use Integer(1) instead");          quoteManager = QuoteManager.newQuoteManager();          pm.makePersistent(quoteManager);          }       return quoteManager;       }    private Quote getQuote(PersistenceManager pm2, QuoteManager qm2)          throws QuoteServerException       {       Query query = getQuery(pm2);       return getQuote(pm2, qm2, query);       }    private Quote getQuote(PersistenceManager pm2, QuoteManager qm2, Query query)          throws QuoteServerException       {       try          {          // qet a random quote          Quote quote = null;          if (qm2 == null || qm2.getNumQuotes() < 1)             quote = QuoteManager.makeTempQuote("Nothing to say", "The System");          else             {             int index = qm2.getRandomIndex();             Collection results = (Collection) query.execute(new Integer(index));             Iterator iter = results.iterator();             if (iter.hasNext())                {                quote = (Quote) iter.next();                if (iter.hasNext())                   throw new QuoteServerException(                         "more than one quote with index: " + index);                }             else                {                throw new QuoteServerException("No quote for index: " + index);                }             }          return quote;          }       finally          {          if (query != null)             query.closeAll();          }       }    private Query getQuery(PersistenceManager pm2)       {       Extent extent = pm2.getExtent(Quote.class, false);       Query query = pm2.newQuery(extent, "quoteIndex == i");       query.declareParameters("Integer i");       return query;       }    } 
end example

In Listing 6-6, all of the private methods of the bean are shown. In the later code listings, private methods that are unchanged from earlier listings are omitted for brevity.

In this application, the Quote is one application data class and the QuoteManager is the other. The persistent QuoteManager object is a singleton in the database. It keeps track of the number of quotes, provides a factory for new Quote objects, and can generate a valid random quote index for looking up a quote.

A persistence manager factory is obtained from JNDI in setSessionContext. It is held during the lifetime of the bean. If desired, in the stateful CMT session bean, ejbPassivate can clear the reference to the persistence manager factory, and ejbActivate can reacquire it. Doing this may save resources during passivation, but it slows down activation. There is no reason to write code for ejbActivate and ejbPassivate in a stateless session bean since the container does not passivate stateless beans.

Both business methods in the QuoteServer bean may throw a QuoteServerException. Since the QuoteServer is a simple EJB, there is no need to force a rollback by calling the setRollbackOnly method in the javax.ejb.SessionContext interface when the QuoteServerException arises. In more complex beans, careful consideration of exception handling is an important part of the bean's design.

Most of the code that calls JDO is wrapped in a try block. JDO exceptions are not caught because the simple bean code shown here does not know how to recover from these error conditions. Since JDO exceptions are derived from java.lang.RuntimeException, they cause the EJB container to roll back the transaction, and they cause the container to discard the bean instance. Following the try block, the finally block closes the query results and the persistence manager.

Notice that the code closes the persistence manager before the EJB container has the opportunity to complete the transaction. When using JDO with container-managed transactions, this usage is required. The implementation ensures that the persistence manager does not close until the container completes the transaction.

When two methods within the bean use the same pattern to acquire and close persistence managers, if one method calls the other, the second one gets the same persistence manager as the first if a managed transaction is active. None of the calls to close the persistence manager actually close the persistence manager until the container completes the transaction. Each acquisition of a persistence manager should match with one and only one call to close it.

The code show in Listing 6-6 comes from the stateful_cmt/QuoteServerEJB.java source file in the com.ysoft.jdo.book.sayings.service.session package. The quote server examples are included in the JDO Learning Tools. These examples show implementations of the QuoteServer business interface for four kinds of session beans and an entity bean. Some of these beans use a connection factory, and some use a persistence manager factory. Either optimistic or datastore transactions can be configured. Chapters 8 through 11 discuss the various tools and example programs in the JDO Learning Tools. Chapter 11 describes how to build and run the quote server examples.




Using and Understanding Java Data Objects
Using and Understanding Java Data Objects
ISBN: 1590590430
EAN: 2147483647
Year: 2005
Pages: 156
Authors: David Ezzio

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