CHAPTER 4

images

Introduction to Enterprise Spring

This chapter introduces several of the APIs supported by the core Spring Framework, including Java Database Connectivity (JDBC), object-relationship management, transactions, and remoting. Many of the interfaces from this support will appear in the corresponding components in Spring Integration and other frameworks that build on them.

Data Access Framework

Access to a relational database is a common requirement for most enterprise applications. JDBC is a part of Java SE that defines a set of standard APIs for access to relational databases in a vendor-independent fashion.The purpose of JDBCis to provide an API through which SQL statements may be executed against a relational database. However, when using JDBC, database-related resources and database exceptions must be handled explicitly outside of the API. To simply using JDBC, Spring provides an abstraction framework for interfacing with JDBC. At the heart of the Spring JDBC framework, the JdbcTemplate, is designed to provide convenient callback methods for different type of operations. Many of the template methods are convenience methods that reduce operations to one-liners; however there are also methods that take callbacks. These callbacks are lower level and surface the most interesting parts of the raw JDBC API.

If raw JDBC will not satisfy your requirements or if your application would benefit from higher-level abstraction, then Spring’s support for Object Relational Mapping (ORM) solutions will interest you. In this section, you will also learn how to integrate ORM frameworks into your Spring applications. Spring supports most of the popular ORM and data mapping frameworks, including Hibernate, JDO, and Java Persistence API (JPA). Classic TopLink is not supported starting from Spring 3.0, but because TopLink shifted focus from internal native (classic) to JPA via EclipseLink. Spring’s JPA support may be used for TopLink. The focus of this section will be on JDBC, Hibernate ORM, and JPA. Spring’s support for these ORM frameworks is consistent, so it can be easily applied to other ORM frameworks as well.

ORM lets developers map objects to database tables. Usually, the mapping is of object properties to database table columns. Once a database schema is correctly mapped, a developer may query and update the database using plain old objects, evading most of the low-level SQL that is being generated by the ORM framework. Hibernate, one of the most popular open source ORM frameworks community, and supports most JDBC-compliant databases. Beyond the basic ORM features, Hibernate supports more advanced features such as collection mapping, bi-directional associations, filters, and componentized mappings. Hibernate supports the variations between SQL vendors through SQL dialects. Hibernate provides a powerful querying language called Hibernate Query Language (HQL) that provides the ability to write simple but powerful object queries.

JPA defines a set of standard annotations and APIs for object persistence in both the Java SE and Java EE platforms. JPA is defined as part of the EJB 3.0 specification in JSR-220. You can compare JPA with the JDBC API and a JPA engine with a JDBC driver. Hibernate can be configured as a JPA-compliantengine through an extension module called Hibernate EntityManager. This section will mainly demonstrate JPA with Hibernate as the underlying engine.

Selecting a Relational Model

We are going to define a simple model and application for stock inventory and order processing whose major functions are the basic Create, Read, Update, and Delete (CRUD) operations on an inventory of stocks and a collection of orders. The entities will be stored in a relational database and accessed by JDBC using Spring’s JdbcTemplate.

Before diving into the stock inventory order application, we must select a database. To minimize memory consumption and simplify configuration, we will used the embedded H2 database. H2 is a full-featured, open source relational database engine implemented in pure Java. This lends itself towards ease-of-deployment, and configurability. However, any JDBC-compliant database may be used with these examples.

H2 can run in either the embedded mode or the client/server mode. For our purposes, the embedded mode is appropriate because it allows the example code to quickly setup, and teardown entire table schemas and datasets. The following Maven dependencies shown in Listing 4–1 are required for the following examples.

Listing 4–1. Enabling H2 for your Application - pom.xml

<dependency>
   <groupId>cglib</groupId>
   <artifactId>cglib-nodep</artifactId>
   <version>2.2</version>
</dependency>
<dependency>
   <groupId>com.h2database</groupId>
   <artifactId>h2</artifactId>
   <version>1.2.144</version>
</dependency>

This example will take an approachof designing table a schema that has a close match between domain object properties and relational model columns. In other words, we simply create a near one to one relationship between table and domain model. H2 provides plenty of options for creating and defining tables complete with primitive types, constraints, indexes, and more. The SQL script for creating the STOCK table is shown in Listing 4–2.

Listing 4–2. STOCKS Table Definition Script stocks.ddl.sql

drop table STOCKS;

create table STOCKS (
  ID SERIAL,
  INVENTORY_CODE VARCHAR(25) NOT NULL,
  SYMBOL VARCHAR(4),
  EXCHANGE_ID VARCHAR(10),
  PRICE_PER_SHARE DECIMAL (6,2) NOT NULL,
  QUANTITY_AVAILABLE INTEGER NOT NULL,
  PURCHASE_DATE DATE NOT NULL,
  CONSTRAINT PK_STOCKID PRIMARY KEY (ID),
  CONSTRAINT INV_CODE UNIQUE(INVENTORY_CODE)
);

The Stock domain object is shown in Listing 4–3.

Listing 4–3. Stock Domain Object

package com.apress.prospringintegration.springenterprise.stocks.model.;

import java.util.Date;

public class Stock {
    int id;
    String inventoryCode;
    String symbol;
    String exchangeId;
    float sharePrice;
    int quantityAvailable;
    Date purchaseDate;

    // Getters and Setters removed for brevity

}

Configuring an Embedded Data Source

Configuringthe Spring context for an embedded database is simple: use the jdbc namespace to enable the embedded-database namespace elements. The embedded-database element enables application context bootstrapping and creates the javax.sql.DataSource. The type of database may be specified with the type attribute;it supports H2, HSQL, and DERBY. The script element lets you select a SQL script that will run when the data source is constructed. This gives you a chance to initialize database schemas. This is very useful in a testing environment. For more flexible initialization, use the initialize-database element to specify the specific SQL/DDL scripts and the type of failures to ignore. The Spring configuration file for configuring the embedded data source is shown in Listing 4–4.

Listing 4–4. Spring Configuration for Connecting to Embedded database data-access.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:jdbc="http://www.springframework.org/schema/jdbc"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/tx
    http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd     
    http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/jdbc
    http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd">

  <context:property-placeholder location="StocksJDBC.properties"/>
  <context:component-scan
      base-package="com.apress.prospringintegration.springenterprise.stocks.dao.jdbc"/>
  <jdbc:embedded-database type="H2" id="h2DataSource"/>

  <jdbc:initialize-database data-source="h2DataSource" ignore-failures="DROPS">
    <jdbc:script location="/STOCKS.DDL.SQL"/>
  </jdbc:initialize-database>

</beans>

Configuring a Remote Data Source

The javax.sql.DataSource is a standard interface defined by the JDBC specification that factories java.sql.Connection instances. There are many DataSource connection pool implementations provided by different vendors and projects: C3PO and Apache Commons DBCP are popular open-source options, and most applications servers will provide their own implementation. It is very easy to switch between different data source implementations, because of the common DataSource interface. Spring also provides several convenient but less powerful data source implementations. The simplest one is org.springframework.jdbc.datasource.DriverManagerDataSource, which opens a new connection every time it is requested. The database properties and Java configuration are shown in Listings 4–5 and 4–6, respectively.

Listing 4–5. Configuration of a JDBC DataSource Properties StockJDBC.properties

jdbc.url=jdbc:h2:tcp://localhost/~/test
jdbc.username=sa
jdbc.password=
jdbc.driver=org.h2.Driver

Listing 4–6. JavaConfiguration for Data Source

package com.apress.prospringintegration.springenterprise.stocks.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DriverManagerDataSource;

import javax.sql.DataSource;

@Configuration
public class StocksBaseConfig {

    @Value("${jdbc.url}")
    String jdbcUrl;

    @Value("${jdbc.username}")
    String username;

    @Value("${jdbc.password}")
    String password;

    @Value("#{h2DataSource}")
    DataSource embeddedDataSource;

    @Bean
    public DataSource dataSource() {
        return embeddedDataSource;
    }

    // Remote Data Source ( just for illustrating remote connection )
    @Bean
    public DataSource remoteDataSource() {
        return new DriverManagerDataSource(jdbcUrl, username, password);
    }
}

DriverManagerDataSource is not an efficient data source implementation, because it opens a new connection for the client every time it is requested. Another data source implementation provided by Spring is the org.springframework.jdbc.datasource.SingleConnectionDataSource (a DriverManagerDataSource subclass). As its name indicates, this maintains only a single connection that is reused all the time and never closed. Obviously, it is not suitable in a multithreaded environment.

Spring’s own data source implementations are mainly used for testing purposes. However, many production data source implementations support connection pooling. For example, the Database Connection Pooling Services (DBCP) module of the Apache Commons Library has several data source implementations that support connection pooling. Of these, BasicDataSource accepts the same connection properties as DriverManagerDataSource and allows you to specify the initial connection size and maximum active connections for the connection pool.

Basic JdbcTemplate Usages

The org.springframework.jdbc.core.JdbcTemplate class declares a number of overloaded update, query, and execute methods that enable control of the overall query and update task.  For example, different varieties of the update method allow you to choose how ResultSets are interpreted into application-specific objects, and thus manipulated. JdbcTemplate is threadsafe, which implies that it can be injected into your service and DAO objects, which must sustain concurrent access from clients. To use the JdbcTemplate, create an instance of it and pass in the data source for this template as a constructor argument. The JdbcTemplate configuration is shown in Listing 4–7.

Listing 4–7. Configuration of JdbcTemplate as an IoC dependency

package com.apress.prospringintegration.springenterprise.stocks.dao.jdbc;

import com.apress.prospringintegration.springenterprise.stocks.config.StocksBaseConfig;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
import org.springframework.jdbc.core.JdbcTemplate;

@Configuration
@ImportResource("classpath:data-access.xml")
public class StocksJdbcConfig extends StocksBaseConfig {

    // JDBC Template
    @Bean
    public JdbcTemplate jdbcTemplate() {
        return new JdbcTemplate(dataSource());
    }
}

There are two options to provide the JdbcTemplate dependency to a DAO or other data repository: simply use a setter method or extend JdbcDaoSupport. Extending JdbcDaoSupport provides the advantage of not having to determine whether the template has been initialized, in addition to other sanity checks. The super class org.springframework.jdbc.core.support.JdbcDaoSupport exposes the getJdbcTemplate method for your subclass to retrieve the template instance. In this example, we will define a very simple data model, Data Access Object (DAO) interface (see Listing 4–8) and implementation (see Listing 4–9), and a few key JdbcTemplate callback implementations that illustrate its usage.

Listing 4–8. The DAO Interface for the Stock Mode.

package com.apress.prospringintegration.springenterprise.stocks.dao;

import com.apress.prospringintegration.springenterprise.stocks.model.Stock;

import java.util.List;

public interface StockDao {

    public void insert(Stock stock);

    public void update(Stock stock);

    public void delete(Stock product);

    public Stock findByInventoryCode(String iCode);

    public List<Stock> findAvailableStockBySymbol(String symbol);

    public List<Stock> get();
}

