001 /*
002 * Databinder: a simple bridge from Wicket to Hibernate
003 * Copyright (C) 2006 Nathan Hamblen nathan@technically.us
004 *
005 * This library is free software; you can redistribute it and/or
006 * modify it under the terms of the GNU Lesser General Public
007 * License as published by the Free Software Foundation; either
008 * version 2.1 of the License, or (at your option) any later version.
009 *
010 * This library is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013 * Lesser General Public License for more details.
014 *
015 * You should have received a copy of the GNU Lesser General Public
016 * License along with this library; if not, write to the Free Software
017 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
018 */
019
020 /*
021 * Note: this class contains code adapted from wicket-contrib-database.
022 */
023
024 package net.databinder.hib;
025
026 import java.util.HashSet;
027
028 import net.databinder.CookieRequestCycle;
029
030 import org.apache.wicket.Page;
031 import org.apache.wicket.Response;
032 import org.apache.wicket.protocol.http.WebApplication;
033 import org.apache.wicket.protocol.http.WebRequest;
034 import org.hibernate.Session;
035 import org.hibernate.SessionFactory;
036 import org.hibernate.context.ManagedSessionContext;
037
038 /**
039 * <p>Opens Hibernate sessions and transactions as required and closes them at a request's
040 * end. Uncomitted transactions are rolled back. Uses keyed Hibernate session factories from
041 * Databinder service.</p>
042 * @see Databinder
043 * @author Nathan Hamblen
044 */
045 public class DataRequestCycle extends CookieRequestCycle implements HibernateRequestCycle {
046
047 /** Keys for session factories that have been opened for this request */
048 protected HashSet<Object> keys = new HashSet<Object>();
049
050 public DataRequestCycle(WebApplication application, WebRequest request, Response response) {
051 super(application, request, response);
052 }
053
054 /** Roll back active transactions and close session. */
055 protected void closeSession(Object key) {
056 Session sess = Databinder.getHibernateSession(key);
057
058 if (sess.isOpen())
059 try {
060 if (sess.getTransaction().isActive())
061 sess.getTransaction().rollback();
062 } finally {
063 sess.close();
064 }
065 }
066
067 /**
068 * Called by DataStaticService when a session is needed and does not already exist.
069 * Opens a new thread-bound Hibernate session.
070 */
071 public void dataSessionRequested(Object key) {
072 openHibernateSession(key);
073 }
074
075 /**
076 * Open a session and begin a transaction for the keyed session factory.
077 * @param key object, or null for the default factory
078 * @return newly opened session
079 */
080 protected org.hibernate.classic.Session openHibernateSession(Object key) {
081 org.hibernate.classic.Session sess = Databinder.getHibernateSessionFactory(key).openSession();
082 sess.beginTransaction();
083 ManagedSessionContext.bind(sess);
084 keys.add(key);
085 return sess;
086 }
087
088 /**
089 * Closes all Hibernate sessions opened for this request. If a transaction has
090 * not been committed, it will be rolled back before closing the session.
091 * @see net.databinder.components.hib.DataForm#onSubmit()
092 */
093 @Override
094 protected void onEndRequest() {
095 for (Object key : keys) {
096 SessionFactory sf = Databinder.getHibernateSessionFactory(key);
097 if (ManagedSessionContext.hasBind(sf)) {
098 closeSession(key);
099 ManagedSessionContext.unbind(sf);
100 }
101 }
102 }
103
104 /**
105 * Closes and reopens sessions for this request cycle. Unrelated models may try to load
106 * themselves after this point.
107 */
108 @Override
109 public Page onRuntimeException(Page page, RuntimeException e) {
110 onEndRequest();
111 onBeginRequest();
112 return null;
113 }
114
115 }