Saturday, January 9, 2010

Shopping Cart Web Application - Part 7 - TopLink and EAR

I recently received a response from someone who was stepping through my Shopping Cart Web Application tutorial and who wanted to deploy the application on GlassFish and use TopLink Essentials (EclipseLink) as the reference implementation for JPA as opposed to Hibernate.

Thankfully there wasn't that much change that needed to be made to the existing ShoppingCartHibJpaPart7 application. This application (ShoppingCartTopLinkJpaPart7.zip) is available to download in case anyone would like to take a look. I chose to use EclipseLink which is the successor to TopLink. In order to get it working with GlassFish 2.0 there are a few simple steps to take. The biggest change I needed to make was in the persistence.xml file:

<persistence xmlns="http://java.sun.com/xml/ns/persistence"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
    http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
 version="1.0">

 <persistence-unit name="shopping-cart"
  transaction-type="RESOURCE_LOCAL">
  <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
  <non-jta-data-source>jdbc/__shoppingcart</non-jta-data-source>
  <exclude-unlisted-classes>false</exclude-unlisted-classes>
  <properties>
   <property name="eclipselink.ddl-generation" value="drop-and-create-tables" />
   <property name="eclipselink.logging.level" value="FINE" />
  </properties>
 </persistence-unit>
</persistence>
The real difference here is the use of EclipseLink properties as opposed to Hibernate properties. I also had to define the non-jta-data-source attribute. Another one of the requirements was to have GlassFish manage the database connections so my application needed to be configured to lookup the resource via the datasource JNDI name.

Java Transaction API  (JTA) inside a web application
After doing this I was asked if I could change the transaction type from RESOURCE_LOCAL to JTA. In order to do this I made the following changes:

I changed the value of the transaction-type in the persistence.xml file from RESOURCE_LOCAL to JTA and changed the non-jta-data-source attribute to jta-data-source.

Secondly I needed to do a JNDI lookup for the EntityManager managed by the container, one way is to do it by annotation on the Dao class:

@PersistenceContext(name="persistence/ShoppingCart", unitName="shopping-cart")
public class BasketDaoImpl implements BasketDao {

and then the lookup:

Context ctx = new InitialContext();
em =  (EntityManager) ctx.lookup("java:comp/env/persistence/ShoppingCart");

Our application is managing the transaction however in a JTA entity manager entityManager.getTransaction() calls are not permitted so instead I needed to get a UserTransaction by doing a JNDI lookup for the UserTransaction:

Context ctx = new InitialContext();
(UserTransaction)ctx.lookup("java:comp/UserTransaction");

If you are interested in seeing how I implemented this you can download the ShoppingCartJtaTopLinkJpaPart7.zip file and view the DAO classes in the shopping-cart-core-jta-toplink-jpa-part7 project.

BasketDaoImpl.java
@PersistenceContext(name="persistence/ShoppingCart", unitName="shopping-cart")
public class BasketDaoImpl implements BasketDao {

  public Basket updateBasket(Basket basket) throws Exception {
    EntityManager em = null;
    UserTransaction utx = null;
    try {
      em = JPAUtil.getEntityManager();
      utx = JPAUtil.getUserTransaction();
      utx.begin();
      basket = em.merge(basket);
      utx.commit();
      return basket;
    } catch (RuntimeException e) {
      if (utx != null) {
        utx.rollback();
      }
      throw e;
    }
  }

Java Transaction API  (JTA) inside a JEE application
In this example our application is going to make use of an EJB session bean. Unlike in the previous example where our application was controlling the transaction via the UserTransaction class here the container will manage and control the transaction for us. Once again you can download the full source of the ShoppingCartEJBTopLinkJpaPart7.zip file and take a look at what I did.

Using JEE annotations it was very simple to turn the ShoppingManager class into a session bean. The @PersistenceContext annotation was used to obtain an EntityManager instance and you will also notice I got rid of the DAO classes as there really was no need for them anymore as the container manages the transaction.

ShoppingManager.java
@Stateless(name="ShoppingManager")
public class ShoppingManager implements ShoppingService {

  @PersistenceContext(unitName="shopping-cart")
  private EntityManager em;

  public Basket updateBasket(Basket basket) throws ShoppingException {
    try {
      return em.merge(basket);
    } catch (Exception e) {
      logger.error("There was an error updating the basket, exception: " + e);
      throw new ShoppingException("There was an error updating the basket", e);
    }
  }

All these applications were written in Eclipse and tested in a GlassFish 2.0 application server.
Post a Comment