Listing 4–9. TheJdbcTemplateStockDAO featuring JdbcTemplate

package com.apress.prospringintegration.springenterprise.stocks.dao.jdbc;

import com.apress.prospringintegration.springenterprise.stocks.dao.StockDao;
import com.apress.prospringintegration.springenterprise.stocks.model.Stock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.PreparedStatementCreator;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.stereotype.Component;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

@Component
public class JdbcTemplateStockDao implements StockDao {
    private JdbcTemplate jdbcTemplate;

    @Autowired
    public void setJdbcTemplate(JdbcTemplate t){
        this.jdbcTemplate = t;
    }

    public void insert(Stock stock) {
        KeyHolder keyHolder = new GeneratedKeyHolder();
        this.jdbcTemplate.update(new PSStockCreater(stock), keyHolder);

        stock.setId(keyHolder.getKey().intValue());
    }

    @Override
    public void update(final Stock stock) {
        jdbcTemplate.update(new PreparedStatementCreator() {
            public PreparedStatement createPreparedStatement(Connection connection)
                    throws SQLException {
                String sql = "UPDATE STOCKS SET SYMBOL = ?, INVENTORY_CODE = ?, " +
                        "PRICE_PER_SHARE = ?, QUANTITY_AVAILABLE = ?, " +
                        "EXCHANGE_ID = ?, PURCHASE_DATE = ? where ID = ?";
                PreparedStatement ps = connection.prepareStatement(sql);
                ps.setString(1, stock.getSymbol());
                ps.setString(2, stock.getInventoryCode());
                ps.setFloat(3, stock.getSharePrice());
                ps.setFloat(4, stock.getQuantityAvailable());
                ps.setString(5, stock.getExchangeId());
                ps.setDate(6, new java.sql.Date(stock.getPurchaseDate().getTime()));
                ps.setInt(7, stock.getId());
                return ps;
            }
        });
    }

    @Override
    public void delete(Stock stock) {
        jdbcTemplate.update("delete from STOCKS where id = ?", stock.getId());
    }

    @Override
    public List<Stock> findAvailableStockBySymbol(String symbol) {
        String sql = " SELECT * from STOCKS" +
                " WHERE SYMBOL = ? order by PRICE_PER_SHARE";
        List<Stock> ret = jdbcTemplate.query(
                sql,
                new Object[]{symbol},
                new RowMapper<Stock>() {
                    public Stock mapRow(ResultSet rs, int rowNum) throws SQLException {
                        Stock s = new Stock(
                                rs.getString("SYMBOL"),
                                rs.getString("INVENTORY_CODE"),
                                rs.getString("EXCHANGE_ID"),
                                rs.getFloat("PRICE_PER_SHARE"),
                                rs.getInt("QUANTITY_AVAILABLE"),
                                rs.getDate("PURCHASE_DATE")
                        );
                        return s;
                    }
                });

        return ret;
    }

    @Override
    public List<Stock> get() {
        List<Stock> ret = jdbcTemplate.query("select * from STOCKS", new StockMapper());
        return ret;
    }

    @Override
    public Stock findByInventoryCode(String iCode) {
        String sql = " SELECT * from STOCKS" +
                " WHERE INVENTORY_CODE = ?";
        return jdbcTemplate.queryForObject(sql,
                new Object[]{iCode},
                new StockMapper());
    }
}

JdbcTemplate Callback Interfaces

The org.springframework.jdbc.core package defines two callback interfaces – PreparedStatementCreator and RowCallbackHandler – that let you tailor how PreparedStatements are created and specify how rows (javax.sql.ResultSets) should be mapped to objects, respectively. You can implement any of these callback interfaces and pass its instance to the corresponding update method on JDBCTemplate to complete the selected task. In this example, we define a PSStockCreater class that has the task of inserting data into the STOCKS table, as shown in Listing 4–10.

Listing 4–10. APreparedStatementCreater Implementation

package com.apress.prospringintegration.springenterprise.stocks.dao.jdbc;

import com.apress.prospringintegration.springenterprise.stocks.model.Stock;
import org.springframework.jdbc.core.PreparedStatementCreator;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;

public class PSStockCreater implements PreparedStatementCreator {
    private Stock stock;

    public PSStockCreater(Stock stock) {
        this.stock = stock;
    }
    public PreparedStatement createPreparedStatement(Connection connection)
            throws SQLException {
        String sql =
                "INSERT INTO" +
                        "STOCKS (SYMBOL, INVENTORY_CODE, PRICE_PER_SHARE," +
                        "QUANTITY_AVAILABLE, EXCHANGE_ID, PURCHASE_DATE) " +
                        " VALUES (?, ?, ?, ?, ?, ?)";
        PreparedStatement ps =
                connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);

        ps.setString(1, stock.getSymbol());
        ps.setString(2, stock.getInventoryCode());
        ps.setFloat(3, stock.getSharePrice());
        ps.setFloat(4, stock.getQuantityAvailable());
        ps.setString(5, stock.getExchangeId());
        ps.setDate(6, new java.sql.Date(stock.getPurchaseDate().getTime()));
        return ps;
    }
}

Since the STOCKS table makes use of an auto-generated column, the generated value must be maintained for subsequent updates. The Connection.prepareStatement method exposes a second argument to specify how to obtain any auto-generated keys. The simplest option is passing the constant java.sql.Statement.RETURN_GENERATED_KEYS. Or, an array of strings may be passed specifying the column names that possess auto-generation, for example, ID. In this case a KeyHolder class implementation must be supplied to hold these auto-generated values. In Listing 4–11, an instance of GeneratedKeyHolder is provided as the second argument to the method jdbcTemplate.update, then GeneratedKeyHolder instance is interrogated for key values upon successful SQL operation completion.

Listing 4–11. Invoking the JdbcTemplateand with a Callback

package com.apress.prospringintegration.springenterprise.stocks.dao.jdbc;

import com.apress.prospringintegration.springenterprise.stocks.dao.jdbc.PSStockCreater;

@Component
public class JdbcTemplateStockDao implements StockDao {
//…
    @Override
    public void insert(Stock stock) {
        KeyHolder keyHolder = new GeneratedKeyHolder();
        jdbcTemplate.update(new PSStockCreater(stock), keyHolder);
        stock.setId(keyHolder.getKey().intValue());
    }
//…
}

Standard updates look almost nothing like regular JDBC code, in that the update query text include the argument replacement values. Spring will go an extra step and determine the SQL types for the arguments you pass in. In this regard, simple update and query operations can fit into oneline. Listing 4–12 uses JdbcTemplate.update method to simply delete rows.

Listing 4–12. Using JdbcTemplate to update a table

    @Override
    public void delete(Stock stock) {
        jdbcTemplate.update("delete from STOCKS where id = ?", stock.getId());
    }

Using JdbcTemplate to Query

As with updates, Spring provides a way to execute queries using a number of overloaded query methods to streamline query execution and result generation. A best practice is to use the org.springframework.jdbc.core.RowMapper<T> interface in JdbcTemplate code to yield the most compact code. Like PreparedStatementCreator, it is best to decide how your code uses a ResultSet, and extract that recipe out accordingly; either inline or in a separate (and re-usable) implementation class.  The RowMapper<T> interface has a single method, mapRow, which you’re expected to implement to construct an object. Depending on the query function, a single object or multiple objects may be returned as the method’s return value. When using queryForObject method to return single domain objects, as shown in Listing 4–13, you need to ensure that your query will always return only one single row of data, otherwise a IncorrectResultSizeDataAccessException is thrown.

Listing 4–13. Method using RowMapper<T>Inline to Obtain aSingle ObjectInstance

    @Override
    public Stock findByInventoryCode(String iCode) {
        String sql = " SELECT * from STOCKS" +
                " WHERE INVENTORY_CODE = ?";
        return jdbcTemplate.queryForObject(sql, new StockMapper(), iCode );
        // the last argument is a varargs array
    }

The RowMapper<Stock> implementation as an external class is shown in Listing 4–14.

Listing 4–14. RowMapper<Stock>Implementation

package com.apress.prospringintegration.springenterprise.stocks.dao.jdbc;

import com.apress.prospringintegration.springenterprise.stocks.model.Stock;
import org.springframework.jdbc.core.RowMapper;
import java.sql.ResultSet;
import java.sql.SQLException;

public class StockMapper implements RowMapper<Stock> {
    public Stock mapRow(ResultSet rs, int rowNum) throws SQLException {
         Stock stock = new Stock(
                                 rs.getString("SYMBOL"),
                                 rs.getString("INVENTORY_CODE"),
                                 rs.getString("EXCHANGE_ID"),
                                 rs.getFloat("PRICE_PER_SHARE"),
                                 rs.getInt("QUANTITY_AVAILABLE"),
                                 rs.getDate("PURCHASE_DATE")
                         );
        stock.setId(rs.getInt("ID"));
                         return stock;
    }
}

An implementation of RowMapper<T> as an inline class is shown in Listing 4–15. The query method returns a List of Stock objects.

Listing 4–15. Method using RowMapper<T> to Return a List of Objects

    @Override
    public List<Stock> findAvailableStockBySymbol(String symbol) {
        String sql = " SELECT * from STOCKS" +
                " WHERE SYMBOL = ? order by PRICE_PER_SHARE";
        List<Stock> ret = jdbcTemplate.query(
                sql,
                new Object[]{symbol},
                new RowMapper<Stock>() {
                    public Stock mapRow(ResultSet rs, int rowNum) throws SQLException {
                        return new Stock(
                                rs.getString("SYMBOL"),
                                rs.getString("INVENTORY_CODE"),
                                rs.getString("EXCHANGE_ID"),
                                rs.getFloat("PRICE_PER_SHARE"),
                                rs.getInt("QUANTITY_AVAILABLE"),
                                rs.getDate("PURCHASE_DATE")
                        );
                    }
                });

        return ret;
    }

The JdbcTemplateStockDao may be exercised by using the main class shown in Listing 4–16. The Spring context is created and a reference to the JdbcTemplateStockDao is obtained. Two Stock instances are inserted into the database and the first instance is retrieved using the findByInventoryCode method.

Listing 4–16. Example main Class for JdbcTemplate

package com.apress.prospringintegration.springenterprise.stocks.runner;

import com.apress.prospringintegration.springenterprise.stocks.dao.StockDao;
import com.apress.prospringintegration.springenterprise.stocks.model.Stock;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.Calendar;

public class MainJdbcTemplate {
    public static void main(String[] args) {
        GenericApplicationContext context =
                new AnnotationConfigApplicationContext(
                        "com.apress.prospringintegration.springenterprise.stocks.dao.jdbc");
        StockDao stockDao =
                context.getBean("jdbcTemplateStockDao", StockDao.class);
        Stock stock = new Stock("ORAC", "JDBCTPL0001", "QQQQ", 120.0f, 1100,
                Calendar.getInstance().getTime());
        stockDao.insert(stock);

        stock = new Stock("APRS", "JDBCTPL0002", "QQQQ", 150.00F, 1500,
                Calendar.getInstance().getTime());
        stockDao.insert(stock);

        stock = stockDao.findByInventoryCode("JDBCTPL0001");

        if (stock != null) {
            System.out.println("Template Version");
            System.out.println("Stock Symbol :" + stock.getSymbol());
            System.out.println("Inventory Code :" + stock.getInventoryCode());
            System.out.println("purchased price:" + stock.getSharePrice());
            System.out.println("Exchange ID:" + stock.getExchangeId());
            System.out.println("Quantity Available :" + stock.getQuantityAvailable());
        }
    }
}

