HIBERNATE JBoss.org
 |  Register  | 
     
News 
About 
   Feature List 
   Road Map 
Documentation 
   Related Projects 
   External Documentation 
Download 
Forum & Mailinglists 
Support & Training 
JIRA Issue Tracking
Wiki Community Area


Hibernate Public Training Courses


Get Hibernate in Action eBook!


JavaWorld 2003 Finalist


Jolt Award 2004 Winner
      
Documentation > Community Area > Hibernate inside PicoContainer

Hibernate inside PicoContainer

Integrating hibernate into PicoContainer is really trivial (as almost everything inside pico)

Create Your custom configuration datasource configuration

Subclass net.sf.hibernate.cfg.Configuration.

public class ProjectConfiguration extends Configuration {
    private final static Log _log = LogFactory.getLog(ProjectConfiguration.class);

    /**
     * configure from supplied properties path
     *
     * @param propertiesPath          Description of Parameter
     * @exception HibernateException  Description of Exception
     * @exception IOException         Description of Exception
     */
    public ProjectConfiguration(String propertiesPath) throws HibernateException, IOException {
        if (_log.isDebugEnabled()) {
            _log.debug("configuring from properties: " + propertiesPath);
        }
        Properties hibernateProperties = new Properties();
        hibernateProperties.load(Thread.currentThread().getContextClassLoader().getResourceAsStream(propertiesPath));
        addProperties(hibernateProperties);

        addClass(ProjectData.class);
        if (_log.isDebugEnabled()) {
            _log.debug("done.");
        }
    }

}

This class receives as parameter path to properties, configures itself and registers persistent classes. You could of course supply DOM tree or whatever Configuration eats. Or do everything manually (but we like external configuration)

Create Session Provider

SessionProvider will receive Configuration as constructor parameter, build its own Session Factory and provide sessionf for those who cares.

Here is example of session provider implementing thread local pattern:

public class ThreadLocalSessionProvider implements SessionProvider {

    private static Log _log = LogFactory.getLog(ThreadLocalSessionProvider.class);

    ThreadLocal     _session = new ThreadLocal();
    ThreadLocal     _transaction = new ThreadLocal();
    SessionFactory  _factory;

    /**
     * Constructor for the ThreadLocalSessionProvider object
     *
     * @param sfp  Description of Parameter
     */
    public ThreadLocalSessionProvider(Configuration cfg) {
        _factory = cfg.buildSessionFactory();
    }

    /**
     * Gets the Session attribute of the DefaultSessionProvider object
     *
     * @return                        The Session value
     * @exception HibernateException  Description of Exception
     */
    public Session getSession() throws HibernateException {
        Session sess = (Session) _session.get();
        if (sess == null) {
            sess = getFactory().openSession();
            Transaction tr = sess.beginTransaction();
            _session.set(sess);
            _transaction.set(tr);
            if (_log.isDebugEnabled()) {
                _log.debug("created session and started new transaction");
            }
        }
        return sess;
    }

    /**
     * rollback current transaction. shall be called in case of any hibernate
     * exception
     *
     * @exception HibernateException  Description of Exception
     */
    public void rollback() throws HibernateException {
        Transaction tr = (Transaction) _transaction.get();
        if (tr != null) {
            tr.rollback();
        }
        _transaction.set(null);
    }

    /**
     * give session back without disconnecting
     *
     * @param sess  session to be returned
     */
    public void returnSession(Session sess) {
    }

    /**
     * reset session if any
     */
    public void resetSession() {
        _session.set(null);
        _transaction.set(null);
    }

    /**
     * give session back and close it
     *
     * @param sess                    session to be closed
     * @exception HibernateException  may be thrown by hibernate
     */
    public void returnCloseSession(Session sess) throws HibernateException {
        Transaction tr = (Transaction) _transaction.get();
        if (tr != null && !tr.wasCommitted() && !tr.wasRolledBack()) {
            tr.commit();
            _transaction.set(null);
        }
        sess.close();
        _session.set(null);
        if (_log.isDebugEnabled()) {
            _log.debug("returned session and closed it");
        }
    }

    /**
     * Gets the Factory attribute of the BaseSessionProvider object
     *
     * @return   The Factory value
     */
    SessionFactory getFactory() {
        return _factory;
    }

}

