8.3 Using JDO and the J2EE Connector Architecture


This section goes through how to use JDO to build a J2EE application. It covers these topics:

  • Setup and Configuration ” setting up and configuring a J2EE Connector Architecture resource adapter.

  • Connection management ” using the PersistenceManagerFactory , PersistenceManager interfaces, and the role of the J2EE Connector Architecture ConnectionFactory and Connection interfaces.

  • Transaction management ” bean-managed versus container-managed transactions and distributed transactions.

  • Security management.

8.3.1 Setup and configuration

The first step in using a JDO implementation with an Application Server is to set up and configure an instance of the J2EE Connector Architecture resource adapter provided by the JDO implementation.

The resource adapter itself is contained in a resource adapter archive or RAR file. The RAR file contains, among other things, the classes used to implement the J2EE Connector Architecture system-level contracts and a deployment descriptor (called ra.xml ). The deployment descriptor defines the classes that implement the J2EE Connector Architecture system-level contracts along with the configuration properties that are specified at deployment time. These configuration properties are akin to the properties used when creating a PersistenceManagerFactory instance ( ConnectionURL ; UserName ; Password ).

Different Application Servers provide different mechanisms for deploying an instance of a resource adapter. Some simply require the RAR file to be copied into a particular directory along with an XML configuration file containing, among other things, the configuration properties for the resource adapter instance. The deployment process results in a PersistenceManagerFactory instance being bound to a specified JNDI name. This name can then be used by a J2EE application to retrieve the PersistenceManagerFactory instance.

The PersistenceManagerFactory instance created during the deployment of the resource adapter automatically delegates connection pooling to the Application Server. It also ensures that the PersistenceManager instances are automatically enlisted in any managed transaction, as appropriate. In this case, the PersistenceManager instances delegate transaction management to the Application Server, and any attempt to explicitly start or end a transaction using JDO's Transaction interface results in a JDOUserException being thrown.

Container-Managed and Bean-Managed Transactions

A container-managed transaction is implicitly started and ended by an EJB container based on the deployment properties for a given bean. A bean-managed transaction is explicitly started and ended programmatically by the bean itself. This is done either using the javax.transaction.UserTransaction interface or via resource adapter specific APIs.


If there is no managed transaction, then JDO's Transaction interface can be used to control the transaction instead.

8.3.2 Connection management

The J2EE Connector Architecture connection management contract enables a JDO implementation to delegate connection management to an Application Server. This allows a JDO implementation to take advantage of the pooling features and quality of service guarantees offered by the Application Server. In addition, it means that administrators can use the interfaces provided by the Application Server to configure and manage all connection pools, JDO or otherwise .

8.3.2.1 Getting a PersistenceManagerFactory

After an instance of the resource adapter has been deployed, a J2EE application can use JNDI to look up the PersistenceManagerFactory instance.

This lookup would typically be done during initialization. For a Servlet, this would be done in its init() method; for an EJB, it would be in its setSessionContext() method. In both cases, an instance field defined by the class would be used to maintain a reference to the PersistenceManagerFactory instance so that the Servlet or EJB methods can use it to get PersistenceManager instances when needed.

The following code snippet shows how an EJB SessionBean would get a PersistenceManagerFactory instance. It assumes that an instance of a resource adapter was deployed using the JNDI name jdo/factory :

 
 private PersistenceManagerFactory pmf; private SessionContext ejbContext; public void setSessionContext(SessionContext context)   throws EJBException, RemoteException {   ejbContext = context;   try {     InitialContext ctx = new InitialContext();     pmf = (PersistenceManagerFactory)       ctx.lookup("java:comp/env/jdo/factory");   }   catch (NamingException e) {     throw new EJBException(       "Can't find PersistenceManagerFactory");   } } 

The following code snippet shows how a Servlet would do likewise:

 
 private PersistenceManagerFactory pmf; public void init() throws ServletException {   try {     InitialContext ctx = new InitialContext();     pmf = (PersistenceManagerFactory)       ctx.lookup("java:comp/env/jdo/factory");   }   catch (NamingException e) {     throw new ServletException(       "Can't find PersistenceManagerFactory", e);   } } 

