Wednesday, July 15, 2009

Shopping Cart Web Application - Part 8 - Spring

Introduction
The Spring Framework provides solutions to many technical challenges faced by Java developers and organizations wanting to create applications based on the Java platform. Because of the size and complexity of the functionality offered, it can be hard to distinguish the major building blocks from which the framework is composed.

The Spring Framework can be considered as a collection of smaller frameworks. Most of these frameworks are designed to work independently of each other yet provide better functionalities when used together. These frameworks are divided along the building blocks of typical complex applications:

  • Inversion of Control container - configuration of application components and lifecycle management of Java objects.
  • Aspect-oriented programming framework - working with functionalities which cannot be implemented with Java's object-oriented programming capabilities without making sacrifices.
  • Data access framework - working with relational database management systems on the Java platform using JDBC and Object-relational mapping tools providing solutions to technical challenges which are reusable in a multitude of Java-based environments.
  • Transaction management framework - harmonization of various transaction management API's and configurative transaction management orchestration for Java objects.
  • Model-view-controller framework - HTTP and Servlet based framework providing many hooks for extension and customization.
  • Remote Access framework - configurative RPC-style export and import of Java objects over computer networks supporting RMI, CORBA and HTTP-based protocols including web services (SOAP).
  • Authentication and authorization framework - configurative orchestration of authentication and authorization processes supporting many popular and industry-standard standards, protocols, tools and practices via the Spring Security sub-project (formerly Acegi).
  • Remote Management framework - configurative exposure and management of Java objects for local or remote configuration via JMX.
  • Messaging framework - configurative registration of message listener objects for transparent message consumption from message queues via JMS, improvement of message sending over standard JMS API's.
  • Testing framework - support classes for writing unit tests and integration tests.

What you need before we get started

What we will cover
  • Spring and Hibernate
  • Shopping Cart application Spring configuration file
  • Shopping Cart application Data Access Objects
  • Shopping Cart application Web Spring bean configuration file

Level
  • Beginner

The Spring Framework covers a lot of ground and we are only going to scratch the surface. We will add Spring to our Shopping Cart Application and I will show how Spring can be used to make our lives a lot easier. The main goal for this tutorial is to show you how to integrate Spring with Hibernate.

Spring and Hibernate
As learnt in the previous Hibernate tutorial Hibernate is a powerful ORM tool that lies between the Application and the Database. It enables applications to access data from any database in a platform-independent manner. There is no need for the application to depend on the low-level JDBC details like managing connection, dealing with statements and result sets. All the necessary details for accessing a particular data source is easily configurable in xml files.

One of the problems with using Hibernate is that the client application that accesses the database using Hibernate framework has to depend on the Hibernate APIs like Configuration, SessionFactory and Session. These objects will continue to get scattered across the code throughout the application. Moreover, the application code has to manually maintain and manage these objects. In the case of Spring, the business objects can be highly configurable with the help of IOC Container. It is possible to use the Hibernate objects as Spring Beans and they can enjoy all the facilities that Spring provides.

Shopping Cart application Spring configuration file
In Spring, all the business objects are configured in xml files and the configured business objects are called Spring Beans. These Spring Beans are maintained by the IOC which is given to the client application upon request.

1. Hibernate Session Example
In the Hibernate tutorial we created a hibernate.cfg.xml file. In this tutorial we are going to replace this file with a Spring bean configuration file. The Hibernate configuration will be configured in the Spring configuration class as opposed to the hibernate configuration file. The details of the Spring bean configuration file are pasted below:

shoppingcart-database.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
  <bean id="shoppingCartDataSource" class="org.apache.commons.dbcp.BasicDataSource">
    <property name="driverClassName" value="org.hsqldb.jdbcDriver" />
    <property name="url" value="jdbc:hsqldb:shoppingcart" />
    <property name="username" value="sa" />
    <property name="password" value="" />
  </bean>
  <bean id="shoppingCartSessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
    <property name="dataSource" ref="shoppingCartDataSource" />
    <property name="hibernateProperties">
      <props>
        <prop key="hibernate.dialect">org.hibernate.dialect.HSQLDialect</prop>
        <prop key="show_sql">true</prop>
        <prop key="format_sql">true</prop>
        <prop key="current_session_context_class">thread</prop>
      </props>
    </property>
    <property name="annotatedClasses">
      <list>
        <value>com.mydomain.shoppingcart.bo.Item</value>
        <value>com.mydomain.shoppingcart.bo.Basket</value>
        <value>com.mydomain.shoppingcart.bo.BasketItem</value>
      </list>
    </property>
  </bean>
  <bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    <property name="sessionFactory">
      <ref local="shoppingCartSessionFactory" />
    </property>
  </bean>
  <bean id="basketDao" class="com.mydomain.shoppingcart.dao.impl.BasketDaoImpl">
    <property name="sessionFactory">
      <ref local="shoppingCartSessionFactory" />
    </property>
  </bean>
  <bean id="itemDao" class="com.mydomain.shoppingcart.dao.impl.ItemDaoImpl">
    <property name="sessionFactory">
      <ref local="shoppingCartSessionFactory" />
    </property>
  </bean>
</beans>

1.1. shoppingCartDataSource
The shoppingCartDataSource bean defines a data-source of type 'org.apache.commons.dbcp.BasicDataSource'. More importantly, it defines the various connection properties that are needed for accessing the database. Since we are using HSQL as our database I have specified the hsqldb driver.

1.2. shoppingCartSessionFactory
The shoppingCartSessionFactory bean is responsible for creating Session objects through which Transaction and Data accessing is done. It replaces the session factory configuration we made in the Hibernate tutorial’s hibernate.cfg.xml file. We can also delete the HibernateUtil class we created in the Hibernate tutorial to get a handle on the session factory as Spring is going to do all of that for us.

1.3. transactionManager
The transactionManager bean binds a Hibernate Session from the factory to a thread to support transactions.

1.4. basketDao and itemDao
These last two beans are references to our very own data access objects. I have defined them here to tell Spring to manage the creation of these objects for me and to initialise them with the sessionFactory class.

2. JPA EntityManager Example
In the Hibernate tutorial for the JPA example we created a persistence.xml file. This file stays exactly the same. In this tutorial we are going to add a Spring bean configuration file and tell it that we are using JPA Entity Manager. The details of the Spring bean configuration file are pasted below:

shoppingcart-database.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
 xsi:schemaLocation="http://www.springframework.org/schema/beans 
      http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
      http://www.springframework.org/schema/tx 
      http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
 
 <bean id="entityManagerFactory"
  class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
  <property name="persistenceUnitName" value="shopping-cart" />
 </bean>
 
 <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
  <property name="entityManagerFactory">
   <ref local="entityManagerFactory" />
  </property>
 </bean>
 <bean
  class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
 
 <bean id="basketDao" class="com.mydomain.shoppingcart.dao.impl.BasketDaoImpl">
  <property name="entityManagerFactory" ref="entityManagerFactory" />
 </bean>
 
 <bean id="itemDao" class="com.mydomain.shoppingcart.dao.impl.ItemDaoImpl">
  <property name="entityManagerFactory" ref="entityManagerFactory" />
 </bean>
 
 <tx:annotation-driven />
</beans>

2.1. entityManagerFactory
The entityManagerFactory is a FactoryBean that creates a JPA EntityManagerFactory according to JPA's standard standalone bootstrap contract.

2.2. transactionManager
The transactionManager bean is a PlatformTransactionManager implementation for a single JPA EntityManagerFactory used to support transactions.


2.3. basketDao and itemDao
Like in the Hibernate example I have defined the DAO classes. They both extend the Spring JJpaDaoSupport helper class.

Shopping Cart application Data Access Objects

1. Hibernate Session Example
As you know we have two DAO implementations, BasketDaoImpl and ItemDaoImpl. We configured these classes already in our Spring bean configuration file so we know that Spring is going to manage the creation and initialisation of these classes for us. I have also made sure these classes both extend Springs HibernateDaoSupport class. The HibernateDaoSupport class is a convenient super class for Hibernate-based data access objects. It requires a SessionFactory to be set, providing a HibernateTemplate based on it to subclasses through the getHibernateTemplate() method.