As noted, this style of DAO implementation uses JDBC directly, and even with templates it employs redundant boilerplate code. Eventually, your application will become burdened with this infrastructure code, and DAO methods will get much larger and less maintainable. In addition to boilerplate code, JDBC does not make handling relationships easy; associated entities must be handled on a per-use basis by creating and persisting the object in the DAO. Executing another query through the same or separate DAO solves this, or as will be shown next, by using an ORM framework.

Integrating Hibernate 3 and Spring

To use Hibernate, your applications will need the following library dependencies. The required dependencies are shown in Listing 4–17.

Listing 4–17. Maven Dependency Setup to Use Hibernate pom.xml

<dependency>
  <groupId>org.hibernate</groupId>
  <artifactId>hibernate-core</artifactId>
  <version>3.3.2.GA</version>
</dependency>
<dependency>
  <groupId>org.hibernate</groupId>
  <artifactId>hibernate-annotations</artifactId>
  <version>3.4.0.GA</version>
</dependency>
<dependency>
  <groupId>org.hibernate</groupId>
  <artifactId>hibernate-commons-annotations</artifactId>
  <version>3.3.0.ga</version>
</dependency>
<dependency>
  <groupId>org.hibernate</groupId>
  <artifactId>hibernate-entitymanager</artifactId>
  <version>3.4.0.GA</version>
</dependency>
<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-log4j12</artifactId>
  <version>1.5.6</version>
</dependency>

To map entity classes using Hibernate XML mappings, a single mapping file may be used for each class or a large file supporting several classes. In practice, one mapping file for each class should be used following the naming convention of appending the class name with .hbm.xml for ease of maintenance. Based on this convention, the mapping file for the Stock class will be named stocks.hbm.xml.

Listing 4–18. Defining the Hibernate Mapping XML Configuration stocks.hbm.xml

<!DOCTYPE hibernate-mapping
    PUBLIC "-//Hibernate/Hibernate Mapping DTED 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.apress.prospringintegration.springenterprise.stocks.model">
  <class name="Stock" table="STOCKS">
    <id name="id" type="int" column="ID">
      <generator class="identity"/>
    </id>
    <property name="symbol" type="string">
      <column name="SYMBOL" length="5" not-null="true"/>
    </property>
    <property name="exchangeId" type="string" column="EXCHANGE_ID"/>
    <property name="quantityAvailable" type="int" column="QUANTITY_AVAILABLE"/>
    <property name="sharePrice" type="float" column="PRICE_PER_SHARE"/>
    <property name="purchaseDate" type="date" column="PURCHASE_DATE"/>
    <property name="inventoryCode" type="string" column="INVENTORY_CODE"/>
  </class>
</hibernate-mapping>

In the mapping file, the table name will be specified for the entity class and a table column for each property. In addition, column details such as column length, not-null constraints, and unique constraints may be specified. Also, each entity must have an identifier defined, which can be generated automatically or assigned manually. In this example, the identifier will be generated using a table identity column.

Each application that uses Hibernate requires a global configuration file to configure properties such as the database settings (either JDBC connection properties or the data source’s JNDI name), the database dialect, the mapping metadata’s locations, and so on. When using XML mapping files to define mapping metadata, the locations of the XML files must be specified. By default, Hibernate will read hibernate.cfg.xml from the root of the classpath. If there is a hibernate.properties file on the classpath, that file will be consulted first with the XML file taking precedence. The Hibernate configuration file is shown in Listing 4–19.

Listing 4–19. Hibernate Configuration File hibernate.cfg.xml

<!DOCTYPE hibernate-configuration PUBLIC
    "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
  <session-factory>
    <property name="hibernate.dialect">org.hibernate.dialect.H2Dialect</property>
    <property name="hiberante.show_sql">true</property>
    <property name="hibernate.format_sql">true</property>
    <mapping resource="stocks.hbm.xml"/>
  </session-factory>
</hibernate-configuration>

Configuring a Hibernate SessionFactory

The Hibernate org.hibernate.SessionFactory is used for all access to the database through the domain objects. The Java configuration for the SessionFactory is shown in Listing 4–20.

Listing 4–20. Java configuration Defining a Hibernate SessionFactory

package com.apress.prospringintegration.springenterprise.stocks.dao.hibernate;

import com.apress.prospringintegration.springenterprise.stocks.config.StocksBaseConfig;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
import org.springframework.core.io.Resource;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.orm.hibernate3.LocalSessionFactoryBean;

@Configuration
@ImportResource("classpath:hibernate-data-access.xml")
public class StocksHibernateConfig extends StocksBaseConfig {

    @Value("hibernate.cfg.xml")
    private Resource hibernateConfigResource;

    Resource hibernateConfigResource() {
        return hibernateConfigResource;
    }

    // Local Session Factory for getting hibernate connections
    @Bean
    LocalSessionFactoryBean sessionFactory() {
        LocalSessionFactoryBean sb = new LocalSessionFactoryBean();
        sb.setDataSource(dataSource());
        sb.setConfigLocation(hibernateConfigResource());
        return sb;
    }

    // Hibernate Template
    @Bean
    public HibernateTemplate hibernateTemplate() {
        return new HibernateTemplate(sessionFactory().getObject());
    }
}

Before you can persist your records, the tables will need to be created in a database schema to store the object data. When using an ORM framework like Hibernate, you are not required to design the tables by yourself. If the hbm2ddl.auto property is set to update, Hibernate will update the database schema and create the tables when necessary. Naturally, this option should not be enabled in production, but it can be a great speed boost for development.

The Hibernate Template

Although you can access Hibernate using the SessionFactory directly, an easier method is to use the provided org.springframework.orm.hibernate3.HibernateTemplate. Similar to the JdbcTemplate, Spring’s HibernateTemplate abstracts away much of boilerplate code, and enables quicker development. Another advantage of using the HibernateTemplate is that it will translate native Hibernate exceptions into exceptions in Spring’s org.springframework.dao.DataAccessException hierarchy. This allows consistent exception handling for all the data access strategies in Spring. For example, if a database constraint is violated when persisting an object, Hibernate usually throws an org.hibernate.exception.ConstraintViolationException. This Exception will be translated by the HibernateTemplate into org.springframework.dao.DataIntegrityViolationException, which is a subclass of org.springframework.dao.DataAccessException.

Using the HibernateTemplate, the StockDao may be implemented, as shown in Listing 4–21.

Listing 4–21. StockDao Implementation using HibernateTemplate

package com.apress.prospringintegration.springenterprise.stocks.dao.hibernate;

import com.apress.prospringintegration.springenterprise.stocks.dao.StockDao;
import com.apress.prospringintegration.springenterprise.stocks.model.Stock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.stereotype.Component;

import java.util.List;

@Component
public class HibernateStockDao implements StockDao {

    @Autowired
    HibernateTemplate hibernateTemplate;

    @Override
    public void insert(Stock stock) {
        hibernateTemplate.persist(stock);
    }

    @Override
    public void update(Stock stock) {
        hibernateTemplate.merge(stock);
    }

    @Override
    public void delete(Stock stock) {
        hibernateTemplate.delete(stock);
    }

    @Override
    public List<Stock> get() {
        return hibernateTemplate.find("from Stock s");
    }

    @Override
    public Stock findByInventoryCode(String iCode) {
        Stock found = null;
        String query = "from Stock s where s.inventoryCode =?";
        List ret = hibernateTemplate.find(query, iCode);
        if (ret != null && ret.size() > 0) {
            found = (Stock) ret.get(0);
        }

        return found;
    }

    @Override
    public List<Stock> findAvailableStockBySymbol(String symbol) {
        String query = "from Stock s where s.symbol =? and s.quantityAvailable>0";
        return hibernateTemplate.find(query, symbol);
    }
}

The following main class shown in Listing 4–22 may be used to test some of the DAO methods. It also demonstrates an entity’s typical life cycle.

Listing 4–22. Main class for Executing HibernateTemplate DAO Methods

package com.apress.prospringintegration.springenterprise.stocks.runner;

import com.apress.prospringintegration.springenterprise.stocks.dao.StockDao;
import com.apress.prospringintegration.springenterprise.stocks.dao.hibernate.HibernateStockDao;
import com.apress.prospringintegration.springenterprise.stocks.model.Stock;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.GenericApplicationContext;

import java.util.Calendar;

public class MainHibernate {
    public static void main(String[] args) {
        GenericApplicationContext context =
            new AnnotationConfigApplicationContext(
                "com.apress.prospringintegration.springenterprise.stocks.dao.hibernate");

        StockDao stockDao =
                context.getBean(“hibernateStockDao”, HibernateStockDao.class);
        Stock stock =
                new Stock("ORAC", "HIBERNATEMAIN0001", "QQQQ", 120.0f, 1100,
                        Calendar.getInstance().getTime());
        stockDao.insert(stock);

        stock = stockDao.findByInventoryCode("HIBERNATEMAIN0001");

        if (stock != null) {
            System.out.println("Stock Symbol :" + stock.getSymbol());
            System.out.println("Inventory Code :" + stock.getInventoryCode());
            System.out.println("purchased price:" + stock.getSharePrice());
            System.out.println("Exchange ID:" + stock.getExchangeId());
            System.out.println("Quantity Available :" + stock.getQuantityAvailable());
        }
    }
}

The example main class demonstrates the ability to persist and retrieve the Stock domain object. The Spring context is created and used to obtain a reference to the HiberateStockDao instance. A Stock object is created, persisted, and retrieved based on the inventoryCode property.

Persistence with Hibernate in a JPA Context

JPA annotations are standardized in the JSR-220 specification so all JPA-compliant ORM frameworks, including Hibernate, support them. Moreover, the use of annotations are often more convenient providing the ability to edit the mapping metadata within the domain object source code.

The Stock class shown in Listing 4–23 illustrates the use of JPA annotations to define mapping metadata. The Stock entity object is embellished using javax.persistence annotation.

Listing 4–23. JPA Annotated Entity Class

package com.apress.prospringintegration.springenterprise.stocks.model;

import javax.persistence.*;
import java.util.Calendar;
import java.util.Date;

// Represents stocks in an inventory
@Entity
@Table(name = "STOCKS")
public class Stock {

    @Id
    @Column(name = "ID")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    int id;

    @Column(name = "INVENTORY_CODE", nullable = false)
    String inventoryCode;

    @Column(name = "SYMBOL")
    String symbol;

    @Column(name = "EXCHANGE_ID")
    String exchangeId;