JDO can also be used with standalone Servlet engines that do not support the J2EE Connector Architecture. In this situation, the init() method simply creates a PersistenceManagerFactory instance as per any unmanaged JDO application.

8.3.2.2 Getting a PersistenceManager

After a PersistenceManagerFactory instance has been created, a Servlet or EJB can use it to get and close PersistenceManager instances as per normal. For an EJB, each bean method would need to get a PersistenceManager instance before it does anything; for a Servlet, the doGet() and doPost() methods would do likewise.

8.3.2.3 ConnectionFactory and Connection interfaces

Because the JDO specification doesn't require a JDO implementation to support the J2EE Connector Architecture or define how the J2EE Connector Architecture should be supported, there is the possibility of variance as to how a JDO implementation supports it.

The J2EE Connector Architecture CCI defines two interfaces related to connection management: ConnectionFactory and Connection . These are equivalent in purpose to JDO's PersistenceManagerFactory and PersistenceManager interfaces. A JDO implementation may choose to use the CCI interfaces as the means of getting PersistenceManager instances. In this case, rather than looking up a PersistenceManagerFactory instance via JNDI, a ConnectionFactory instance is looked up instead. Using the getConnection() method defined on ConnectionFactory , the J2EE application would get a Connection instance. Depending on the JDO implementation, it might be possible to cast the Connection instance to a PersistenceManager directly or else use an implementation-specific API to retrieve the PersistenceManager instance from the Connection instance.

Some JDO implementations may support the use of the CCI interfaces completely interchangeably with the JDO PersistenceManagerFactory and PersistenceManager interfaces. In this case, the implementation's PersistenceManagerFactory and PersistenceManager classes also implement the CCI ConnectionFactory and Connection interfaces. Depending on the application's perspective, it can decide to be either the J2EE Connector Architecture or JDO compliant in the way it gets its connections.

8.3.3 Transaction management

The J2EE Connector Architecture transaction management contract enables a JDO implementation to delegate transaction control to an Application Server.

With Servlets, only explicit transaction control is possible. However, when using JDO to develop an EJB, it is possible to either explicitly control transactions (bean-managed transactions) or delegate transaction control to the EJB container (container-managed transactions).

8.3.3.1 Servlets

When using JDO with Servlets, the doGet() and doPost() methods would get a PersistenceManager instance, begin a transaction, do something, end the transaction, and close the PersistenceManager instance.

