Struts2 sigue siendo uno de los frameworks web para java más populares. Lo del número 2 no está de más ya que ciertamente Struts2 y Struts a secas no tienen mucho que ver en cuanto a código. Aunque sí, formalmente los dos son frameworks MVC. Pero con Struts2 no es suficiente, ¿qué pasa con el acceso a los datos? Para facilitar la gestión de datos y ante todo poder centrarnos en el negocio y no andar por ejemplo cargando listas de objetos a mano de un resultset de jdbc disponemos de Hibernate, una pareja de baile ideal para Struts.

Hibernate logo
La sesión de Hibernate

Hibernate permite a nuestra aplicación abstraerse de la base de datos, hasta el punto siempre deseable en el que podemos cambiar la Base de datos tocando un fichero de configuración ajeno al código. Para que nuestra aplicación pueda acceder a los datos lo debe hacer a través de Hibernate y TODOS los accesos de Hibernate deben hacerse a través de una instancia de la clase Session. En una aplicación de consola por ejemplo, la clase java que pretenda acceder a los datos primero deberá conseguir una instancia de Session. Eso se suele hacer a través de una clase como esta

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;

/**
 * provide Hibernate Session factory
 * @author Pello Xabier Altadill Izura
 * @greetz blue mug
 */
public class HibernateSession {

    private static final SessionFactory sessionFactory = buildSessionFactory();
    private static Session session;

    /**
     * Based on hibernate.cfg.xml configuration creates
     * a SessionFactory
     * @return the session factory
     */
    private static SessionFactory buildSessionFactory() {
            Configuration configuration = new Configuration();
            configuration.configure();
            ServiceRegistry serviceRegistry = new ServiceRegistryBuilder().applySettings(configuration.getProperties()).buildServiceRegistry();
            SessionFactory sessionFactory = configuration.buildSessionFactory(serviceRegistry);
            return sessionFactory;
    }

    /**
     * this gives the desired session factory
     * @return hibernate Session Factory instance
     */
    public static SessionFactory getSessionFactory() {
        return sessionFactory;
    }

    /**
     * gives the current Session
     * @return Hibernate Session
     */
    public static Session getSession () {
        if (null == session) {
                session = sessionFactory.openSession();
        }

        return session;
    }
}

Como se puede ver, lo que hace esta clase básicamente es cargar la configuración de Hibernate que se mete en el fichero hibernate.cfg.xml, y simplemente devuelve una instancia de Session. En la clase java que utilizar Hibernate accedemos y usamos la sesión de esta manera:

        /*
         * inserts a new seller in database
         * retrieves generated id and sets to seller instance
         * @param new seller
         */
        public void insert(Seller seller) {
            SessionFactory sessionFactory = HibernateSession.getSessionFactory();
            Session session = sessionFactory.openSession();
            session.beginTransaction();

            Integer id = (Integer) session.save(seller);
            seller.setId(id);

            session.getTransaction().commit();

            session.close();

        }

Hasta aquí todo ok, y en una aplicación de consola no hay problemas. Pero... ¿Cómo nos lo montamos en Struts2 para que nuestrar clases puedan sacar una instancia de Session de Hibernate? A continuación muestro tres maneras que se mencionan con frecuencia:

1. Usando el contexto de Servlet

Mykong, un habitual de las recetas J2EE indica que ya que no existe una forma oficial de integrar los dos frameworks, se pueden utilizar el contexto. ¿cuál es el contexto en Struts2? No estamos en consola, estamos en un contexto de Servlet. Así que lo que hace es una clase que genera la Session que implementa ServletContextListener, lo cual nos va a permitir conseguir la sesión en cualquier clase dentro de la aplicación Struts2. Se puede ver este ejemplo, y en concreto el funcionamiento se ve en las clases HibernateListener.java, CustomerAction.java y el listener que se configura en web.xml.

2. Usando una librería que lo integra por anotaciones

No es oficial pero existe un proyecto alojado en googlecode con el que se hace mucho más fácil. No tenemos más que instalar un fichero jar y con un par de anotaciones ya tenemos nuestro Factory y nuestra Session inyectados de forma automática:

...
import com.googlecode.s2hibernate.struts2.plugin.annotations.SessionTarget;
import com.googlecode.s2hibernate.struts2.plugin.annotations.TransactionTarget;

/**
* Implementation of UserDAO interface
* @author Pellop Altadill
* @greetz again and again
*/
public class UserDAOImpl implements UserDAO {

	@SessionTarget
	Session session;

	@TransactionTarget
	Transaction transaction;

	/**
	 * Used to save or update a user.
	 */
	@Override
	public void saveOrUpdateUser(User user) {
		try {
			session.saveOrUpdate(user);
		} catch (Exception e) {
			transaction.rollback();
			e.printStackTrace();
		}
	}
...

El único problema de esto es que esa librería no se ha actualizado desde 2010. Por tanto pese a que es la forma más simple de todas a la larga no ofrece muchas garantías.

3. Usar Hibernate como si nada

Bueno, otra opción es hacerlo de manera normal, como si estuvieramos en una aplicación de consola. En un post de otro clásico de los blogs J2EE, Viral Patel lo hace sin ningún tipo de medida especial. Para la Session crea una clase llamada HibernateUtil que es la que provee la Session. Utilizamos la clase previa de HibernateSession y la utilizamos en las clases DAO.

Proyecto en acción

Como muestra de esta integración en esta url tienes un proyecto de Eclipse listo desarrollado en Struts2 e Hibernate. Esta hecho desde 0 mano, sin Maven ni nada ya que hay gente a mi alrededor que con su Windows8 Maven le explota en la cara.