    @Column(name = "PRICE_PER_SHARE")
    float sharePrice;

    @Column(name = "QUANTITY_AVAILABLE")
    int quantityAvailable;

    @Column(name = "PURCHASE_DATE")
    Date purchaseDate;
    public Stock() {
    }

    public Stock(String symbol, String inventoryCode, String exchange,
                 float purchasedPrice, int quantityAvailable, Date purchaseDate) {
        this.symbol = symbol;
        this.inventoryCode = inventoryCode;
        this.exchangeId = exchange;
        this.sharePrice = purchasedPrice;
        this.quantityAvailable = quantityAvailable;
        this.purchaseDate =
                purchaseDate != null ? purchaseDate : Calendar.getInstance().getTime();
    }

    // Getters and Setters removed for brevity

}

Each entity class must be annotated with the @javax.persistence.Entity annotation. The table name for an entity class specified using the @javax.persistence.Table annotation.

For each property, you can specify a column name and column details using the @javax.persistence.Column annotation. Each entity class must have an identifier defined by @javax.persistence.Id annotation. You can choose a strategy for identifier generation using the @javax.persistence.GeneratedValue annotation. Here, a table identity column will generate the identifier value.

Hibernate supports both native XML mapping files and JPA annotations as means of defining mapping metadata. It is optional to specify mapped classes through a configuration element in the Hibernate configuration or persistence.xml file. Hibernate will automatically detect them at runtime. The Hibernate configuration for JPA is shown in Listing 4–24.

Listing 4–24. Hibernate Configuration for JPA Annotations hibernate-jpa-cfg.xml

<!DOCTYPE hibernate-configuration PUBLIC
    "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory/>
</hibernate-configuration>

In the JPA context, your Hibernate configuration items can be consolidated with the entity manager configuration inside of META-INF/persistence.xml. This will help ensure maintainability; besides, Hibernate observes the same set of configuration properties here too. For this example, the empty Hibernate configuration is specified to prevent Hibernate from auto detecting the hibernate.cfg.xml file already present on the classpath. Hibernate is also configured so that entity definitions are drawn from class metadata only, because otherwise the hibernate.hbm.xml file would get automatically detected. This also means that that explicit mapping elements are not required, as all valid @Entity mapped classes will get auto detected by Hibernate.

Listing 4–25. Entity Manager Configurationwith Hibernate META-INF/persistence.xml

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.0"
             xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
        http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
<persistence-unit name="persistenceUnit"
                  transaction-type="RESOURCE_LOCAL">
  <provider>org.hibernate.ejb.HibernatePersistence</provider>
  <properties>
    <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>
    <!--value='create' to build a new database on each run; value='update'
        to modify an existing database; value='create-drop' means the same as 'create'
        but also drops tables when Hibernate closes; value='validate' makes no changes
        to the database -->
    <!-- <property name="hibernate.hbm2ddl.auto" value="true"/> -->
    <property name="hibernate.ejb.cfgfile" value="hibernate-jpa-cfg.xml"/>
    <property name="hiberante.show_sql" value="true"/>
    <property name="hibernate.archive.autodetection" value="class"/>

  </properties>
 </persistence-unit>
</persistence>

Configuration and Usage of JpaTemplate

These examples will not make direct use of the EntityManager, but instead provide a JPA context to your Spring-based application. The LocalContainerEntityManagerFactoryBean instance will be created which is responsible for creating the entity manager factory by loading the persistence.xml. This class also provides convenience for overriding some configurations in the JPA configuration file, such as the data source and database dialect. The Java configuration for creating the JpaTemplate is shown in Listing 4–26.

Listing 4–26. JavaConfiguration for Hibernate-based JPA Support

package com.apress.prospringintegration.springenterprise.stocks.dao.jpa;

import com.apress.prospringintegration.springenterprise.stocks.config.StocksBaseConfig;
import org.hibernate.SessionFactory;
import org.hibernate.ejb.HibernateEntityManagerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.orm.jpa.JpaTemplate;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;

@Configuration
@ImportResource("classpath:jpa-data-access.xml")
public class StocksJpaConfig extends StocksBaseConfig {

    // Entity Manger for JPA
    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
        LocalContainerEntityManagerFactoryBean entityManagerFactory =
                new LocalContainerEntityManagerFactoryBean();
        entityManagerFactory.setDataSource(dataSource());
        return entityManagerFactory;
    }
    // JPA Template
    @Bean
    public JpaTemplate jpaTemplate() {
        return new JpaTemplate(entityManagerFactory().getObject());
    }

    // Transaction Manager for JPA
    @Bean
    public JpaTransactionManager transactionManager() {
        return new JpaTransactionManager(entityManagerFactory().getObject());
    }

    // Local Session Factory for getting hibernate connections
    @Bean
    SessionFactory sessionFactory() {
        return ((HibernateEntityManagerFactory)
                 entityManagerFactory().getObject()).getSessionFactory();
    }

    // Hibernate Template
    @Bean
    public HibernateTemplate hibernateTemplate() {
        return new HibernateTemplate(sessionFactory());
    }
}

Because Hibernate is configured through JPA persistence, obtaining a Hibernate SessionFactory is a little less straightforward, but it’s also less cumbersome. The glue is the HibernateEntityManagerFactory, which extends the EntityManagerFactory interface, which contains a method to obtain a reference to the Hibernate SessionFactory instance. Thus, obtaining a SessionFactory is made through the casting the EntityManagerFactory to the HibernateEntityManager as seen in the configuration class for this example.

Spring provides the HibernateTemplate and JpaTemplate classes that enable the same simplified programming style enjoyed with JdbcTemplate. Like their JdbcTemplate counterpart, these template classes also enforce resource creation and disposal to ensure that Hibernate session and JPA entity managers are properly managed. The StockDao implementation using the JpaTemplate is shown in Listing 4–27.

Listing 4–27. Implementation of StockDao using JpaTemplate

package com.apress.prospringintegration.springenterprise.stocks.dao.jpa;

import com.apress.prospringintegration.springenterprise.stocks.dao.StockDao;
import com.apress.prospringintegration.springenterprise.stocks.model.Stock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.jpa.JpaTemplate;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
import org.springframework.test.context.transaction.TransactionConfiguration;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@TransactionConfiguration(transactionManager = "transactionManager")
@Component
public class JpaStockDao implements StockDao {
    @Autowired
    private JpaTemplate jpaTemplate;

    @Override
    @Transactional
    public void insert(Stock stock) {
        jpaTemplate.persist(stock);
    }

    @Override
    @Transactional
    public void update(Stock stock) {
        jpaTemplate.merge(stock);
    }

    @Override
    @Transactional
    public void delete(Stock stock) {
        jpaTemplate.refresh(stock);
    }

    @Override
    @SuppressWarnings("unchecked")
    @Transactional(readOnly = true)
    public List<Stock> findAvailableStockBySymbol(String symbol) {
        return (List<Stock>) jpaTemplate.find("from Stock s where s.symbol=?", symbol);
    }

    @Override
    @Transactional(readOnly = true)
    public Stock findByInventoryCode(String iCode) {
        return jpaTemplate.find(Stock.class, iCode);
    }

    @Override
    @Transactional(readOnly = true)
    public List<Stock> get() {
        return jpaTemplate.find("from Stock s");
    }
}

These DAO implementation methods are all declared to be transactional with the @Transactional annotation. The @Transactional method turns on transaction demarcation for all method invocations in a given thread: thus, if a method is invoked and it turn invokes another method, they will both participate in the same transaction. The transaction will commit all the changes by the outermost method invocation in a given thread. To gain this functionality, you must enable the Spring tx schema element <tx:annotation-driven> in the Spring configuration file as shown in Listing 4–28.

Listing 4–28. Declarative Transaction Management jpa-data-access.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:jdbc="http://www.springframework.org/schema/jdbc"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/tx
    http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd     
    http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/jdbc
    http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd">

  <context:property-placeholder location="StocksJDBC.properties"/>
  <context:component-scan
      base-package="com.apress.prospringintegration.springenterprise.stocks.dao.jpa"/>
  <jdbc:embedded-database type="H2" id="h2DataSource"/>

  <jdbc:initialize-database data-source="h2DataSource" ignore-failures="DROPS">
    <jdbc:script location="/STOCKS.DDL.SQL"/>
  </jdbc:initialize-database>

  <!--proxy-target-class set to true because CGLIB hides our bean when usingTransactional-->
  <tx:annotation-driven proxy-target-class="true"/>
</beans>

By default, this element looks for an org.springframework.transaction.PlatformTransactionManager manager bean instance by the name of transactionManager, so a PlatformTransactionManager must be declared based on the persistence API that is being used. In this case, the Spring provided org.springframework.orm.jpa.JPATransactionManager is used which requires the EntityManagerFactory property to be set as shown in Listing 4–26. Transaction management will be discussed in more detail following.

The StockDao implementation using JpaTemplate may be tested using the main class shown in Listing 4–29. The main class creates the Spring context and obtains a reference to the JpaStockDao instance. A Stock object is created and persisted using the JpaStockDao instance and then retrieved using the findAvailableStockBySymbol method.

Listing 4–29. Main class Demonstrating JpaStockDao

package com.apress.prospringintegration.springenterprise.stocks.runner;

import com.apress.prospringintegration.springenterprise.stocks.dao.StockDao;
import com.apress.prospringintegration.springenterprise.stocks.model.Stock;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.GenericApplicationContext;

import java.util.Calendar;
import java.util.List;

public class MainHibernateJPA {
    public static void main(String[] args) {
        GenericApplicationContext context =
                new AnnotationConfigApplicationContext(
                        "com.apress.prospringintegration.springenterprise.stocks.dao.jpa");

        StockDao stockDao = context.getBean("jpaStockDao", StockDao.class);
        Stock stock =
                new Stock("ORAC", "JPAMAIN0001", "QQQQ", 120.0f, 1100,
                        Calendar.getInstance().getTime());
        stockDao.insert(stock);

        List<Stock> stocks = stockDao.findAvailableStockBySymbol("ORAC");

        if (stocks != null && stocks.size() > 0) {
            stock = stocks.get(0);
            System.out.println("Stock Symbol :" + stock.getSymbol());
            System.out.println("Inventory Code :" + stock.getInventoryCode());
            System.out.println("purchased price:" + stock.getSharePrice());
            System.out.println("Exchange ID:" + stock.getExchangeId());
            System.out.println("Quantity Available :" + stock.getQuantityAvailable());
        }
    }
}

Using JPA EntityManagers Directly