The following code snippet shows how the doGet() method of a Servlet works:

 
 public void doGet(   HttpServletRequest req,   HttpServletResponse res)   throws ServletException, IOException {   PersistenceManager pm = null;   try {     pm = pmf.getPersistenceManager();     Transaction tx = pm.currentTransaction();     tx.begin();     // Do something...     tx.commit();   }   catch (JDOException e) {     throw new ServletException("JDO exception", e);   }   finally {     if (pm != null && !pm.isClosed()) {       if (pm.currentTransaction().isActive()) {         pm.currentTransaction().rollback();       }       pm.close();     }   } } 

A try/finally block ensures that even in the event of an unhandled exception, the PersistenceManager instance is closed and any active transaction is rolled back.

8.3.3.2 Bean-managed transactions

When using EJB with bean-managed transactions, a bean method can either use JDO's Transaction interface or the javax.transaction.UserTransaction interface to demarcate transactions.

If using JDO's Transaction interface, the bean method would get a PersistenceManager instance, begin a transaction, do something, end the transaction, and close the PersistenceManager instance. The following code snippet shows how a bean method works in this case:

 
 public void localTransactionExample() {   PersistenceManager pm = null;   try {     pm = pmf.getPersistenceManager();     javax.jdo.Transaction tx = pm.currentTransaction();     tx.begin();     // Do something...     tx.commit();   }   catch (JDOException e) {     throw new EJBException("JDO exception");   }   finally {     if (pm != null && !pm.isClosed()) {       if (pm.currentTransaction().isActive()) {         pm.currentTransaction().rollback();       }       pm.close();     }   } } 

A try/finally block ensures that even in the event of an unhandled exception, the PersistenceManager instance is closed and any active transaction is rolled back.

If using the javax.transaction.UserTransaction interface, the bean method would begin a transaction using the begin() method on javax.transaction.UserTransaction , get a PersistenceManager instance, do something, and end the transaction using the commit() method on javax.transaction.UserTransaction . The following code snippet shows how a bean method works in this case:

 
 public void userTransactionExample() {   PersistenceManager pm = null;   UserTransaction tx = ejbContext.getUserTransaction();   try {     tx.begin();     pm = pmf.getPersistenceManager();     // Do something...     tx.commit();   }   catch (Exception e) {     throw new EJBException("Exception encountered");   }   finally {     if (pm != null && !pm.isClosed()) {       pm.close();     }   } } 

A try/finally block ensures that even in the event of an unhandled exception, the PersistenceManager instance is closed.

When using JDO's Transaction interface to demarcate transactions, each time getPersistenceManager() is called, it returns a different PersistenceManager instance (because there is no managed transaction). If one bean method calls another and each calls getPersistenceManager() , each method gets its own PersistenceManager instance. This means each bean method operates within its own transaction.

8.3.3.3 Container-managed transactions

When using EJB with container-managed transactions, the EJB container implicitly begins and ends transactions. In this case, each bean method simply gets a PersistenceManager instance, does something interesting, and closes it. The following code snippet shows how a bean method works in this case:

 
 public void containerTransactionExample() {   PersistenceManager pm = null;   try {     pm = pmf.getPersistenceManager();     // Do something...   }   finally {     if (pm != null && !pm.isClosed()) {       pm.close();     }   } } 

A try/finally block ensures that even in the event of an unhandled exception, the PersistenceManager instance is closed.

With container-managed transactions, multiple bean method invocations can be made within the same transaction (based on the transaction attribute declared for the bean methods). In this case, each time getPersistenceManager() is called, it returns the PersistenceManager instance associated with the managed transaction. This way, multiple bean methods share the same underlying PersistenceManager instance.

Because EJBs have remote interfaces, it is possible that one bean can call a method on another in a different JVM. In this situation, the bean methods cannot possibly share the same PersistenceManager instance. Instead, a PersistenceManager instance is associated with the transaction within each JVM, and the Java Transaction Service (JTS) is responsible for coordinating them all as a single, distributed transaction.

8.3.3.4 Distributed transactions

Usually, a transactional resource, like an RDBMS, manages its own transactions. When an application commits, the RDBMS itself determines whether the transaction is successful or not.

However, if an application needs to interact with several different systems but still requires transactional guarantees across all those systems, then it needs to use an external transaction manager. The external transaction manager is responsible for coordinating access to each system as a single transaction ”either all systems are updated or none are updated.

Distributed transactions are of primary use when there is a requirement to coordinate access across different systems. For example, an application may need to read a message from a queue and update a database as a single operation (to ensure that the message gets written into the database). In this situation, a distributed transaction can be used to coordinate the message queue and the database.

The J2EE Connector Architecture specification defines three classifications for resource adapters, based on their level of transaction support:

NoTransaction: The resource adapter does not support transactions. Each interaction with the EIS is an atomic operation in itself.

LocalTransaction: The resource adapter supports local transactions only. Multiple interactions to the same EIS can be coordinated transactionally , but it cannot be used as part of a distributed transaction.

XATransaction: The resource adapter supports local and distributed transactions.

Some JDO implementations provide LocalTransaction resource adapters only. This means that a bean method using JDO cannot be coordinated transactionally with another bean method, unless both methods are invoked within the same JVM and both use the same PersistenceManagerFactory instance (and therefore each method gets the same PersistenceManager instance).

If an application needs to coordinate the following transactionally:

  • Bean methods across multiple JVMs

  • Bean methods that use different PersistenceManagerFactory instances

  • Bean methods accessing other transactional systems (EIS, RDBMS)

Then the chosen JDO implementation needs to provide a XATransaction-capable resource adapter.

8.3.4 Security

Because JDO does not define its own security model and instead relies on the security provided by the underlying datastore, the J2EE Connector Architecture security contract is of less relevance to JDO than the connection and transaction contracts.

The JDO implementation's resource adapter provides an appropriate implementation of the security contract, given the underlying datastore being used. In most cases, this relies on a traditional username and password being specified when the resource adapter is deployed.



Core Java Data Objects
Core Java Data Objects
ISBN: 0131407317
EAN: 2147483647
Year: 2003
Pages: 146

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