BasketDaoImpl.java
@Transactional
public class BasketDaoImpl extends HibernateDaoSupport implements BasketDao {

    public void delete(final Basket basket) throws Exception {
        HibernateCallback callback = new HibernateCallback() {
            public Object doInHibernate(Session session) throws HibernateException, SQLException {
                Object basketObj = session.load(Basket.class, basket.getId());
                session.delete(basketObj);
                return null;
            }
        };
        getHibernateTemplate().execute(callback);
    }

    public void saveOrUpdateBasket(final Basket basket) throws Exception {
        HibernateCallback callback = new HibernateCallback() {
            public Object doInHibernate(Session session) throws HibernateException, SQLException {
                session.saveOrUpdate(basket);
                return null;
            }
        };
        getHibernateTemplate().execute(callback);
    }

    public Basket removeItemFromBasket(final BasketItem basketItem) throws Exception {
        HibernateCallback callback = new HibernateCallback() {
            public Object doInHibernate(Session session) throws HibernateException, SQLException {

                Basket basket = (Basket) session.load(Basket.class, basketItem.getBasket().getId());
                for (Iterator<BasketItem> it = basket.getBasketItems().iterator(); it.hasNext();) {
                    BasketItem existingBasketItem = (BasketItem) it.next();
                    if (existingBasketItem.getId().equals(basketItem.getId())) {
                        if (existingBasketItem.getQuantity() > 1) {
                            existingBasketItem.decreaseQuantity();
                        } else {
                            it.remove();
                        }
                    }
                }
                session.saveOrUpdate(basket);
                return basket;
            }
        };
        return (Basket) getHibernateTemplate().execute(callback);
    }
}

I will step through the saveOrUpdateBasket method only as the others are very similar. The first thing you will notice is the instantiation of an anonymous class from a Spring interface called HibernateCallback.

There is one method inside this class called doInHibernate. This method will be called by the HibernateTemplate’s execute method. An active Hibernate session is passed to this method. As you can see we don’t care about activating or closing the Session, or handling transactions. This is all taken care of by Spring.

2. JPA Entity Manager Example
The BasketDaoImpl class in the JPA sample application extends Springs helper class (JpaDaoSupport):

BasketDaoImpl.java
@Transactional
public class BasketDaoImpl extends JpaDaoSupport implements BasketDao {

    public void delete(Basket basket) throws Exception {
        basket = getJpaTemplate().find(Basket.class, basket.getId());
        getJpaTemplate().remove(basket);
    }

    public Basket update(Basket basket) throws Exception {
        return getJpaTemplate().merge(basket);
    }
    
    public Basket removeItemFromBasket(BasketItem basketItem) throws Exception {
        Basket basket = getJpaTemplate().find(Basket.class, basketItem.getBasket().getId());
        for (Iterator<BasketItem> it = basket.getBasketItems().iterator(); it.hasNext(); ) {
            BasketItem existingBasketItem = (BasketItem) it.next();
            if (existingBasketItem.getId().equals(basketItem.getId())) {
                if (existingBasketItem.getQuantity() > 1) {
                    existingBasketItem.decreaseQuantity();
                } else {
                    it.remove();
                }
            }
        };
        return getJpaTemplate().merge(basket);
    }
}

Shopping Cart application Web Spring bean configuration file
I created a Spring bean configuration file for the web project as well. The main reason for this was so that I would let Spring manage the creation and retrieval of our ShoppingManager service. I created a file called applicationContext.xml and saved it in the WebContent/WEB-INF directory.

applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
 xsi:schemaLocation="http://www.springframework.org/schema/beans 
      http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
 <bean id="shoppingService" class="com.mydomain.shoppingcart.service.impl.ShoppingManager">
  <property name="itemDao">
   <ref bean="itemDao" />
  </property>
  <property name="basketDao">
   <ref bean="basketDao" />
  </property>
 </bean>
 <import resource="classpath:shoppingcart-database.xml" />
</beans>
Post a Comment