The JpaTemplate provides a clean way to work with JPA, just as the HibernateTemplate provides a convenient way to work with Hibernate’s Sessions. However, we can do better. In EJB 3.0, applications can inject a JPA EntityManager instance and use that to work with the backend datastore. This, of course, doesn’t work in Java SE, but it is a compelling programming model, so Spring brings it to you in any environment. EJB 3.0 beans are stateful by default. EJB beans are passivated and activated for each request. EJB beans are not shared across requests, and EJB beans are pooled. When a method is invoked on an EJB, the invocation can manipulate class state and work with values in a thread-safe way with no extra care. Spring beans, on the other hand, are stateless, so it is up to you to ensure that any state is also thread safe. A JPA EntityManager is not thread safe, however. So, injecting a regular EntityManager is a recipe for disaster in a shared, concurrently accessed DAO. Spring provides a way around this and lets you inject an EntityManager proxy. The proxy is simply a wrapper that delegates to a thread-local EntityManager. Clients can have their cake and eat it too: EntityManager access is now threadsafe, and your Spring beans retain the advantages of being stateless.

Let’s look at the previous example, slightly reworked to support this style of programming. First, let’s look at the revised configuration as shown in Listing 4–30.

Listing 4–30. JavaConfiguration for using EntityManager Directly

package com.apress.prospringintegration.springenterprise.stocks.dao.jpaandentitymanagers;
import com.apress.prospringintegration.springenterprise.stocks.config.StocksBaseConfig;
import org.hibernate.SessionFactory;
import org.hibernate.ejb.HibernateEntityManagerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.orm.jpa.JpaTemplate;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;

@Configuration
@ImportResource("classpath:jpa-entity-manager.xml")
public class StocksJpaConfig extends StocksBaseConfig {

    // Entity Manger for JPA
    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
        LocalContainerEntityManagerFactoryBean entityManagerFactory =
                new LocalContainerEntityManagerFactoryBean();
        entityManagerFactory.setDataSource(dataSource());
        return entityManagerFactory;
    }

    // JPA Template
    @Bean
    public JpaTemplate jpaTemplate() {
        return new JpaTemplate(entityManagerFactory().getObject());
    }

    // Transaction Manager for JPA
    @Bean
    public JpaTransactionManager transactionManager() {
        return new JpaTransactionManager(entityManagerFactory().getObject());
    }

    // Since we're no longer using the JpaTemplate, we don't benefit from the exception translation
    // so we need to turn this on explicitly
    @Bean
    public PersistenceExceptionTranslationPostProcessor persistenceExceptionTranslationPostProcessor() {images
        PersistenceExceptionTranslationPostProcessor persistenceExceptionTranslationPostProcessor = images
                new PersistenceExceptionTranslationPostProcessor();
        return persistenceExceptionTranslationPostProcessor;
    }
}

You can see we’ve omitted the JpaTemplate (naturally) and included something that would appear to have almost no relation to JPA at all – a PersistenceExceptionTranslationPostProcessor. The PersistenceExceptionTranslationPostProcessor is something that normally lives in the background – you rarely need to deal with it directly since all the persistence technologies already provide equivalent support. As you know, the various persistence technologies in the Spring framework provide consistent exception translation. Spring provides a consistent exception hierarchy and then translates various JDBC, JPA and Hibernate (among others) exceptions into this hierarchy so that you can deal with exceptions in a consistent way across all persistence technologies. As we are foregoing the JpaTemplate, we need to reinstate this behavior manually by registering the bean with the context manually.

Now we can rework our DAOs to use this support. Let’s look at our StockJpaDao, as shown in Listing 4–31.

Listing 4–31. DAO using EntityManager Directly

package com.apress.prospringintegration.springenterprise.stocks.dao.jpaandentitymanagers;
import com.apress.prospringintegration.springenterprise.stocks.dao.StockDao;
import com.apress.prospringintegration.springenterprise.stocks.model.Stock;
import org.springframework.stereotype.Component;
import org.springframework.test.context.transaction.TransactionConfiguration;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import java.util.List;

@TransactionConfiguration(transactionManager = "transactionManager")
@Component
public class JpaStockDao implements StockDao {

    @PersistenceContext
    private EntityManager entityManager;

    @Override
    @Transactional
    public void insert(Stock stock) {
        this.entityManager.persist(stock);
    }

    @Override
    @Transactional
    public void update(Stock stock) {
        this.entityManager.merge(stock);
    }
    @Override
    @Transactional
    public void delete(Stock stock) {
        entityManager.remove(stock);
    }
    @Override
    @SuppressWarnings("unchecked")
    @Transactional(readOnly = true)
    public List<Stock> findAvailableStockBySymbol(String symbol) {
        Query qu = entityManager.createQuery(
                " from Stock s where s.symbol = :stock ");
        qu.setParameter("stock", symbol);
        return (List<Stock>) qu.getResultList();
    }

    @Override
    @Transactional(readOnly = true)
    public Stock findByInventoryCode(String iCode) {
        return entityManager.find(Stock.class, iCode);
    }

    @Override
    @Transactional(readOnly = true)
    public List<Stock> get() {
        return (List<Stock>) entityManager.createQuery("from Stock").getResultList();
    }
}

Not bad! The code is now almost as brief as the original JpaTemplate-based example, and is very apparent in function. There is equivalent support for Hibernate Sessions, as well.

Transaction Management Framework

Transactions enable controllable concurrent access of data by multiple business operations, thus safeguarding integrity. In the event of sudden system outages, transactions ensure that data remains in a consistent state. Transactions also define business units of work – usually several data commits and reads taken as a whole. To do this, a per-thread transaction context is defined which encapsulates all operations bound to it under a given unit of work that will either entirely complete with a commit, or roll back as a whole - undoing all operations if any single part fails. This may be illustrated with discrete steps using the following pseudo code as shown in Listing 4–32.

Listing 4–32. Pseudocode Illustrating Typical Business Logic Within a Transaction

Begin transaction
        Deduct inventory (sql write)
        Debit client bank account (sql write)
        Credit business funds (sql write)
        Update history log (sql write)
Commit transaction

The four individual steps behave as an indivisible unit of work, thus the final outcome is determined by each one of the steps. When one step fails, the unit fails – any state changes are unwound, and the transaction rolls back. Conversely, when they all succeed, the transaction is committed and the final state is saved. When designing your application, you determine the individual units of work. The concepts of transactions can be stated as a group of four well defined properties known as ACID: Atomicity, Consistency, Isolation, and Durability. This is explained in Table 4–1.

Table 4–1. Fundamental Transaction Concepts

Atomicity A transaction is an atomic operation that consists of a series of actions.The atomicity of a transaction ensures that the actions either complete entirely, or take no effect at all.
Consistency Once all actions of a transaction have completed, the transaction is committed. Then your data and resources will be in a consistent state that conforms to business rules.
Isolation Because there may be many transactions processing with the same data set at the same time, each transaction should be isolated from others to prevent data corruption.
Durability Once a transaction has completed, its result should be durable to survive any system failure such as power failure to a critical database system.Usually, the result of a transaction is written to persistent storage.

Most resources that you interact with provide a notion of a transaction: database commits may be aggregated and committed, JMS messages may be acknowledged or not, and so on. Many different APIs provide a concept that  basically feels like a transaction, even if it’s not exposed as such. These transactions are generally referred to as local transactions.

A process might conduct operations in multiple contexts spanning disparate internal/external departments, business partners, and/or vendors. These operations enlist multiple resources – a local transaction will not suffice. Global transactions – in contrast to local transactions, which are resource-specific – span multiple transactional resources and are managed by a third-party transaction monitor. The transaction monitor coordinates all the enlisted transactions to create a transaction. The API typically used to describe the interaction between transactional resources and a third party monitor is called the Java Transaction API (JTA). Most global transaction monitors work through an implementation of two-phase commit (2PC). 2PC works by enlisting a resource in a coordinated transaction, preparing that transaction, and then – when all enlisted resources are prepared – committing all of the resources. Java EE application servers provide JTA implementations, and there are also open-source or commercial JTA implementations that can be embedded in your application if your server doesn’t have one already built in.

Spring Transaction Management

Clearly, you have choices to make: whether to use local transactions or global transactions and, if you’re using global transactions, which should you use? Spring provides both programmatic and declarative transaction management. The programmatic approach exposes the underlying JTA or non-JTA implementation by the org.springframework.transaction.PlatformTransactionManager interface and related sub-classes. This provides a consistent API to deal with all transactions in a similar way, indifferent to how the underlying API exposes the transaction. Declarative transactions are applied using Aspect Oriented Programming (AOP) to define transaction boundaries. This approach allows for much less invasive transaction control, in that it departs from coding directly to the underlying API.

The basic transactional unit of work in a Spring transaction is exposed through the org.springframework.transaction.TransactionDefinition interface, which controls basic properties of a transaction.

Table 4–2. TransactionDefinition Transactional Concepts

Isolation Like the ACID Isolation principle, this defines degree of isolation of the given transaction (for example, visibility of results from another uncommitted transaction).
Propagation Determines controlling scope of the transaction that is it supports a set of properties, similar to EJB CMT’s javax.ejb.TransactionAttributeType constants.
Timeout Governs the duration a transaction should execute before timing out and automatically being rolling back.
Read-Only Defines a read-only transaction that cannot make any writes to transactional resources.

Let your business case justify the level of isolation you need in any given transaction. However, do note that the choice you make can greatly have impact on performance. Spring supports five levels of isolation that are given as static properties on the TransactionDefinition interface as shown in Table 4–3.

Table 4–3. Transactional Isolation Levels

DEFAULT Default level for the PlatformTransactionManager. For example, most databases use READ_COMMITTED by default.
READ_UNCOMMITTED Lowest isolation, highest concurrency; allows this transaction to see changes from other uncommitted transactions.
READ_COMMITTED Less concurrency; ensures that other transactions cannot see uncommitted data, however you can see inserts and updates from other transactions.
REPEATABLE_READ More isolated than read_commited; that is you can guarantee that data selects will always contain the same dataset until the transaction completes.
SERIALIZABLE Lowest concurrency;all transactions are repeatable_read, and are serialized in execution order.No concurrency is guaranteed.

In addition to isolation levels, Spring provides a finer grained org.springframework.transaction.interceptor.TransactionAttribute interface that enables you to declaratively specify a strategy that determines which specific subclasses of java.lang.Throwable cause rollback. By default, if no exceptions are specified, any Throwable thrown will cause a rollback.

Controlling Transaction Propagation with the TransactionStatus Interface

To provide fine-grained transaction monitoring, Spring provides the org.springframework.transaction.TransactionStatus interface that allows your application to check the status of the running transaction, whether it is new, read-only, or rollback only. This simple interface exposes the setRollbackOnly method, which causes the current transaction to rollback and end as opposed to having a transaction abnormally terminate through an exception. The propagation behavior is similar to the org.springframework.transaction.TransactionDefinition interface. This interface will seem familiar to EJB CMT transaction attributes (see Table 4–4).

Table 4–4. Propagation Strategy Properties as Defined in TransactionDefinition

