Norrman-

I wrote a Tapestry extension for Hibernate sessions, but I have not tried it yet in 2.3. It creates Hibernate sessions on demand with a scope of a single page for a single request. Sessions are automatically committed when the page renders or when you switch pages (cycle.setPage()).

My source code is attached - let me know if you have any problems using it in 2.3.

Eric Everman
package com.preceda.hibertap;

/**
 * @author Eric Everman of Preceda Design
 *
 * A Tapestry Extension that provides Hibernate Sessions on demand.
 * 
 * <p>
 * To use this extension, access it as you would any other Tapetstry Extension
 * via the ApplicationSpecification.
 * 
 * <p>
 * To configure the extension, add something like this to the .application:
 * (Not Javadoc friendly)
 * <extension name="SessionSourceExt" class="com.preceda.hibertap.SessionSourceExt" 
immediate="yes">
 *   <configure property-name="classList" type="String">
 *     com.preceda.contact.Contact, com.other.OtherClasse, ...
 *   </configure>
 * </extension>
 * 
 * <p>
 * To access the extension within a page or component, use:
 * <code>
 * SessionSourceExt sse = (SessionSourceExt)
 *  (getEngine().getSpecification().getExtension("SessionSourceExt"));
 * </code>
 * 
 * <p>
 * To use the SessionSource extension, there are only three methods that you
 * need to worry about: getSession, commitAndClose, and rollbackAndClose.
 * Each method takes a IRequestCycle as an argument.  A returned Session has
 * a lifetime of a <b>SINGLE PAGE</b> for a <b>SINGLE REQUEST</b>.  At the
 * end of that lifetime, the transaction will automatically be committed
 * via a pageEndRenderer listener.  Thus, unless you need to rollback a
 * transaction, you would normally not need to worry about flushing & committing.
 * 
 * <p>
 * If the page changes during the cycle via
 * <code>cycle.setPage()<code>, the current Session's transaction is
 * committed and the Session is discarded.  Further requests for a Session
 * will be serviced by a new Session.
 * 
 * <p>
 * Sample Usage (pretty easy):
 * 
 * <code>
 * SessionSourceExt sse = (SessionSourceExt)
 *   (getEngine().getSpecification().getExtension("SessionSourceExt"));
 * Session s = sse.getSession(cycle);
 * . . .do some work
 * cycle.setPage("Success");    //Session is auto committed & closed
 * </code>
 * 
 * <p>
 * To Do:
 * <ul>
 * <li>Would a method 'commitAndContinue' be useful?
 * </ul>
 * 
 */

import java.util.StringTokenizer;
import java.io.InputStream;
import java.util.Properties;

import net.sf.tapestry.IPage;
import net.sf.tapestry.IRequestCycle;
import net.sf.tapestry.event.PageEvent;
import net.sf.tapestry.event.PageRenderListener;

import cirrus.hibernate.Session;
import cirrus.hibernate.SessionFactory;
import cirrus.hibernate.Transaction;
import cirrus.hibernate.Datastore;
import cirrus.hibernate.Hibernate;

public class SessionSourceExt {
        
        public final static String SESSION_KEY = "DEFAULT_HIBERNATE_SESSION";
        
        private String classList;       //List of classes to persist
        
        //Full absolute path name to the hibernate.properties file.
        //Defaults to Hibernate default.
        private String propertiesFileName = "/hibernate.properties";
        
        private SessionFactory sessionFactory;  //Used to create all requested Sessions
        
        //Single instance listener used to close & commit sessions
        //when a page completes the redering process.
        private PageRenderListener pageRenderListener;  
        
        
        /**
         * Default empty constructor
         */
        public SessionSourceExt() {}
        

        /**
         * A list of persisted classes.
         * 
         * A list of fully qualified class names that Hibernate should persist.
         * Names can be separated with commas, semi-colons, or spaces.
         * For each class persisted, Hibernate expects to find a file named
         * "ClassName.hbm.xml" in the same package location as the class.
         * 
         * @param classList String
         */
        public void setClassList(String classList) {
                this.classList = classList;
        }

        /**
         * Fully qualified name of the Hibernate Properties file.
         * 
         * Optional - defaults to "/hibernate.properties".
         * 
         * By Hibernate convention, this file is normally placed in the classpath
         * root, however it could be placed anywhere.  Note that the name must
         * be of this form:  "/package/package/name.properties" or if in the
         * classpath root: "/name.properties".
         * 
         * <b>Limitation</b>The properties file must configure Hibernate to supply its
         * own connections.
         * 
         * @param propertiesFileName String
         */
        public void setPropertiesFileName(String propertiesFileName) {
                this.propertiesFileName = propertiesFileName;
        }
        
        /**
         * Retrieves an existing Hibernate Session or creates a new one.
         */
        public Session getSession(IRequestCycle cycle) throws Exception {
                //System.out.print("*** getSession");
                
                SessionWrapper sw = (SessionWrapper)cycle.getAttribute(SESSION_KEY);
                Session sess = null;
                
                if (sw != null) sess = sw.session;
                
                if (sess == null) { 
                        
                        sess = createSession(cycle);    //No previous session, create 
new
                        
                } else if (! sess.isOpen()) {
                        
                        closeAndRollback(cycle);                        //The user 
closed the session (do cleanup)
                        sess = createSession(cycle);    //Now create a new session
                                
                } else if (! sess.isConnected()) {
                        
                        sess.reconnect();               //The user disconnected the 
session
                }
                
                return sess;
        }
        
