Chapter 12. Best Practices, Style Guide, Tips and Tricks

Hibernate supports several different systems for building applications. For example, you can start with Java objects (as shown in Chapter 3) or with an existing database (as shown in Chapter 4). If, as sometimes happens, you “inherit” a system, this may force your hand by making it necessary to start from an existing database.

In this chapter, we'll look at a few available technologies and solutions for reducing or improving your code. They aren't required but may make your life with Hibernate easier. They include:

  • Reducing code with inversion of control.

  • Reducing session-creation impact with ThreadLocal.

  • Using Hibernate as an EJB BMP Solution.

  • Integrating additional tools and technologies.

  • Reviewing applications that use Hibernate.

  • Strategies for getting started.

Hibernate is a popular technology, so watch the Hibernate Web site and forum (http://www.hibernate.org/) closely; there's always something interesting going on.

Reducing Code with Inversion of Control

Perhaps you wish to use Hibernate in a JSP application (as described in Chapter 2) but are unhappy with the copy-and-paste booking shown for managing transactions. If so, you can use anonymous inner classes to reduce bookkeeping while preserving control. This is popularly referred to as inversion of control, or IoC.

The term inversion of control refers to the notion that your code is handed to another class to actually be executed. Whenever you write code intended to run inside another application, you are, in a sense, inverting (or transferring) control of the execution environment to another system. In particular, the use in Java of anonymous inner classes in conjunction with a framework is dubbed “inversion of control.”

Listing 12.1 shows the use of an anonymous inner class to actually perform the database access. Two independent operations are shown. Each operation is performed by an anonymous HibernateSessionWrapper() implementation of the task() method. The first operation demonstrates access to the database, the second is an example of error handling. Note that the code shows no exception-handling strategy; it is subsumed into the underlying HibernateSession Wrapper class.

Example 12.1. Inversion of Control Example

package com.cascadetg.ch12;

import java.util.Iterator;

public class IoCExample
{

    public static void main(String[] args)
    {
        // Need one global configuration
        HibernateSessionWrapper.initialization();

        // Create our task as an anonymous inner class.
        // Note, no exception handling needed, implicit
        // availability of a session.
        HibernateSessionWrapper myTask = new
        HibernateSessionWrapper()
        {

            Object task(Object in) throws Exception
            {
                net.sf.hibernate.Query myQuery = session
                        .createQuery((String) in);

                Iterator result = myQuery.list().iterator();

                session.flush();
                return result;
            }
        };

        // Execute a bit of HQL and get the results
        Iterator result = (Iterator) myTask
                .perform("from Author");
        while (result.hasNext())
        {
            System.out.println(result.next().toString());
            System.out.flush();
        }

        // Create our task as an anonymous inner class.
        // Note, no exception handling needed, implicit
        // availability of a session.
        HibernateSessionWrapper myTask2 = new
        HibernateSessionWrapper()
        {

            Object task(Object in) throws Exception
            {
                throw new Exception();
            }
        };

        // Do the task.
        if (myTask2.perform() == null)
                System.out.println(myTask2.getException());
    }
}

The anonymous inner class in Listing 12.1 is a subclass of the abstract class shown in Listing 12.2. Only the task() method must be overridden. If the task() method fails because of an exception, the method automatically returns null, and additional methods are provided to determine the precise nature of the exception.

Example 12.2. Inversion of Control Example

package com.cascadetg.ch12;

import net.sf.hibernate.*;
import net.sf.hibernate.cfg.*;

public abstract class HibernateSessionWrapper
{

    /** This method must be overridden to actually do anything
    */
    abstract Object task(Object in) throws Exception;

    Session session = null;

    Transaction transaction = null;

    boolean stale = false;

    Exception problem = null;
    /**
     * Used to identify that a stale object was encountered as
     * part of the transaction.
     */
    public boolean isStaleOperation()
    {
        return stale;
    }

    public Exception getException()
    {
        return problem;
    }

    /** We use this session factory to create our sessions */
    public static SessionFactory sessionFactory;

    /**
     * Loads the Hibernate configuration information, sets up the
     * database and the Hibernate session factory.
     *
     * Should be customized for your application.
     */
    public static void initialization()
    {
        try
        {
            Configuration myConfiguration = new
                 Configuration();
            myConfiguration
                    .addClass(com.cascadetg.ch02.Post.class);
            myConfiguration
                    .addClass(com.cascadetg.ch02.Author.class);

            // Sets up the session factory (used in the rest
            // of the application).
            sessionFactory = myConfiguration
                    .buildSessionFactory();
        } catch (Exception e)
        {
            e.printStackTrace();
        }
    }

    public Object perform()
    {
        return perform(null);
    }

    /**
     * Actually does the set-up for the session, as well as
     * execute the task. Handles all of the exceptions (you may
     * wish to customize this per your login preference)
     */
    public Object perform(Object in)
    {
        Object result = null;
        try
        {
            session = sessionFactory.openSession();
            transaction = session.beginTransaction();

            result = task(in);

            transaction.commit();

        } catch (StaleObjectStateException staleException)
        {
            stale = true;
            try
            {
                transaction.rollback();
            } catch (Exception e2)
            {
                e2.printStackTrace();
            }
        } catch (Exception e)
        {
            result = null;
            problem = e;
            e.printStackTrace();
            try
            {
                transaction.rollback();
            } catch (Exception e2)
            {
                // Notify of a failure to roll the transaction
                // back
                e.printStackTrace();
            }
        } finally
        {
            try
            {
                if (session != null) session.close();
            } catch (Exception e)
            {
                // Silent failure of session close
            }
        }
        return result;
    }
}

If you find the inversion of control style of development interesting, you may wish to investigate the Spring framework (http://www.springframework.org/). Spring is a more sophisticated IoC framework than the one shown in Listing 12.2; it provides a number of additional services (both specific to Hibernate and helpful for application development in general).

Reducing Session Creation Impact with ThreadLocal

You can reduce the impact of retrieving a new Session object for each thread by reusing the Session for a given object. As described in Chapter 6 and Chapter 9, a Session is not sharable across threads. The code in Listing 12.3 shows a Hibernate-recommended mechanism for maintaining a per-thread Session variable. The real work of this code is done in the java.lang.ThreadLocal class, which simplifies the use of a per-thread variable.

Example 12.3. ThreadLocal Example

import net.sf.hibernate.*;
import net.sf.hibernate.cfg.*;

public class HibernateUtil {

    private static final SessionFactory sessionFactory;

    static {
        try {
            sessionFactory =
                  new Configuration().configure()
                         .buildSessionFactory();
        } catch (HibernateException ex) {
            throw new RuntimeException(
                  "Exception building SessionFactory: "
                        + ex.getMessage(), ex);
        }
    }

    public static final java.lang.ThreadLocal
      session = new java.lang. ThreadLocal();

    public static Session currentSession() throws
    HibernateException {
        Session s = (Session) session.get();
        // Open a new Session, if this Thread has none yet
        if (s == null) {
            s = sessionFactory.openSession();
            session.set(s);
        }
        return s;
    }

    public static void discardSession() throws
    HibernateException {
        Session s = (Session) session.get();
        session.set(null);
        if (s != null)
            s.close();
    }
}

With luck, you should already have your Session management contained in a specific class with a static method, as shown in Chapter 2. The biggest difficulty with the pattern shown in Listing 12.3 is that a Session object can be rendered into an untenable state if a transaction-related exception is shown (Hibernate explicitly does not allow reuse of a Session object in this situation). This is why an additional discardSession() method is shown above; you need to ensure that the Session object is discarded if your application throws a transaction-related exception, as shown in the discardSession() method.

Using Hibernate as an EJB BMP Solution

Hibernate is intended to work in a wide variety of environments, and works well as a bean-managed persistence (BMP) solution when used in a variety of J2EE application servers. In fact, JBoss has indicated that a future version of its software will likely use Hibernate as the basis for container-managed persistence (CMP).

The development process for BMP and EJB varies tremendously from development environment to environment and therefore is beyond the scope of this text. Conceptually, however, you are relying on your J2EE application server to provide a variety of services, such as identity management, clustering, and JDBC connection pooling, when you use Hibernate to handle the actual generated persistence (specifically, the generated SQL). This affords several advantages, such as the ability to unit test your database access logic outside the context of a full application server and also the ability to understand the persistence performance characteristics of an application independent of the application server. Let's say, for example, that you develop an application intended to target three different application servers. By using Hibernate as your persistence mechanism, you can test your application against your target databases with a greater sense of independence for the tests with the different application servers.

In any event, Hibernate should at most be considered an alternative to EJB container-managed persistence, not the full EJB specification.

If you are interested in using Hibernate in conjunction with EJB, you will find descriptions of the general integration at http://hibernate.org/82.html and http://hibernate.org/166.html. A description of how to add Hibernate as a service to your JBoss installation can be found at http://hibernate.org/66.html.

Integrating with Other Technologies

Hibernate is a very popular package, and several developers have posted tips and tricks for integrating Hibernate with other packages. Table 12.1 shows a list, up to date as of this writing, of some of the products and technologies that in one form or another have been integrated with Hibernate. For the latest information, consult the http://hibernate.org/ Web site.

Table 12.1. Technologies Integrated with Hibernate

Technology

Use

Page

Eclipse

Java IDE

http://www.midrangeserver.com/fhg/fhg030304-story01.html

HiberClipse

Eclipse Plugin

http://sourceforge.net/projects/hiberclipse/

Hibernate JSP Tags

JSP Tags

http://sourceforge.net/projects/hibtags/

HibernateSynchronizer

Eclipse Plugin

http://sourceforge.net/projects/hibernatesynch/

Hibernator

Eclipse Plugin

http://sourceforge.net/projects/hibernator

IntelliJ IDEA

Java IDE

http://hibernate.org/108.html

JUnit

Unit Test Framework

http://hibernate.org/83.html

Log4j

Logging Toolkit

http://hibernate.org/97.html

Lucerne

Free Text Search Engine

http://hibernate.org/138.html

Maven

Project Management

http://hibernate.org/134.html

Pico

Lightweight Container

http://hibernate.org/174.html

Spring

Java IoC Framework

http://hibernate.org/110.html

Struts

Web MVC Framework

http://hibernate.org/105.html

Tangosol Coherence

Distributed Cache

http://hibernate.org/132.html

Tapestry

Web Application Framework

http://hibernate.org/96.html

Tomcat

Application Server

http://hibernate.org/114.html

WebSphere Application Developer (WASD) 5.x

IBM Java IDE

http://hibernate.org/173.html

Applications That Use Hibernate

Table 12.2 shows some applications that make use of Hibernate. If you wish to examine applications larger than those that can conveniently be included in a book like this one, you may wish to download and peruse the code for the open-source projects (and you may get ideas or useful tips from both the open-source and commercial products).

Table 12.2. Products That Use Hibernate

Application

Use

Page

DeepBlack

Weblog

http://deepblack.blackcore.com/

Flock

News aggregator

http://flock.sourceforge.net/

Jagzilla

Bugzilla Interface

http://sourceforge.net/projects/jagzilla/

JasperReports

Reporting Tool

http://hibernate.org/79.html

JavaLobby Community Platform

Portal

http://sourceforge.net/projects/gotjava/

jboard

Bulletin Board

http://sourceforge.net/projects/jboard/

jBpm

Business Process Management

http://jbpm.org/

Liferay

Enterprise Portal

http://www.liferay.com/

openEF/J

Enterprise Application Framework

http://sourceforge.net/projects/openef/

OpenReports

Reporting Tool

http://sourceforge.net/projects/oreports

PersonalBlog

Weblog

http://sourceforge.net/projects/personalblog/

Phoo

Java Bot Suite

http://sourceforge.net/projects/phoo/

Roller Weblogger

Weblog

http://www.rollerweblogger.org/

TM4J

Topic Map Engine

http://tm4j.org/

Strategies for Getting Started

Throughout this text, I've tried to provide as balanced a set of recommendations as possible. In this section, I offer some general guidelines for those who are still unsure about the proper approach. Consider this section to reflect opinion only—and keep in mind that since I don't know your application's requirements, these recommendations should be taken with a grain of salt.

Where to Start?

My approach for working with Hibernate depends on whether or not there is an existing database. If you are starting with an existing database, use Middlegen (as described in Chapter 4). If the database schema is extremely stable, you may wish to use Middlegen to generate a first pass at the *.hbm.xml files, and then hand-tune them as needed. If you believe the schema is potentially subject to change, follow the guidelines for Middlegen as described in Chapter 4.

If you are starting from scratch, use the *.hbm.xml mapping as your canonical format, and generate both your Java and database schema based on that (as described in Chapter 2 and Chapter 11). I find that starting from Java (as described in Chapter 3) is most comfortable for developers who are accustomed to using XDoclet as a refuge from the complexity of EJB. I find it much easier to generate persistent objects from my mapping file than to rely on generating get/set methods in bulk and then inspecting the generated *.hbm.xml files.

Start with Many-to-One and One-to-Many

Make sure that you understand the many-to-one and one-to-many relationships before working on the more esoteric types shown in Chapter 7. The vast majority of databases can be modeled relatively conveniently using only these two basic relationships. Class and the more sophisticated relationships are useful tools, but you should feel comfortable with the basic relationships before tackling them.

Profile Database Fetching

When you are first starting out with Hibernate, the relationship between queries and lazy loading of objects can be confusing. You will probably find it especially difficult to understand the implications of the different data-loading strategies. Use the tools shown in Chapter 10 to inspect and time the SQL generated by Hibernate.

Put another way, make sure that you understand how your object graph is going to be traversed. How do you expect to access your data? Make sure that you understand as many as possible of the creation, retrieval, update, and delete (CRUD) operations on your objects.

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

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