REQUIRED Transaction either exists, or a new one is started.
SUPPORTS Transaction either exists, or execution is done non-transactional. This still enables participation in greater transactional contexts by providing a transaction scope to operate resources in.
MANDATORY Transaction must be active, or RemoteException is thrown.
REQUIRES_NEW Active transactions are suspended, and a new one started. Otherwise, a new transaction is started in the absence of an active transaction.
NOT_SUPPORTED Doesn’t support execution within an active transaction. Will suspend any active transaction.
NEVER If a transaction exists, then RemoteException is thrown. Otherwise, execution is non-transactional.
NESTED If a transaction is active, then propagation mode switches to REQUIRED. Otherwise, it runs in a new, nested transaction. You can rollback nested transactions, or the containing transactions with the support through JDBC 3.0 Savepoint API.

Introduction to PlatformTransactionManager and Implementations

The org.springframework.transaction.PlatformTransactionManager interface uses TransactionDefinition and TransactionStatus to create and manage transactions. This is a Service Provider Interface (SPI) that can also be mocked and stubbed to provide programmatic transaction management. Any given implementation of this interface contains the salient details of the underling transaction manager. For example, the DataSourceTransactionManager manages transactions performed within a JDBC DataSource, JdoTransactionManager controls transactions performed in a JDO session, HibernateTransactionManager does the same in a Hibernate session, and JpaTransactionManager supports transaction for JPA.

Setting Up Transaction Control with TransactionTemplate

Spring offers a convenient approach to wrapping execution logic inside of a transaction by providing the TransactionTemplate. This class, similar to JdbcTemplate, allows you to enforce your transaction logic through the callback class that implements the TransactionCallback<T> interface. By passing your TransactionCallback<T> implementation to the TransactionTemplate.execute method, you gain the triple advantage of more concise and readable code, and not having to manage boilerplate transaction management code for the affected operations. As with a JdbcTemplate, configuring and injecting a TransactionTemplate is simply a matter of injecting the TransactionTemplate with a TransactionManager, then injecting the template into your bean of preference.

The Java configuration remains similar to earlier StockConfig configurations with the presence of a dataSource, jdbcTemplate, and other common data resources. Here, a TransactionTemplate is configured with the corresponding PlatformTransactionManager instance. The TransactionTemplate instance will get injected into dependent DAO repositories. The Java Configuration is shown in Listing 4–33.

Listing 4–33. Configuring Spring Container with TransactionManager

package com.apress.prospringintegration.springenterprise.stocks.transactions.template;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.support.TransactionTemplate;

import javax.sql.DataSource;

@Configuration
@ImportResource("tx_template.xml")
public class TransactionalConfig {
    @Autowired
    private DataSource dataSource;

    @Bean
    public PlatformTransactionManager transactionManager() throws Exception {
        DataSourceTransactionManager dtm = new DataSourceTransactionManager();
        dtm.setDataSource(dataSource);
        dtm.setDefaultTimeout(30);
        return dtm;
    }

    @Bean
    public TransactionTemplate transactionTemplate() throws Exception {
        return new TransactionTemplate(transactionManager());
    }
}

This example will utilize an unreliable stock data insertion technique to provide the transactional logic illustration. It will begin to insert several stocks and upon (randomly manufactured) coincidence, generate a constraint violation, which produces an exception that interrupts the process. The objective in this is to demonstrate the rollback phase. The preFillStocks method shown in Listing 4–34 will perform a series of insert/updates where the inventoryCode property will be set to the same value for two different rows creating a constraint violation. This will cause all of the insert/updates to rollback.

Listing 4–34. Transaction-based Insert/Update that will Create Random Constraint Violation

package com.apress.prospringintegration.springenterprise.stocks.transactions.template;

import com.apress.prospringintegration.springenterprise.stocks.dao.StockBrokerService;
import com.apress.prospringintegration.springenterprise.stocks.dao.StockDao;
import com.apress.prospringintegration.springenterprise.stocks.model.Stock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;

import java.util.Calendar;
import java.util.Random;

@Component
public class TransactionalStockBrokerService implements StockBrokerService {
    @Autowired
    @Qualifier("transactionTemplate")
    private TransactionTemplate transactionTemplate;

    @Autowired
    @Qualifier("jdbcTemplateStockDao")
    private StockDao stockDao;

    // inserts at least 25% duplicate inventory code.
    public void preFillStocks(final String exchangeId, final String... symbols) {
        final Random random = new Random();

        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            protected void doInTransactionWithoutResult(TransactionStatus status) {
                int i = 0;
                for (String sym : symbols) {
                    float pp = (float) Math.random() * 100.0f;
                    int qq = (int) Math.random() * 250;
                    Stock s = new Stock(sym, "INV00" + i, exchangeId, pp, qq, Calendar
                            .getInstance().getTime());
                    stockDao.insert(s);
                    System.out.println("ORIG INVENTORY: " + s.getInventoryCode() + " ");
                    int randomized = (random.nextInt(100) % 4) == 0 ? 0 : i;
                    s.setInventoryCode("INV00" + randomized);
                    System.out.println("NEW RANDOMIZED INVENTORY:"
                            + s.getInventoryCode() + " " + randomized);
                    stockDao.update(s);
                    i++;
                }
            }
        });
    }
}

The main class for the TransactionTemplate example is shown in Listing 4–35. The main class creates a Spring context and obtains a reference to the transactionalStockBrokerService instance. Calling the preFillStocks method will attempt to insert six new stocks resulting in a constraint violation causing the transaction to rollback. The main class will log that no rows have been added to the database.

Listing 4–35. Main Class for Demostrating the TransactionTemplate

package com.apress.prospringintegration.springenterprise.stocks.runner;

import com.apress.prospringintegration.springenterprise.stocks.dao.StockDao;
import com.apress.prospringintegration.springenterprise.stocks.dao.jdbc.JdbcTemplateStockDao;
import com.apress.prospringintegration.springenterprise.stocks.model.Stock;
import com.apress.prospringintegration.springenterprise.stocks.transactions.template.TransactionalStockBrokerService;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.GenericApplicationContext;

public class MainTxJdbc {
    public static void main(String[] args) {
        GenericApplicationContext context = new AnnotationConfigApplicationContext(
            "com.apress.prospringintegration.springenterprise.stocks.transactions.template",
            "com.apress.prospringintegration.springenterprise.stocks.dao.jdbc");

        TransactionalStockBrokerService uStockDao =
                context.getBean("transactionalStockBrokerService",
                        TransactionalStockBrokerService.class);
        try {
            uStockDao.preFillStocks("TEST", "IBM", "INTC", "MSFT", "ORAC", "C");
        } catch (Exception ex) {
            System.out.println("Exception: " + ex.getMessage());
        }

        StockDao stockDao = context.getBean(JdbcTemplateStockDao.class);
        System.out.println("Total rows inserted: " + stockDao.get().size());
        for (Stock s : stockDao.get()) {
            System.out.println("Stock added: " + s.getSymbol());
        }
    }
}

Declaring Transactions with Transaction Advices

Spring offers AOP-based support for declarative transactions. This advice can be enabled with AOP configuration facilities defined in the aop schema. AOP support requires the addition Maven dependency:

<dependency>
  <groupId>org.aspectj</groupId>
  <artifactId>aspectjweaver</artifactId>
  <version>1.6.8</version>
</dependency>

To enable declarative transaction management, add the <tx:advice> element to the Spring configuration file shown in Listing 4–36. This advice will need to be associated with a pointcut. Because a transaction advice is declared outside the <aop:config> element, it cannot link with a pointcut directly. An advisor must be declared in the <aop:config> element to associate an advice with a pointcut.

Listing 4–36. Defining a T ransaction Advice and Pointcut with Spring XML tx_aop.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:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
     http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
     http://www.springframework.org/schema/tx
     http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
     http://www.springframework.org/schema/aop
     http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
     http://www.springframework.org/schema/context
     http://www.springframework.org/schema/context/spring-context-3.0.xsd">

  <context:component-scan base-images package="com.apress.prospringintegration.springenterprise.stocks.transactions.aopdeclarative"images />

  <tx:advice id="txAdvice" transaction-manager="transactionManager">
    <tx:attributes>
      <tx:method name="find*" read-only="true"/>
      <tx:method name="*"/>
    </tx:attributes>
  </tx:advice>

  <aop:config>
    <aop:pointcut id="stockBrokerOperation"
                  expression="execution(* images com.apress.prospringintegration.springenterprise.stocks.dao.StockBrokerService.*(..))"/>
    <aop:advisor advice-ref="txAdvice" pointcut-ref="stockBrokerOperation"/>
  </aop:config>

</beans>

The preceding AspectJ pointcut expression matches all the methods declared in the StockBrokerService interface. However, because Spring AOP is based on proxies, it can apply only to public methods. Thus only public methods can be made transactional with Spring AOP.

Each transaction advice requires an identifier and a reference to a transaction manager in the IoC container. If you do not specify a transaction manager explicitly, Spring will search the application context for a PlatformTransactionManager with a bean name of transactionManager. The methods that require transaction management are specified with multiple <tx:method> elements inside the <tx:attributes> element. The method name supports wildcards for you to match a group of many methods. Transaction attributes may also be defined for each group of methods.The default attributes are listed in Table 4–5.

Table 4–5. Attribues Used with tx:attributes with Their Defaults

Attribute Required Default
name Yes n/a
propagation No REQUIRED
isolation No DEFAULT
timeout No -1
read-only No False
rollback-for No N/A
no-rollback-for No N/A

Obtaining the AOPStockBrokerService bean is simply a matter of retrieving it from the IoC container. This is because this bean’s methods are matched by the pointcut and that causes Spring to return a proxy that has transaction management enabled for this bean.

The StockBrokerService implementation will be modified to removethe TransactionalTemplate since we are no longer coding with the transaction system directly. This proxied version will perform all transactional duties enabled by the <aop:config> element in the Spring configuration file.  The modified AopStockBrokerService implementation is shown in Listing 4–37.

Listing 4–37. StockBrokerService Implementation using Transaction Advice

package com.apress.prospringintegration.springenterprise.stocks.transactions.aopdeclarative;

import com.apress.prospringintegration.springenterprise.stocks.dao.StockBrokerService;
import com.apress.prospringintegration.springenterprise.stocks.dao.StockDao;
import com.apress.prospringintegration.springenterprise.stocks.model.Stock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

import java.util.Calendar;
import java.util.Random;

@Component
public class AopStockBrokerService implements StockBrokerService {

    @Autowired
    @Qualifier("hibernateStockDao")
    private StockDao stockDao;

    private Random random = new Random();

    // inserts at least 25% duplicate inventory code.
    public void preFillStocks(final String exchangeId, final String... symbols) {
        int i = 0;
        for (String sym : symbols) {
            float pp = (float) Math.random() * 100.0f;
            int qq = (int) Math.random() * 250;
            Stock s = new Stock(sym, "INV00" + i, exchangeId, pp, qq, Calendar
                    .getInstance().getTime());
            stockDao.insert(s);
            System.out.println("ORIG INVENTORY: " + s.getInventoryCode() + " ");
            int randomized = (random.nextInt(100) % 4) == 0 ? 0 : i;
            s.setInventoryCode("INV00" + randomized);
            System.out.println("NEW RANDOMIZED INVENTORY:"
                    + s.getInventoryCode() + " " + randomized);
            stockDao.update(s);
            i++;
        }
    }
}

