Welcome

A Hybrid SessionFactoryBean

LocalSessionFactoryBean is a nice way to create and initialize a Hibernate SessionFactory instance in applications. It lets us to configure other objects and properties, such as DataSource, and other hibernate properties that SessionFactory instance depends during initialization inside Spring?s context mechanism. We can easily configure other parts of our application, that are related with SessionFactory instance in that way,too. For example, we currently have an audit logging mechanism based on Hibernate?s entity interceptor, and this part of our application has to be brought up inside Spring context.

There might be cases, where SessionFactory must be shared accross multiple applications. In this case, we can wire up one via JndiObjectFactoryBean, starting up SessionFactory instance via a separate mechanism outside applications and register it in a JNDI context as a server-wide resource in a J2EE application server environment.

We are in a similar situation as mentioned above, we have many modules each runs as a separate web application in our system and each one needs a SessionFactory instance. SessionFactory instances are identical accross all modules, ie. each one loads up same Hibernate mapping files, connects to same database, and employs same properties. Hence, it would be good enough that one of those modules could bring a SessionFactory instance up and make it available to all other modules. That way, we might get at least a performance improvement during our modules? startup period.

We needed a way to start a SessionFactory instance up inside Spring context and then register it as a server-wide resource in JNDI context in the application server environment. As a result, we merged functionalities of both LocalSessionFactoryBean and JndiObjectFactoryBean classes to get our work to be done, and named it as JndiEnabledLocalSessionFactoryBean.

It extends from LocalSessionFactoryBean, and add some additional properties to enable JNDI lookup, namely jndiName, jndiAccessor, enableJndiLookup. If enableJndiLookup is true, it first tries to load SessionFactory instance from specified JNDI location. If there is an available instance found, it is provided to our application, otherwise it intializes a SessionFactory instance and registers it to that JNDI location. That way, other modules will get rid of intializing a new instance again and again separately. If enableJndiLookup property is false, it behaves as an ordinary LocalSessionFactoryBean instance, which might be preferrable for a development environment.

Here is an excerpt from source code and bean defintion from Spring context file as follows;

public class JndiEnabledLocalSessionFactoryBean extends LocalSessionFactoryBean {

    private Object sessionFactoryObject;
    private String jndiName;
    private JndiAccessor jndiAccessor;
    private boolean enableJndiLookup;

    public void afterPropertiesSet() throws IllegalArgumentException, HibernateException, IOException {
        try {
            if(isEnableJndiLookup()) {
              sessionFactoryObject = getJndiAccessor().getJndiTemplate().lookup(getJndiName());
            } else {
                initializeSessionFactory();
            }
        } catch (NamingException e) {
            initializeSessionFactory();
            try {
                 getJndiAccessor().getJndiTemplate().bind(getJndiName(),super.getObject());
            } catch (NamingException e1) {
                logger.warn("Cannot bind SessionFactory to JNDI Context",e1);
            }
        }
    }

    private void initializeSessionFactory() throws HibernateException, IOException {
        super.afterPropertiesSet();
        sessionFactoryObject = super.getObject();
    }
    public void destroy() throws HibernateException {
        if(isEnableJndiLookup()) {
               try {
                   getJndiAccessor().getJndiTemplate().unbind(getJndiName());
               } catch (NamingException e) {
                   logger.warn("Cannot unbind SessionFactory from JNDI Context",e);
               }

        }
        super.destroy();
    }

    public Object getObject() {
        return sessionFactoryObject;
    }

    //getter and setter methods for properties defined above, jndiName, jndiAccessor, enableJndiLookup
}

<bean id="sessionFactory" class="tbs.verisozlugu.ambar.JndiEnabledLocalSessionFactoryBean">
      <property name="configLocation">
            <value>classpath:hibernate.cfg.xml</value>
      </property>
      <property name="dataSource">
            <ref local="dataSource" />
      </property>
      <property name="jndiName">
            <value>vsSessionFactory</value>
      </property>
      <property name="enableJndiLookup">
            <value>false</value>
      </property>
      <property name="jndiAccessor">
            <ref local="jndiAccessor"/>
      </property>
</bean>

<bean id="jndiAccessor" class="org.springframework.jndi.JndiAccessor">
      <property name="jndiEnvironment">
            <value>
      java.naming.factory.initial=org.exolab.jms.jndi.InitialContextFactory
      java.naming.provider.url=rmi://localhost:1099
            </value>
      </property>
</bean>

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.