net.databinder.hib.conv.DataConversationRequestCycle.java Source code

Java tutorial

Introduction

Here is the source code for net.databinder.hib.conv.DataConversationRequestCycle.java

Source

/*
 * Databinder: a simple bridge from Wicket to Hibernate
 * Copyright (C) 2006  Nathan Hamblen nathan@technically.us
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

/*
 * Note: this class contains code adapted from wicket-contrib-database. 
 */

package net.databinder.hib.conv;

import net.databinder.hib.DataRequestCycle;
import net.databinder.hib.Databinder;
import net.databinder.hib.conv.components.IConversationPage;

import org.apache.wicket.Page;
import org.apache.wicket.Response;
import org.apache.wicket.protocol.http.WebApplication;
import org.apache.wicket.protocol.http.WebRequest;
import org.hibernate.FlushMode;
import org.hibernate.HibernateException;
import org.hibernate.classic.Session;
import org.hibernate.context.ManagedSessionContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Supports extended Hibernate sessions for long conversations. This is useful for a page or
 * a series of pages where changes are made to an entity that can not be immediately
 * committed. Using a "conversation" session, HibernateObjectModels are used normally, but
 * until the session is flushed the changes are not made to persistent storage.   
 * @author Nathan Hamblen
 */
public class DataConversationRequestCycle extends DataRequestCycle {
    private static final Logger log = LoggerFactory.getLogger(DataConversationRequestCycle.class);

    public DataConversationRequestCycle(WebApplication application, WebRequest request, Response response) {
        super(application, request, response);
    }

    /**
     * Does nothing; The session is open or retreived only when the request target is known.
     */
    @Override
    protected void onBeginRequest() {
    }

    /**
     * Called by DataStaticService when a session is needed and does not already exist. 
     * Determines current page and retrieves its associated conversation session if 
     * appropriate. Does nothing if current page is not yet available.
     * @param key factory key object, or null for the default factory
     */
    public void dataSessionRequested(Object key) {
        Page page = getResponsePage();
        if (page == null)
            page = getRequest().getPage();

        if (page == null) {
            Class pageClass = getResponsePageClass();
            if (pageClass != null) {
                openHibernateSession(key);
                // set to manual if we are going to a conv. page
                if (IConversationPage.class.isAssignableFrom(pageClass))
                    Databinder.getHibernateSession(key).setFlushMode(FlushMode.MANUAL);
            }
            return;
        }

        // if continuing a conversation page
        if (page instanceof IConversationPage) {
            // look for existing session
            IConversationPage convPage = (IConversationPage) page;
            org.hibernate.classic.Session sess = convPage.getConversationSession(key);

            // if usable session exists, try to open txn, bind, and return
            if (sess != null && sess.isOpen()) {
                try {
                    sess.beginTransaction();
                    ManagedSessionContext.bind(sess);
                    keys.add(key);
                    return;
                } catch (HibernateException e) {
                    log.warn("Existing session exception on beginTransation, opening new", e);
                }
            }
            // else start new one and set in page
            sess = openHibernateSession(key);
            sess.setFlushMode(FlushMode.MANUAL);
            ((IConversationPage) page).setConversationSession(key, sess);
            return;
        }
        // start new standard session
        openHibernateSession(key);
    }

    /**
     * Inspects responding page to determine if current Hibernate session should be closed
     * or left open and stored in the page.
     */
    @Override
    protected void onEndRequest() {
        for (Object key : keys) {
            if (!ManagedSessionContext.hasBind(Databinder.getHibernateSessionFactory(key)))
                return;
            org.hibernate.classic.Session sess = Databinder.getHibernateSession(key);
            boolean transactionComitted = false;
            if (sess.getTransaction().isActive())
                sess.getTransaction().rollback();
            else
                transactionComitted = true;

            Page page = getResponsePage();

            if (page != null) {
                // check for current conversational session
                if (page instanceof IConversationPage) {
                    IConversationPage convPage = (IConversationPage) page;
                    // close if not dirty contains no changes
                    if (transactionComitted && !sess.isDirty()) {
                        sess.close();
                        sess = null;
                    }
                    convPage.setConversationSession(key, sess);
                } else
                    sess.close();
            }
            ManagedSessionContext.unbind(Databinder.getHibernateSessionFactory(key));
        }
    }

    /** 
     * Closes and reopens Hibernate session for this Web session. Unrelated models may try to load 
     * themselves after this point. 
     */
    @Override
    public Page onRuntimeException(Page page, RuntimeException e) {
        for (Object key : keys) {
            if (Databinder.hasBoundSession(key)) {
                Session sess = Databinder.getHibernateSession(key);
                try {
                    if (sess.getTransaction().isActive())
                        sess.getTransaction().rollback();
                } finally {
                    sess.close();
                    ManagedSessionContext.unbind(Databinder.getHibernateSessionFactory(key));
                }
            }
            openHibernateSession(key);
        }
        return null;
    }

}