To demonstrate that Spring transaction support can be used with any of the Spring DAO templates, this example has also been modified to use Hibernate instead of JDBC. Note that the StockDao is using the HibernateStockDao implementation. In addition, the PlatformTransactionManager implementation is HibernateTransactionManager, as shown in Listing 4–38. Note that the Hibernate sessionFactory is now required.

Listing 4–38. JavaConfiguration for AOP transaction using  Hibernate

package com.apress.prospringintegration.springenterprise.stocks.transactions.aopdeclarative;

import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
import org.springframework.orm.hibernate3.HibernateTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;

@Configuration
@ImportResource("tx_aop.xml")
public class TxAOPConfig {
    @Autowired
    private SessionFactory sessionFactory;

    @Bean
    public PlatformTransactionManager transactionManager() throws Exception {
        HibernateTransactionManager dtm = new HibernateTransactionManager();
        dtm.setSessionFactory(sessionFactory);
        dtm.setDefaultTimeout(30);
        return dtm;
    }
}

The main class to run the AOP transaction example with Hibernate as shown in Listing 4–39 will be similar to the previous example.The main class creates a Spring context and obtains a reference to the aopStockBrokerService instance. Calling the preFillStocks method will attempt to insert six new stocks resulting in a constraint violation causing the transaction to rollback. The main class will log that no rows have been added to the database.

Listing 4–39. Transaction Advise Main Class

package com.apress.prospringintegration.springenterprise.stocks.runner;

import com.apress.prospringintegration.springenterprise.stocks.dao.StockBrokerService;
import com.apress.prospringintegration.springenterprise.stocks.dao.StockDao;
import com.apress.prospringintegration.springenterprise.stocks.dao.hibernate.HibernateStockDao;
import com.apress.prospringintegration.springenterprise.stocks.model.Stock;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.GenericApplicationContext;

public class MainTxAop {
    public static void main(String[] args) throws Exception {
        GenericApplicationContext context = new AnnotationConfigApplicationContext(
      "com.apress.prospringintegration.springenterprise.stocks.transactions.aopdeclarative",
      "com.apress.prospringintegration.springenterprise.stocks.dao.hibernate");

        StockBrokerService broker =
                context.getBean("aopStockBrokerService", StockBrokerService.class);
        try {
            broker.preFillStocks("QQQQ", "INTC", "IBM", "XLA", "MGM", "C");
        } catch (Exception ex) {
            System.out.println("Exception: " + ex.getMessage());
        }

        StockDao stockDao = context.getBean(HibernateStockDao.class);
        System.out.println("Total rows inserted: " + stockDao.get().size());
        for (Stock s : stockDao.get()) {
            System.out.println("Stock added: " + s.getSymbol());
        }
    }
}

Declarative Transaction Managing with the @Transactional Annotation

Declaring transactions in the bean configuration file requires knowledge of AOP concepts such as pointcuts, advices, and advisors. While the solution is advantageous in eliminating complex transaction API code, it does not come without its price. Developers who do not or cannot engage in the nitty-gritty of aspects declaration may find it hard to enable declarative transaction management. That is why in addition to declaring transactions in the bean configuration file with pointcut, advices, and advisors, Spring allows you to declare transactions by annotating your transactional methods with @Transactional enabled by the <tx:annotation-driven> element in the XML metadata configuration. Thus, to define a method as transactional, you annotate with @Transactional and provide any one of the arguments that define the transactional behavior. Note that you should only annotate public methods due to the proxy-base limitations of Spring AOP. The StockBrokerService implementation using the @Transactional annotation is shown in Listing 4–40.

Listing 4–40. Declaring methodswith @Transactional

package com.apress.prospringintegration.springenterprise.stocks.transactions.annotation;

import com.apress.prospringintegration.springenterprise.stocks.dao.StockBrokerService;
import com.apress.prospringintegration.springenterprise.stocks.dao.StockDao;
import com.apress.prospringintegration.springenterprise.stocks.model.Stock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.Calendar;
import java.util.Random;

@Component
public class AnnotationTxStockBrokerService implements StockBrokerService {

    @Autowired
    private HibernateTemplate hibernateTemplate;

    @Autowired
    @Qualifier("hibernateStockDao")
    private StockDao stockDao;

    Random random = new Random();

    @Transactional
    public void preFillStocks(final String exchangeId, final String... symbols) {
        int i = 0;
        for (String sym : symbols) {
            float pp = (float) Math.random() * 100.0f;
            int qq = (int) Math.random() * 250;
            Stock s = new Stock(sym, "INV00" + i, exchangeId, pp, qq, Calendar
                    .getInstance().getTime());
            stockDao.insert(s);
            System.out.println("ORIG INVENTORY: " + s.getInventoryCode() + " ");
            int randomized = (random.nextInt(100) % 4) == 0 ? 0 : i;
            s.setInventoryCode("INV00" + randomized);
            System.out.println("NEW RANDOMIZED INVENTORY:"
                    + s.getInventoryCode() + " " + randomized);
            stockDao.update(s);
            i++;
        }
    }

}

The @Transactional annotation may be applied at the method level or the class level. When applying this annotation to a class, all of the public methods within this class will be defined as transactional. Although you can apply @Transactional to interfaces or method declarations in an interface, it is not recommended because there may be conflicts with class-based proxies (CGLIB proxies).

In the bean configuration file, you only need to enable the <tx:annotation-driven> element and specify a transaction manager for it as shown in Listing 4–41. That way, Spring will advise methods on classes defined with @Transactional, and individual methods with @Transactional, for beans that are declared in the IoC container.

Listing 4–41. Declaring tx:annotation-driven tx_annotation.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"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/tx
    http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd">

  <context:component-scan
      base-package="com.apress.prospringintegration.springenterprise.stocks.transactions.annotation"/>

  <tx:annotation-driven transaction-manager="transactionManager"/>

</beans>

Again, this example is using Hibernate, which requires the HibernateTransactionManager and the dependent Hibernate sessionFactory as shown in Listing 4–42.

Listing 4–42. Demonstration of Transactional Property Attributes

package com.apress.prospringintegration.springenterprise.stocks.transactions.annotation;

import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
import org.springframework.orm.hibernate3.HibernateTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;

@Configuration
@ImportResource("tx_annotation.xml")
public class TxAnnotationConfig {
    @Autowired
    private SessionFactory sessionFactory;

    @Bean
    public PlatformTransactionManager transactionManager() throws Exception {
        HibernateTransactionManager dtm = new HibernateTransactionManager ();
        dtm.setSessionFactory(sessionFactory);
        dtm.setDefaultTimeout(30);
        return dtm;
    }
}

The main class to run the AOP transaction example with Hibernate as shown in Listing 4–43 will be similar to the previous examples.The main class creates a Spring context and obtains a reference to the annotationTxStockBrokerService instance. Calling the preFillStocks method will attempt to insert six new stocks resulting in a constraint violation causing the transaction to rollback. The main class will log that no rows have been added to the database.

Listing 4–43. Executing Class for @Transaction Methods

package com.apress.prospringintegration.springenterprise.stocks.runner;

import com.apress.prospringintegration.springenterprise.stocks.dao.StockBrokerService;
import com.apress.prospringintegration.springenterprise.stocks.dao.StockDao;
import com.apress.prospringintegration.springenterprise.stocks.dao.hibernate.HibernateStockDao;
import com.apress.prospringintegration.springenterprise.stocks.model.Stock;
import com.apress.prospringintegration.springenterprise.stocks.transactions.annotation.AnnotationTxStockBrokerService;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.GenericApplicationContext;

public class MainTxAnnotation {
    public static void main(String[] args) throws Exception {
        GenericApplicationContext context = new AnnotationConfigApplicationContext(
            "com.apress.prospringintegration.springenterprise.stocks.transactions.annotation",
            "com.apress.prospringintegration.springenterprise.stocks.dao.hibernate");

        StockBrokerService broker =
                context.getBean("annotationTxStockBrokerService", StockBrokerService.class);
        try {
            broker.preFillStocks("QQQQ", "INTC", "IBM", "XLA", "MGM", "C");
        } catch(Exception ex) {
            System.out.println("Exception: " + ex.getMessage());
        }

        StockDao stockDao = context.getBean(HibernateStockDao.class);
        System.out.println("Total rows inserted: " + stockDao.get().size());
        for (Stock s : stockDao.get()) {
            System.out.println("Stock added: " + s.getSymbol());
        }
    }
}

Because Spring auto-detects a PlatformTransactionManager named transactionManager in the container, you can further reduce configuration by naming your local transaction manager transactionManager, that way you will not need to specify the transaction-manager attribute in <tx:annotation-driven>.

In addition to declaring a method transactional with the @Transactional behavior, you may specify any of the TransactionDefinition properties as described at the beginning of this section. You simply describe a transactional behavior as an attribute to the @Transactional annotation.

For example, given a stock ordering system, we may want to find a stock that meets our criteria for price, quantity, and symbol. Because a transaction (or other transaction running) may acquire locks on rows and tables, a long transaction will tie up resources and have an impact on overall performance. If a transaction only reads, rather than update data, the database engine could optimize this transaction. In this case you can tailor the behavior of the transaction management by marking the transaction as readOnly (see Listing 4–44).

Listing 4–44. Demonstration of @Transactional Property Attributes

    @Transactional(isolation = Isolation.REPEATABLE_READ,
            timeout = 30,
            readOnly = true)
    public BestAsk findBestPrice(Order o) throws Exception {
        BestAsk bestAsk = new BestAsk();
        List<Stock> rets = hibernateTemplate.find("from Stock s where " +
                "s.pricePerShare <= ? and " +
                "s.quantityAvailable >= ? and s.symbol = ?",
                new Object[]{o.getBid(), o.getQuantity(), o.getSymbol()}, String.class);
        if (!rets.isEmpty()) {
            Stock stock = stockDao.findByInventoryCode(rets.get(0).getInventoryCode());
            bestAsk.setStock(stock);
        }

        return bestAsk;
    }

The timeout transaction attribute indicates how long your transaction can survive before it is forced to roll back. This can prevent a long transaction from tying up resources. The read-only attribute indicates that this transaction will only read, but not update, data. The read-only flag is just a hint to enable a resource to optimize the transaction, and a resource might not necessarily cause a failure if a write is attempted.

Additionally, Spring’s DataSourceTransactionManager may be setup with a default timeout value. This comes in handy when setup is done via Java configuration as are most of the examples as shown in Listing 4–45.

Listing 4–45. Setting the Default Timeout Property

    @Bean
    public PlatformTransactionManager transactionManager() throws Exception {
        DataSourceTransactionManager dtm = new DataSourceTransactionManager();
        dtm.setDataSource(dataSource);
        dtm.setDefaultTimeout(30);
        return dtm;
    }

Spring Remoting

It is standard organizational strategy to compartmentalize data based on requirements such as human resource management, or product inventory tracking. The source of such data can often be confined to storage that is not accessible through conventional means, such as a database, or file. This is the motivation for remote computing services to provide a link to data across business tiers.

