This is slightly modified from what is on the wiki
This should close a session after a timeout/or when thread dies. Note each query resets the timeout.
Code:
package com.diamondip.netcontrol.db;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Timer;
import java.util.TimerTask;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import net.sf.hibernate.HibernateException;
import net.sf.hibernate.JDBCException;
import net.sf.hibernate.MappingException;
import net.sf.hibernate.Session;
import net.sf.hibernate.SessionFactory;
public class HibernateSession {
public static final ThreadLocal session = new ThreadLocal();
Session hibernateSession;
private static SessionFactory sf = null;
ApplicationContext ctx = null;
private static Log log = LogFactory.getLog(ServiceLocator.class);
private static HibernateSession me;
static {
try
{
me = new HibernateSession();
}
catch (Exception e)
{
log.fatal("Error occurred initializing ServiceLocator");
e.printStackTrace();
}
}
// ~ Constructors ===========================================================
private HibernateSession() throws HibernateException, JDBCException {
// Try to lookup a JNDI Connection
try {
sf = HibernateSession.createConfiguration();
if (sf == null) {
System.out.println("session factory is null in after create config");
}
} catch (MappingException me) {
if (log.isDebugEnabled()) {
log.info("error communicating with JNDI, assuming testcase");
}
}
}
public static Session currentSession() throws ServiceException {
Session s = (Session) session.get();
if (s == null) {
//SessionFactory sf;
try {
// sf = (SessionFactory) new InitialContext().lookup("SessionFactory");
s = sf.openSession();
} catch (HibernateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
throw new ServiceException(e);
}
s = (Session) createSession(s,50 * 1000); //50 sec
session.set(s);
}
return s;
}
public static void closeSession() throws HibernateException {
Session s = (Session) session.get();
session.set(null);
if (s != null){
if (s.isOpen())
{
s.flush();
s.close();
if (log.isDebugEnabled())
{
log.debug("Closed hibernate session.");
}
}
}
}
/**
* The classes with mappings to add to the Configuration are enumerated here.
* There should be a "${class}.hbm.xml" mapping file for each class
* stored with each compiled class file.
* <p>
* To complete the Hibernate setup, there must be a valid "hibernate.properties"
* file under the "classes" folder (root of the classpath),
* which specifies the details of the database hookup.
* <p>
* The mapping documents and properties file is all that Hibernate requires.
* <p>
* @return A Configuration object
* @throws net.sf.hibernate.MappingException if any the mapping documents can be rendered.
*/
private static final SessionFactory createConfiguration() throws MappingException, HibernateException {
log.info(" Hibernate plugIn configuration loaded");
/* Perhaps these classes can be loaded from the config files instead of specifying them here
*/
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext.xml");
return ((SessionFactory) ctx.getBean("sessionFactory"));
}
private static Session createSession(final Session hibernate, final long timeout) {
return (Session)Proxy.newProxyInstance(Session.class.getClassLoader(),
new Class[] { Session.class },
new InvocationHandler () {
Session _hibernate = hibernate;
TimerTask t = null;
Timer timer = null;
private void renewLease() {
System.out.println("renew called");
if (timer != null) {
timer.cancel();
System.out.println("cancel timer:" + timer);
}
timer = new Timer();
t = new TimerTask() {
public void run() {
try {
//run session close....
closeSession();
} catch (HibernateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
timer.schedule(t,timeout);
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equals("close")) {
//cancel the timer;
if (timer != null) {
timer.cancel();
return method.invoke(_hibernate,args);
}
}
renewLease();
return method.invoke(_hibernate,args);
}
});
}
}