Strictly speaking, it's not necessary to use thread local, because this component would be typically registered in request-level container or container can provide thread local semantics.

And creation of session factory is better placed in separate component, since session factory is invariant and can be easily shared.

Now create you DAO

Your dao shall depend (have constructor parameter) of type SessionFactoryProvider. The pico will do the right thing. Mine DAO looks like this

/**
 * hibernate implementation of project manager
 *
 * @author    konstantin
 * @created   February 13, 2004
 * @version   $Revision: 1.3 $
 */
public class HibernateProjectManager implements ProjectManager {
    private final static Log _log = LogFactory.getLog(HibernateProjectManager.class);

    ProjectAuthContext _authContext;
    SessionProvider _sessionProvider;

    /**
     * instantiate project manager off session provider and auth context wi ring
     * is done by container.
     *
     * @param sessionProvider  Description of Parameter
     * @param authContext      Description of Parameter
     */
    public HibernateProjectManager(SessionProvider sessionProvider, ProjectAuthContext authContext) {
        if (_log.isDebugEnabled()) {
            _log.debug("instantiated:" + authContext + " / " + sessionProvider);
        }
        _sessionProvider = sessionProvider;
        _authContext = authContext;
    }

    /**
     * create new project
     *
     * @param name                         Description of Parameter
     * @param description                  Description of Parameter
     * @param client                       Description of Parameter
     * @return                             Description of the Returned Value
     * @exception ProjectStorageException  Description of Exception
     */
    public Project createProject(String name, String description, String client) throws ProjectStorageException {

        try {
            ProjectData pd = new ProjectData();

            pd.setUser(_authContext.getUser());
            pd.setGroup(_authContext.getStatusGroup());
            pd.setName(name);
            pd.setDescription(description);
            pd.setClient(client);

            _sessionProvider.getSession().save(pd);

            return pd;
        } catch (Exception ex) {
            _log.error("exception while creating new project", ex);
            try {
                _sessionProvider.rollback();
            } catch (HibernateException ee) {
                _log.error("error while session rollback", ee);
            } finally {
                _sessionProvider.resetSession();
            }
            throw new ProjectStorageException(ex);
        }
    }

Launch it

In my testcase I do following:

Configure container

    /**
     * rig up pico container and recreate schema
     *
     * @exception Exception  Description of Exception
     */
    public void setUp() throws Exception {
        _container = new DefaultPicoContainer();

        _container.registerComponentImplementation(ProjectConfiguration.class,
            ProjectConfiguration.class,
            new Parameter[]{new ConstantParameter(new String("/connection.properties"))});

        _container.registerComponentImplementation(DefaultSessionFactoryProvider.class);
        _container.registerComponentImplementation(ThreadLocalSessionProvider.class);
        _container.registerComponentImplementation(TestAuthContext.class);
        _container.registerComponentImplementation(HibernateProjectManager.class);

        SchemaExport ex = new SchemaExport((Configuration) _container.getComponentInstance(ProjectConfiguration.class));

        ex.drop(true, true);
        ex.create(true, true);

        _sessionProvider = (SessionProvider) _container.getComponentInstance(ThreadLocalSessionProvider.class);
    }

...and use it ...


    /**
     * The JUnit setup method
     *
     * @exception Exception  Description of Exception
     */
    public void setUp() throws Exception {
        super.setUp();

        _manager = (ProjectManager) _container.getComponentInstance(HibernateProjectManager.class);
    }

This got me fully configured DAO ready to action

    /**
     * A unit test for JUnit
     *
     * @exception Exception  Description of Exception
     */
    public void testProjectCreation() throws Exception {

        Project project = _manager.createProject("foo", "bar", "baz");
        assertNotNull(project);
        assertNotNull(project.getId());
        assertEquals("foo", project.getName());
        assertEquals("bar", project.getDescription());
        assertEquals("baz", project.getClient());

        Collection projects = _manager.getProjects();
        assertEquals(1, projects.size());

        assertTrue(projects.contains(project));
    }

Conclusion

It took us only 3 really trivial classes, to develop fully functional hibernated DAO. And we have flexible configuration, we can have several instances of those services, thy can be located easily etc.

You can try it at home without any harm

      

coWiki