In this section, we are going to discuss how you can leverage Springremoting. Spring supports a variety of remoting technologies in a consistent manner.On the server side, Spring allows exposing an arbitrary bean as a remote service through a service exporter.On the client side, Spring provides many proxy factory beans for you to create a local proxy for a remote service so that you can use the same remote service interface as if it were a local bean.

The Spring Framework features integration classes for remoting using the technologies shown in Table 4–6.

Table 4–6. Spring Remoting Technology Support

RMI Traditional Java to Java Remote Method Invocation protocol.
HTTP INVOKER Initiative by the Spring developers to enable Java serialization via HTTP.
HESSIAN A lightweight binary HTTP based protocol developed by Caucho.
Burlap Caucho’s XML variety of Hessian. The two APIs are entirely interchangeable.
JAX-RPC J2EE 1.4’s web service API that features WSDL 1.1, SOAP 1.1 using HTTP 1.1 as the transport.
JAX-WS Successor to JAX-RPC introduced in Java EE 5 featuring SOAP 1.2, JAXB data mapping, MTOM, and more.
JMS Java Message Service for integrating a wide ranges of messaging products, such a MQueue series.

In order to gain insight on the bigger picture of Spring remoting integration, we will take a look at RMI service exposition, and RMI client usage. The other technologies are configured in virtually the same way. Remote Method Invocation (RMI) is the Java-based remoting technology that allows multiple Java applications running in different JVMs to communicate with each other.RMI utilizes Java serialization to marshal and un-marshal method arguments and return values.It uses direct TCP/IP sockets for transport, and the RMI Registry that defines service endpoints.A simple service implementation using RMI gives you a setup that mirrors EJB remoting only it does not provide hooks for security contexts, or remote transaction propagation. However, Spring enables you to propagate contexts such as Spring security context by wiring one to the org.springframework.remoting.rmi.RmiServiceExporter bean instance.

Spring exposes support for RMI through either the traditional java.rmi.Remote interface, or transparently through RMI invokers.Choose RMI invokers using org.springframework.remoting.rmi.RmiServiceExporter if you have existing Spring applications deployed or wish to begin with a fresh start using RMI. If you already have traditional RMI service endpoints deployed and need to inter-operate, then you must use the Remote and java.rmi.RemoteException classes.

images Note As of Java SE 6, you no longer have to execute rmic to generate RMI stub and skeletons, as this is done completely inline by the Runtime.

Exposing and Invoking Services with RMI

Spring provides the org.springframework.remoting.rmi package that contains remoting facilitates that reduce complexity in exposing RMI services.You can leverage this on the server side by wiring RmiServiceExporter to export a Spring bean as an RMI service, enabling remote method invocation.On the client side, you simply wire RmiProxyFactoryBean with connectivity details to your service interface and that will create a proxy to your remote service.

Let us begin with a simple stock quoting scenario: we have a stock quoting service that delivers stock quotes, and a client that requests quotes for individual companies. But first, we need to setup the model. Note that all RMI transferrable objects must implement the java.io.Serializable interface; otherwise you will get a java.rmi.UnmarshalException. The Quote domain class is shown in Listing 4–46.

Listing 4–46. Quote Domain Object

package com.apress.prospringintegration.springenterprise.stocks.model;

import java.io.Serializable;

public class Quote implements Serializable {

    private String symbol;
    private float price;
    private String exchangeId;

    public Quote(String symbol, float price, String exchangeId) {
        this.symbol = symbol;
        this.price = price;
        this.exchangeId = exchangeId;
    }

    public Quote() {
    }

    public String getSymbol() {
        return symbol;
    }

    public void setSymbol(String symbol) {
        this.symbol = symbol;
    }

    public float getPrice() {
        return price;
    }

    public void setPrice(float price) {
        this.price = price;
    }

    public String getExchangeId() {
        return exchangeId;
    }

    public void setExchangeId(String exchangeId) {
        this.exchangeId = exchangeId;
    }
}

Let us define the Quote service interface that includes the method getQuote(String symbol), which returns a Quote with randomized price. The method getAllSymbols will simply return a list of symbols for which you haverequested (see Listing 4–47).

Listing 4–47. QuoteService Interface

package com.apress.prospringintegration.springenterprise.stocks.service;

import com.apress.prospringintegration.springenterprise.stocks.model.Quote;

import java.util.List;

public interface QuoteService {

    public Quote getQuote(String symbol);

    public List<String> getAllSymbols();
}

In addition to the interface, it is necessary to provide a full implementation as shown in Listing 4–48. In production applications, you will want this service to query some message oriented stock ticker system. Here, we are going to randomize stock symbols, and quote values.

Listing 4–48. QuoteService Business Implementation

package com.apress.prospringintegration.springenterprise.stocks.service;

import com.apress.prospringintegration.springenterprise.stocks.model.Quote;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class QuoteServiceImpl implements QuoteService {

    Map<String, Quote> quoteUniverse = new HashMap<String, Quote>();
    public Quote getQuote(String symbol) {
        if(quoteUniverse.containsKey(symbol))
            return quoteUniverse.get(symbol);
        Quote q = new Quote(symbol,(float)Math.random()*100,"NYSE");
        quoteUniverse.put(symbol, q);
        return q;
    }

    public List<String> getAllSymbols() {
        List<String> keyList = new ArrayList();
            keyList.addAll(quoteUniverse.keySet());
        return keyList;
    }
}

At this point, we have enough application detail that will enable us to expose our QuoteService remotely.We will use Spring’s remoting facilities here to configure a bean for the StockQuote service implementation and expose it as an RMI service by using RmiServiceExporter. The Java configuration is shown in Listing 4–49.

Listing 4–49. JavaConfiguration for Exposing RMI services

package com.apress.prospringintegration.springenterprise.stocks.service;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.remoting.rmi.RmiServiceExporter;

@Configuration
public class RmiServiceConfig {

    @Bean
    public QuoteService quoteService() {
        return new QuoteServiceImpl();
    }

    @Bean
    public RmiServiceExporter serviceExporter() throws Exception {
        RmiServiceExporter se = new RmiServiceExporter();
        se.setServiceName("QuoteService");
        se.setService(quoteService());
        se.setServiceInterface(QuoteService.class);
        //se.setRegistryHost("localhost");
        //se.setRegistryPort(1399);
        se.afterPropertiesSet();
        return se;
    }
}

The salient configuration bits here are defined in the RmiServiceExporter bean. The serviceName property specifies the endpoint name that will be defined in the RMI registry. We also specify serviceInterface and service to define our service interface and concrete implementation respectively. The configuration properties registryPort and registryHost allow you to bind to an existing registry. In the absence of registry configuration properties, a new registry would get started which defaults to localhost at port 1099.

Bootstrapping the RMI service is straightforward. You simply create an application context for the Spring configuration or Java configuration containing your service configuration as shown in Listing 4–50.

Listing 4–50. Bootstrapping RMI Services in J2SE

package com.apress.prospringintegration.springenterprise.stocks.runner;

import com.apress.prospringintegration.springenterprise.stocks.service.RmiServiceConfig;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class MainRmiService {
    public static void main(String[] args) {
        new AnnotationConfigApplicationContext(RmiServiceConfig.class);
    }
}

Running this program causes remote services to begin listening in the background on port 1099. Now we are going to illustrate remote service invocation through a Spring generated proxy. The RMI proxy generator class, RmiProxyFactoryBean enables declarative proxy generation that is injectable as a dependency in your client class. The example below shows how this is simply accomplished. We create our client class that will get injected with a proxy of our service interface, and it additionally serves as the execution bootstrap (see Listing 4–51).

Listing 4–51. A Simple QuoteService Client Implementation

package com.apress.prospringintegration.springenterprise.stocks.runner;

import com.apress.prospringintegration.springenterprise.stocks.client.QuoteServiceClient;
import com.apress.prospringintegration.springenterprise.stocks.model.Quote;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.GenericApplicationContext;

import java.util.ArrayList;
import java.util.List;

public class MainRmiClient {
    public static void main(String[] args) {
        GenericApplicationContext context =
                new AnnotationConfigApplicationContext(
                        "com.apress.prospringintegration.springenterprise.stocks.client");

        QuoteServiceClient client =
                context.getBean("client", QuoteServiceClient.class);

        List<Quote> myQuotes = new ArrayList<Quote>();
        myQuotes.add(client.getMyQuote("APRESS"));
        myQuotes.add(client.getMyQuote("SPRNG"));
        myQuotes.add(client.getMyQuote("INTGRN"));

        for (Quote myQuote : myQuotes) {
            System.out.println("Symbol : " + myQuote.getSymbol());
            System.out.println("Price  :" + myQuote.getPrice());
            System.out.println("Exchange: " + myQuote.getExchangeId());
        }
    }
}

We are ready to wire a client using the proxy factory. The generated proxy contains all of the necessary RMI boilerplate, so we only need to concentrate on our particular business implementation. The following configuration does the client-side wiring. In configuring any InitializingBean instance such as the RmiProxyFactoryBean, it is important to call the afterPropertiesSet() method to invoke special bean initialization logic (see Listing 4–52).

Listing 4–52. JavaConfiguration for a (QuoteClient) RMI client

package com.apress.prospringintegration.springenterprise.stocks.client;

import com.apress.prospringintegration.springenterprise.stocks.service.QuoteService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.remoting.rmi.RmiProxyFactoryBean;

@Configuration
public class RMIClientConfig {
    @Bean
    public QuoteService quoteServiceBean() {
        RmiProxyFactoryBean factory = new RmiProxyFactoryBean();
        factory.setServiceUrl("rmi://localhost:1099/QuoteService");
        factory.setServiceInterface(QuoteService.class);
        factory.afterPropertiesSet();
        return (QuoteService) factory.getObject();
    }

    @Bean
    public QuoteServiceClient client() {
        QuoteServiceClient qc = new QuoteServiceClient();
        qc.setMyQuoteService(quoteServiceBean());
        return qc;
    }
}

Run the main class MainRmiService to start the RMI service then run the client main class MainRmiClient. The client will connect to the remote RMI service return three quotes, as shown in Listing 4–53.

Listing 4–53. Results of Running the RMI Exmple Client

Symbol : APRESS
Price  :51.866577
Exchange: NYSE
Symbol : SPRNG
Price  :63.999958
Exchange: NYSE
Symbol : INTGRN
Price  :94.239365
Exchange: NYSE

Summary

This chapter has covered some of the building blocks in Spring’s enterprise support. We have covered how to use Spring’s database support to enable querying and updating relational databases. We demonstrated the benefits of Spring’s template support for ORM-support and standard JDBC technologies simplifying demanding query tasks. In addition, we have learned about Spring’s support for transaction management, as well as motivation for their use. A database may be setup and with minimal configuration, transactions may be used to enforce a high degree of integrity in the database. Finally, we demonstrated how to setup an RMI endpoint and consume one with minimal configuration and coding.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.186.219