        /**
         * Create a new session and store it as an attribute of the RequestCycle.
         * 
         * This method also adds a pageEndRender listener on the current page so
         * that the session can be automatically committed when the page has
         * completed rendering.
         */
        private Session createSession(IRequestCycle cycle) throws Exception {
                //System.out.print("*** Create Session");
                
                if (sessionFactory == null) init();
                
                //Create a Session & begin a transaction on it
                Session session = sessionFactory.openSession();
                Transaction trans = session.beginTransaction();
                
                //Store Session & Transaction to a SessionWrapper & store as cycle 
attrib
                SessionWrapper sw = new SessionWrapper();
                sw.session = session;
                sw.transaction = trans;
                cycle.setAttribute(SESSION_KEY, sw);
                
                //Add pageRenderListener to allow auto commits
                IPage page = cycle.getPage();
                page.addPageRenderListener(pageRenderListener);
        
                
                return session;
        }
        
        /**
         * Close and commits the session contained in the passed cycle
         * 
         * After calling this method, the current Session will be defunct and future
         * calls to getSession will be servied by a new Session.
         */
        public void closeAndCommit(IRequestCycle cycle) {
                //System.out.print("*** Close And Commit Session");
                
                SessionWrapper sw = (SessionWrapper)cycle.getAttribute(SESSION_KEY);
                
                if (sw != null) {
                        
                        Session session = sw.session;
                        Transaction trans = sw.transaction;
                        
                        if (session != null && session.isOpen()) {


                                try {
                                        
                                        try {
                                                
                                                trans.commit();
                                                //System.out.print("*** Session Closed 
OK");
                                                
                                        } catch (Exception ee) {
                                                
                                                System.out.print("*** Error during 
session close");
                                                trans.rollback();
                                                
                                        } finally {
                                                
                                                session.close();
                                                
                                        }
                                        
                                } catch (Exception e) {
                                        //Can't do anything at this point - rollback 
or close failed    
                                }
                                
                        } else {

                                System.out.print("*** Session is closed (!!)");
                                
                        }
                        
                        //Cleanup
                        cycle.removeAttribute(SESSION_KEY);
                        cycle.getPage().removePageRenderListener(pageRenderListener);
                
                } else {

                        System.out.print("*** There is no SessionWrapper!!!");
                        
                }
                
                        
        }
        
        /**
         * Rolls back the session's transaction and closes the session.
         * 
         * After calling this method, the current Session will be defunct and future
         * calls to getSession will be servied by a new Session.
         */
        public void closeAndRollback(IRequestCycle cycle) {
                //System.out.print("*** Rollback");
                
                
                SessionWrapper sw = (SessionWrapper)cycle.getAttribute(SESSION_KEY);
                
                if (sw != null) {
                        
                        Session sess = sw.session;
                        Transaction trans = sw.transaction;
                        
                        if (trans != null) { 
                                
                                try {
                                        trans.rollback();
                                } catch (Exception e) { /* Not much we can do */ }
                                
                                try {
                                        sess.close();
                                } catch (Exception e) { /* Not much we can do */ }
                                
                        }
                                
                                
                        //Cleanup
                        cycle.removeAttribute(SESSION_KEY);
                        cycle.getPage().removePageRenderListener(pageRenderListener);
                        
                } else {
                        System.out.print("*** You are trying to rollback a cycle with 
no Session!!");
                }

        }
        
        private void init() throws Exception {

                if (classList == null || classList.length() == 0) {
                        
                        throw new Exception(
                                "The Required init param classNames was not set or was 
empty.");
                                
                } else {
                        
                        pageRenderListener = new PageRenderListener() {
                                public void pageBeginRender(PageEvent event) { /*Don't 
need this event*/ }
                                
                                public void pageEndRender(PageEvent event) {
                                        
                                        //System.out.print("*** PageEndRender Event");
                                        closeAndCommit(event.getRequestCycle());
                                                
                                        
event.getRequestCycle().removeAttribute(SESSION_KEY);
                                        
event.getPage().removePageRenderListener(pageRenderListener);
                                }
                        };
                        
                        StringTokenizer st = new StringTokenizer(classList, ",; ");
                        Datastore ds = Hibernate.createDatastore();
                        
                        try {
                                
                                while (st.hasMoreElements()) {
                                        ds.storeClass(Class.forName(st.nextToken()));  
 
                                }
                                
                        } catch (Exception e) {
                                
                                throw new Exception(
                                        "An error occured while building Hibernate's 
persistant class list.  " +
                                        "Most likely, one of the class names is not on 
the classpath.",
                                        e);
                                        
                        }
                        

                        
                        //Load Hibernate Properties from properties file
                        Properties props = new Properties();
                        InputStream iStream = null;
                        
                        try {
                                
                                // "/" causes the loader to not convert dots to 
slashes (ie abs path).
                                iStream = 
this.getClass().getResourceAsStream(propertiesFileName);
                                props.load(iStream);
                                iStream.close();
                                
                        } catch (Exception e) {
                                
                                throw new Exception(
                                        "The properties file '" + propertiesFileName + 
"' could not be loaded.", e);
                                
                        }
                        

                        sessionFactory = ds.buildSessionFactory(props); //Build 
session factory


                        try {
                                
                                //Test session
                                Session s = sessionFactory.openSession();
                                Transaction t = s.beginTransaction();
                                t.commit();
                                s.close();
                                
                        } catch (Exception e) {
                                throw new Exception(
                                        "An error occured while testing the Hibernate 
SessionFactory.",
                                        e);     
                        }
                        
                        
                }
        }
        
        
        /**
         * Inner class used to encapsilate a session with its transaction
         */
        static class SessionWrapper {
                protected Session session;
                protected Transaction transaction;
        }



}

<<< text/plain; charset=us-ascii; format=flowed: Unrecognized >>>

Reply via email to