Member Menu
 
 Monthly JBoss newsletter:
 
Hibernate Books
CaveatEmptor

Open Session in View

Sessions and transactions is required reading to understand this pattern. This page describes Hibernate 3.1.x and code shown here does not work in older versions.

The problem

A common issue in a typical (web-)application is the rendering of the view, after the main logic of the action has been completed, and therefore, the Hibernate Session has already been closed and the database transaction has ended. If you access detached objects that have been loaded in the Session inside your JSP (or any other view rendering mechanism), you might hit an unloaded collection or a proxy that isn't initialized. The exception you get is: LazyInitializationException: Session has been closed (or a very similar message). Of course, this is to be expected, after all you already ended your unit of work.

A first solution would be to open another unit of work for rendering the view. This can easily be done but is usually not the right approach. Rendering the view for a completed action is supposed to be inside the first unit of work, not a separate one. The solution, in two-tiered systems, with the action execution, data access through the Session, and the rendering of the view all in the same virtual machine, is to keep the Session open until the view has been rendered.

Using an interceptor

If you implement your Session handling with Hibernates built-in support for automatic Session context management, see Sessions and transactions, you have half of the code for this already. Now you only need some kind of interceptor that runs after the view has been rendered, and that will then commit the database transaction, hence close the Session. In other words, in most applications you need the following: when an HTTP request has to be handled, a new Session and database transaction will begin. Right before the response is send to the client, and after all the work has been done, the transaction will be committed, and the Session will be closed.

A good standard interceptor in a servlet container is a ServletFilter. It's rather trivial to put some lines into a custom filter that runs on every request and before every response, taken from CaveatEmptor:

public class HibernateSessionRequestFilter implements Filter {

    private static Log log = LogFactory.getLog(HibernateSessionRequestFilter.class);

    private SessionFactory sf;

    public void doFilter(ServletRequest request,
                         ServletResponse response,
                         FilterChain chain)
            throws IOException, ServletException {

        try {
            log.debug("Starting a database transaction");
            sf.getCurrentSession().beginTransaction();

            // Call the next filter (continue request processing)
            chain.doFilter(request, response);

            // Commit and cleanup
            log.debug("Committing the database transaction");
            sf.getCurrentSession().getTransaction().commit();

        } catch (StaleObjectStateException staleEx) {
            log.error("This interceptor does not implement optimistic concurrency control!");
            log.error("Your application will not work until you add compensation actions!");
            // Rollback, close everything, possibly compensate for any permanent changes
            // during the conversation, and finally restart business conversation. Maybe
            // give the user of the application a chance to merge some of his work with
            // fresh data... what you do here depends on your applications design.
            throw staleEx;
        } catch (Throwable ex) {
            // Rollback only
            ex.printStackTrace();
            try {
                if (sf.getCurrentSession().getTransaction().isActive()) {
                    log.debug("Trying to rollback database transaction after exception");
                    sf.getCurrentSession().getTransaction().rollback();
                }
            } catch (Throwable rbEx) {
                log.error("Could not rollback transaction after exception!", rbEx);
            }

            // Let others handle it... maybe another interceptor for exceptions?
            throw new ServletException(ex);
        }
    }

    public void init(FilterConfig filterConfig) throws ServletException {
        log.debug("Initializing filter...");
        log.debug("Obtaining SessionFactory from static HibernateUtil singleton");
        sf = HibernateUtil.getSessionFactory();
    }

    public void destroy() {}

}

If you combine this filter with the automatic Session context support, writing a DAO becomes as trivial as this:

public class ItemDAO {

    Session currentSession;

    public ItemDAO() {
        currentSession = HibernateUtil.getSessionFactory().getCurrentSession();
    }

    public Item getItemById(Long itemId) {
        return (Item) currentSession.load(Item.class, itemId);
    }
}

Alternatively, a DAO could require that a Session is a constructor argument, so responsibility of setting the current Session would be moved to the client of the DAO (which could be a factory). For more information about DAOs, see Generic Data Access Objects.

Now your application controllers can use the DAOs and don't have to bother at all with sessions or transactions, e.g. in your servlets:

public String execute(HttpRequest request) {

    Long itemId = request.getParameter(ITEM_ID);

    ItemDAO dao = new ItemDAO();

    request.setAttribute( RESULT, dao.getItemById(itemId) );
  
    return "success";
}

To enable the filter to run for all Http requests, add this to your web.xml configuration file:

    <filter>
        <filter-name>HibernateFilter</filter-name>
        <filter-class>my.package.HibernateThreadFilter</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>HibernateFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

If you don't want to start a Hibernate Session (and a transaction, which obtains a database connection from the pool) for every Http request, adjust the filter mapping to an appropriate URL pattern (e.g. only URLs that require database access). Or, add a switch to the filter that computes if a database session/transaction is needed, based on some arbitrary criteria (e.g. request parameter).

Caveat: Since the Session is flushed after the view has been rendered, database exceptions might occur after a successful output has been generated. If you use plain JSP and servlets the page output will be rendered into a buffer, usually 8K. If the buffer is full, it is flushed to the client browser! So, your user might see a successful page (200 OK) but in fact an exception occurred. To avoid this, don't render into the servlet engine buffer or increase the buffer size to a safe value. Most web frameworks avoid this issue by not rendering into the standard servlet engine buffer, but into their own.

What about three-tier environments?

It's clear that this pattern only makes sense if you can actually use a local Session when rendering the view. In a three-tier environment the view might be rendered on the presentation virtual machine, not on the service virtual machine with the business and data access layer. Therefore, keeping the Session and transaction open is not an option. In this case you have to send the right "amount" of data to the presentation layer, so a view can be constructed with the Session already closed. It depends on your architecture if you better use Detached Objects, Data Transfer Objects, or maybe a mix of both with the Command Pattern. These options are discussed in Hibernate in Action.

What about the extended Session pattern for long Conversations?

If you'd like to use a single Session for several database transactions, you either have to implement it completely yourself, or you have to use the built-in "application managed" strategy:

To enable the application-managed "current" Session strategy, set your hibernate.current_session_context_class configuration property to org.hibernate.context.ManagedSessionContext (or simply "managed" in Hibernate 3.2). You can now bind and unbind the "current" Session with static methods, and control the FlushMode and flushing manually. The Servlet filter shown earlier has to do this binding and flushing, during a conversation:

public class HibernateSessionConversationFilter
        implements Filter {

    private static Log log = LogFactory.getLog(HibernateSessionConversationFilter.class);

    private SessionFactory sf;

    public static final String HIBERNATE_SESSION_KEY = "hibernateSession";
    public static final String END_OF_CONVERSATION_FLAG = "endOfConversation";

    public void doFilter(ServletRequest request,
                         ServletResponse response,
                         FilterChain chain)
            throws IOException, ServletException {

        org.hibernate.classic.Session currentSession;

        // Try to get a Hibernate Session from the HttpSession
        HttpSession httpSession =
                ((HttpServletRequest) request).getSession();
        Session disconnectedSession =
                (Session) httpSession.getAttribute(HIBERNATE_SESSION_KEY);

        try {

            // Start a new conversation or in the middle?
            if (disconnectedSession == null) {
                log.debug(">>> New conversation");
                currentSession = sf.openSession();
                currentSession.setFlushMode(FlushMode.NEVER);
            } else {
                log.debug("< Continuing conversation");
                currentSession = (org.hibernate.classic.Session) disconnectedSession;
            }

            log.debug("Binding the current Session");
            ManagedSessionContext.bind(currentSession);

            log.debug("Starting a database transaction");
            currentSession.beginTransaction();

            log.debug("Processing the event");
            chain.doFilter(request, response);

            log.debug("Unbinding Session after processing");
            currentSession = ManagedSessionContext.unbind(sf);

            // End or continue the long-running conversation?
            if (request.getAttribute(END_OF_CONVERSATION_FLAG) != null ||
                request.getParameter(END_OF_CONVERSATION_FLAG) != null) {

                log.debug("Flushing Session");
                currentSession.flush();

                log.debug("Committing the database transaction");
                currentSession.getTransaction().commit();

                log.debug("Closing the Session");
                currentSession.close();

                log.debug("Cleaning Session from HttpSession");
                httpSession.setAttribute(HIBERNATE_SESSION_KEY, null);

                log.debug("<<< End of conversation");

            } else {

                log.debug("Committing database transaction");
                currentSession.getTransaction().commit();

                log.debug("Storing Session in the HttpSession");
                httpSession.setAttribute(HIBERNATE_SESSION_KEY, currentSession);

                log.debug("> Returning to user in conversation");
            }

        } catch (StaleObjectStateException staleEx) {
            log.error("This interceptor does not implement optimistic concurrency control!");
            log.error("Your application will not work until you add compensation actions!");
            // Rollback, close everything, possibly compensate for any permanent changes
            // during the conversation, and finally restart business conversation. Maybe
            // give the user of the application a chance to merge some of his work with
            // fresh data... what you do here depends on your applications design.
            throw staleEx;
        } catch (Throwable ex) {
            // Rollback only
            try {
                if (sf.getCurrentSession().getTransaction().isActive()) {
                    log.debug("Trying to rollback database transaction after exception");
                    sf.getCurrentSession().getTransaction().rollback();
                }
            } catch (Throwable rbEx) {
                log.error("Could not rollback transaction after exception!", rbEx);
            } finally {
                log.error("Cleanup after exception!");

                // Cleanup
                log.debug("Unbinding Session after exception");
                currentSession = ManagedSessionContext.unbind(sf);

                log.debug("Closing Session after exception");
                currentSession.close();

                log.debug("Removing Session from HttpSession");
                httpSession.setAttribute(HIBERNATE_SESSION_KEY, null);

            }

            // Let others handle it... maybe another interceptor for exceptions?
            throw new ServletException(ex);
        }

    }

    public void init(FilterConfig filterConfig) throws ServletException {
        log.debug("Initializing filter...");
        log.debug("Obtaining SessionFactory from static HibernateUtil singleton");
        sf = HibernateUtil.getSessionFactory();
    }

    public void destroy() {}

}

This filter is transparent for the rest of your application, no DAO or any other code that uses the "current" Session has to be changed. However, at some point the conversation has to end, and the Session has to be finally flushed and closed. The example above uses a special marker flag that has to be present in the request scope. You could set this flag during processing of the request, based on some arbitrary criteria. Maybe you have another interceptor layer for Conversation demarcation? Or a workflow engine?

I don't want to write servlet filters, they are so old school!

You are right, servlet filters are not really hot technology. However, they work very well as wrap-around interceptors in web applications and there is nothing wrong with servlet filters per se. As mentioned already, if you use a web framework that has its own interceptors, you will probably find them more flexible. Many containers also provide custom interceptors these days - note that if these containers do not implement a Java EE standard (such as EJB), you are locked into a proprietary runtime environment. Finally, a very flexible approach are AOP interceptors - see Session handling with AOP.

How do I handle exceptions?

Clearly, whenever an exception happens, the database transaction has to be rolled back. Another rule in Hibernate is that the current Session has to be closed and discarded immediately, it can't be re-used. Hence, this is all you have to do to handle exceptions from a Hibernate perspective. Of course you might want to retry some unit of work if it failed, or you might want to display custom errors. All of this is outside of the scope of Hibernate and can be implemented in any way you like.

Can I commit the transaction before rendering the view?

Apparently, though never promoted in Hibernate documentation, some developers are using a variation of this pattern that keeps the Session open until the view has been rendered, but commits the database transaction before rendering of the view. Then, during rendering of the view, unloaded proxies or collections are accessed and have to be initialized. Because the Session is still open, this seems to work. Even the Session can be called and will do what it is told. The Session gets a connection and executes a prepared statement for a single operation.

However, this kind of access is non-transactional. You need to enable the auto-commit mode in Hibernate's configuration for this. If, and only if you configured Hibernate to enable auto-commit mode behavior, does Hibernate set the connection into auto-commit mode after it obtains it from the pool, for the single operation, and returns it to the pool with close() on the JDBC Connection object afterwards.

Also note that non-transactional access will/might work if you forget to enable the auto-commit mode in the Hibernate configuration. If you did not enable auto-commit mode in Hibernate, the connection is in whatever mode it is by default after obtained from the pool, and returned there without commit or rollback. The behavior is then undefined. Never do this, as the JDBC specification does not say what happens on close() with any potentially pending transaction (yes, it is possible that a database transaction will be started implicitly when Hibernate obtains the connection from the pool).

In fact, consider any non-transactional data access (without JTA/EJBs) a complete anti-pattern, as there is no performance, scalability, or other benefit to be gained from it. Some frameworks that rely on Hibernate also rely on this anti-pattern, avoid them. Always set clear transaction boundaries to group your statements into units of work. You can consider using two transactions, one for executing the event, one for rendering the view, with the same Session.

Can I use two transactions in one Session?

Yes, this is actually a better implementation of this pattern. One database transaction is used to read and write data during the processing of the request event. The second database transaction is only used to read data, during rendering of the view. No modifications to objects are made at this point. Hence, database locks are released early in the first transaction, allowing better scalability, and the second transaction can possibly be optimized (e.g. some databases require read-only transaction settings for best cleanup after transaction commit). To use two transactions you need a more powerful interceptor than a simple servlet filter - AOP is a good choice. The JBoss Seam frameworks uses this model.

Why can't Hibernate just load objects on demand?

Every month someone has the idea that Hibernate could instead of throwing a LazyInitializationException just open up a new connection to the database (effectively starting a new Session) and load the collection or initialize the proxy that has been touched on-demand. Of course, this idea, while brilliant at first, has several shortcomings that only appear if you start to think about the consequences of ad-hoc transactional access.

If Hibernate would, hidden from the developer and outside of any transaction demarcation, start random database connections and transactions, why have transaction demarcation at all? What happens when Hibernate opens a new database connection to load a collection, but the owning entity has been deleted meanwhile? (Note that this problem does not appear with the two-transaction strategy as described above - the single Session provides repeatable reads for entities.) Why even have a service layer when every object can be retrieved by simply navigating to it? How much memory should be consumed by this and which objects should be evicted first? All of this leads to no solution, because Hibernate is a service for online transaction processing (and certain kinds of batch operations) and not a "streaming objects from some persistent data store in undefined units of work"-service. Also, in addition to the n+1 selects problem, do we really need an n+1 transaction and connection problem?

The solution for this issue is of course proper unit of work demarcation and design, supported by possibly an interception technique as shown in the pattern here, and/or the correct fetch technique so that all required information for a particular unit of work can be retrieved with minimum impact, best performance, and scalability.

This is all very difficult, can't this be done easier?

Hibernate can only do so much as a persistence service, the problem discussed here is however the responsibility of the application infrastructure, or framework. The EJB3 programming model makes transaction and persistence context management very easy, use the Hibernate EntityManager to get this API. Either run your EJBs inside a full J2EE application server (previews available from several vendors) or in a lightweight embeddable EJB3 container, JBoss Embeddable EJB3, in any Java environment. The JBoss Seam framework has built-in support for automatic context management, including persistence and conversations, with only a few annotations in your source code.

Note: Some people still believe that this pattern creates a dependency between the presentation layer and Hibernate. It does not, see this thread on the forum.

Note: Most of the comments on this page are outdated.


  NEW COMMENT

A workaround... 25 Aug 2003, 22:55 David Benoff
With JSP, one way around this is to disconnect from the session before 
placing it in the request, then use a scriptlet to reconnect to the 
session before rendering the view.  If for some reason you have a long 
delay between the controller returning a request and the view actually 
being rendered, this could help.  Its hard for me to imagine a web app 
where this would ever really occur, though.  And if you are building a 
genuinely enterprise-class app, you probably shouldn't be using this 
pattern, as it kind of breaks MVC anyway.
 
an error 26 Sep 2003, 01:25 jelmer
new Configuration().configure() 
 
should be 
 
new Configuration().configure().buildSessionFactory(); 
 
or you won't be able to lookup the session in JNDI
 
Workaround for Weblogic 6.x 21 Jan 2004, 06:31 paulkilroy
Looks like weblogic's filters get run on a forward. So I had to 
implement a stack counter to get around the exception check in 
doFilter (I could of removed it altogether, but its a nice check).
 
Not the best pattern for an enterprise app? 25 Feb 2004, 23:43 qvanegeren
David mentioned that if you were creating a true enterprise app then
this wouldn't be the right pattern to use anyway.  If this is the case,
what pattern should I be using for enterprise apps?

Quenten
 
Open Session pattern and Tapestry web framework 24 Mar 2004, 19:27 wassup
If you develop your application with Tapestry framework it is better 
do not use Servlet Filters to manage request cycle. More preferable to 
override setupForRequest() and cleanupAfterRequest() of Engine class.
 
Works great for me 14 Jan 2005, 17:24 jemiller
I just started using this design pattern today, so, maybe I haven't 
yet run into potential problems, but, so far so good. I can't see any 
drawbacks to using it. It's simple and efficient. I also like the fact 
that you don't have to worry about accidentally not closing the 
session. A great pattern IMHO.
 
Using this pattern in a Struts Application 28 Jul 2005, 17:10 pksiv
A couple of suggestions when using this pattern with a Struts application.
	
	1)  Only filter on the Struts ActionServlet - This ensures that you
don't accidentally close the session. 
	    I found that if my filter-mapping picked up the *.jsp files, 
	    <jsp:include>'s would get a separate path through the Filter and could 
	    close the session before you wanted it to. Filtering only on the
Struts 
	    ActionServlet ensures that every request is filtered exactly once.
	    (Of course this assumes that the entire app is going through Struts)
	
	<code>
	   <filter>
		   <filter-name>HibernateFilter</filter-name>
		   <filter-class>example.hibernate.HibernateFilter</filter-class>
	   </filter>
	   <filter-mapping>
		   <filter-name>HibernateFilter</filter-name>
		   <servlet-name>action</servlet-name>
	   </filter-mapping>
	   <servlet>
		   <servlet-name>action</servlet-name>
		   <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
		   ...
     </servlet>
  </code>
  
  2) Don't commit the Transaction in the Filter if you're using
Optimistic Locking.
     The reason I suggest this is because any Optimistic Locking
exceptions you receive 
     won't be thrown until the commit takes place. And in most
instances, you've already
     returned an ActionForward object that will take you to another page. 
     
     If you're on an edit page and hit the save button, you'd like the
Concurrent Modification
     message to appear on the edit page, not on the maintain or view
page that you'd forward to 
     if the update were successful. At the very least, I like my action
to be able to determine
     which ActionForward to navigate to when this exception is thrown.
     
     <code>
     ...
      public void doFilter(ServletRequest request, ServletResponse
response, FilterChain chain)
            throws IOException, ServletException {

        try {
             // We don't start the database transaction here, but when
first needed
            
              chain.doFilter(request, response);

            // Commit any pending database transaction.
            // HibernateUtil.commitTransaction();     <-- Do this in a
data-management layer.

        } finally {
            // No matter what happens, close the Session.
            HibernateUtil.closeSession();
        }
    }
    ...
    </code>
 
web.xml filters don't work 10 Sep 2005, 19:53 mschipperheyn
I think too much emphasis is placed on using servlet filters to 
implement this pattern. When you use includes etc, you will have 
multiple sessions on a single request, basically rendering this 
pattern **useless**. You would expect a filter to surround an entire 
request but it doesn't and as far as I can see this can't be 
implemented this way in a reliable way.

In Struts the only right way to implement this pattern is by extending 
the requestprocessor and closing the hibernate session after the 
action has been processed (process method in the request processor). 
For other frameworks it will be much the same. 

Marc
 
Spring's OpenSessionInViewFilter 13 Sep 2005, 03:46 rlubbat
An alternative solution that you don't need to implement yourself is to
use the Spring Franmework's OpenSessionInViewFilter class. You simply
define a servlet filter mapping for the filter and it takes care of
opening a Session when a request comes in and closing it when the
response is generated.

In fact, it will even bind the Session to the current thread and Spring
provides a static SessionFactoryUtils.getSession() method that
intelligently returns the bound Session or a new one (optionally).

We use this pattern in our Struts application and it works like a charm.
You can reliably get the one Session even if you use jsp:include and you
can pass around your Hibernate POJOs without worrying about lazy
initialization exceptions anywhere.

However, be aware that having a single Session open for an entire
request/response cycle can result in some unexpected behavior that did
not happen before. We encountered this ourselves, but dealt with it by
using the JUnit setUp() and tearDown() methods to mimic the
OpenSessionInViewFilter behavior in our unit tests and solving the
quirks from there.

Hibernate + Spring = bliss
 
Re: web.xml filters don't work 13 Sep 2005, 11:44 mgj2
POST QUESTIONS ON THE FORUM! COMMENTS HERE SHOULD ADD VALUE TO THE
PAGE!Hi Marc,

I don't understand in what circumstances you think multiple sessions
will be opened. If you use ThreadLocal as in the widely publicised
HibernateUtil class, you should only ever receive the same session back
no matter how many times you call HibernateUtil.currentSession();

Am I understanding it correctly?

Thanks,

Michael
 
Handling multiple filter requests for a single User request 22 Sep 2005, 23:09 rdleeper
I believe I have a solution that currently works for me with respect to
having the filter close the Session prematurely in the session-per-view
impl as defined above.  This will ensure that the Session will stay open
for the entire thread request which may contain multiple ServletRequests.

This came about because I was including <jsp:include .../> files in
other JSP's which resulted in additional filter requests consequently
closed the session before it should have been and produced undesirable
results.

The following is the filter code rewritten:

<code>

public class HibernateFilter implements Filter {

    private static Log log = LogFactory.getLog(HibernateFilter.class);

    public void init(FilterConfig filterConfig) throws ServletException {
        log.info("Servlet filter init, now opening/closing a Session for
each re
quest.");
    }

    private static String INIT_REQ_ATTR_NAME = "__INIT_REQ__";

    public void doFilter(ServletRequest request,
                         ServletResponse response,
                         FilterChain chain)
            throws IOException, ServletException {

        // There is actually no explicit "opening" of a Session, the
        // first call to HibernateUtil.beginTransaction() in control
        // logic (e.g. use case controller/event handler, or even a
        // DAO factory) will get a fresh Session.
        boolean initialRequest = false;

        try {
            HttpServletRequest httpRequest = (HttpServletRequest)request;
            Object val = httpRequest.getAttribute( INIT_REQ_ATTR_NAME );
            initialRequest = ( val == null );
            httpRequest.setAttribute( INIT_REQ_ATTR_NAME,
INIT_REQ_ATTR_NAME );

            chain.doFilter(request, response);

            HibernateUtil.commitTransaction();

        }
        catch (RuntimeException ex) {
            log.debug("Rolling back the database transaction.");
            HibernateUtil.rollbackTransaction(); // Also closes the session
            // Just rollback and let others handle the exception, e.g.
for display
            throw ex;

        }
        finally {
            // No matter what happens, close the Session.
            if ( initialRequest ) {
                HibernateUtil.closeSession();
            }
        }
    }

    public void destroy() {}
}


</code>


Each <jsp:include > forwards all request attributes.  The initial
request flag is then set in all subsequent requests within the thread. 
Therefore the initial filter call will then only close the session which
is the desired effect.

This allowed me to assign a filter for both "*.do" and "*.jsp" and not
have to worry about where the initial request started.

For those using struts, you can filter on the action servlet and also
jsp files at the same time and ensure that you will have only one Session.

Hope this helps (and makes sense)
- Doug
 
Re: web.xml filters don't work 14 Oct 2005, 13:27 pksiv
Marc,

if you apply the filter in a struts application to only the action
servlet, then it works just fine. The problem you describe only exists
if you filter on *.jsp or something like it.

pksiv
 
Long transaction and Spring 25 Oct 2005, 05:52 l.masini
You can use this solution to have a long session with Spring:
http://opensource2.atlassian.com/confluence/spring/pages/viewpage.action?pageId=1447
Ciao.
 
ThreadLocal Sessions and jsp:include 25 Oct 2005, 11:41 rbellia
The new request triggered by <jsp:include ...> can easily avoid the
Thread Local Session management Filter.

The answer is in Servlet 2.4 spec at SRV.6.2.5:
"... By using the new <dispatcher> element in the deployment descriptor,
the developer can indicate for a filter-mapping whether he would like
the filter to be applied to requests when:
1. The request comes directly from the client. ...
2.  ... 
3. The request is being processed under a request dispatcher ... using
an include() call. ...
4. ...

Mapping the Filter like this in web.xml:
  ...
  <filter-mapping>
    <filter-name>TLSessionManagementFilter</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>REQUEST</dispatcher>
  </filter-mapping>
  ...

It won´t intercept the <jsp:include> internal requests - Avoiding the
premature session closing.
 
Re: Handling multiple filter requests for a single User request 22 Nov 2005, 08:39 claan
<code>

>        try {
>            HttpServletRequest httpRequest = (HttpServletRequest)
request;
>            Object val = httpRequest.getAttribute(
INIT_REQ_ATTR_NAME );
>            initialRequest = ( val == null );
>            httpRequest.setAttribute( INIT_REQ_ATTR_NAME,
>INIT_REQ_ATTR_NAME );

>            chain.doFilter(request, response);

>            HibernateUtil.commitTransaction();

>        }
>        catch (RuntimeException ex) {
>            log.debug("Rolling back the database transaction.");
>            HibernateUtil.rollbackTransaction(); // Also closes the
session
>            // Just rollback and let others handle the exception, e.g.
>for display
>            throw ex;

>        }
>        finally {
>            // No matter what happens, close the Session.
>            if ( initialRequest ) {
>                HibernateUtil.closeSession();
>            }
>        }
>    }

>    public void destroy() {}
>}

</code>

>For those using struts, you can filter on the action servlet and also
>jsp files at the same time and ensure that you will have only one
Session.

Now, here's one for the STRUTS guys out there, how do you catch 
exceptions thrown from an Action class in the filter as STRUTS 
captures it before it reaches the filter... thus making the rollback 
unreachable?

Should you extend the RequestProcessor and take it from there?

Any ideas?

Regards
ace
 
struts / jsp session control 23 Nov 2005, 07:07 stewart.cambridge
How about this suggestion?

Have a servlet filter controlling a read-only session, mapped to *.jsp,
plus override struts RequestProcessor.processActionPerform() to do:
- open read/write session
- open try block
- call ActionForward = super.processActionPerform()
- catch hibernate errors, rollback, set ActionForward -> useful errors 
page, or even mapping.getInputForward()
- finally close session
- return ActionForward

This way you get the two session (r/w for action, r/o for jsp) model 
suggested earlier, for which servlet filters alone was inadequate.
This path allows you to still act within the struts controller should 
an error occur.

I think that's the way to go, or migrate to using Spring.

Stewart
 
Re: Open Session pattern and Tapestry web framework 30 May 2006, 21:53 phamvphu
POST QUESTIONS ON THE FORUM! COMMENTS HERE SHOULD ADD VALUE TO THE
PAGE!On 24 Mar 2004 19:27, wassup wrote:

>If you develop your application with Tapestry framework it is better
>do not use Servlet Filters to manage request cycle. More preferable to
>override setupForRequest() and cleanupAfterRequest() of Engine class.
hello
 
Implementing destroy() for cleanup 07 Feb 2007, 03:34 damiel
One problem I noticed with the HibernateSessionConversationFilter was
that when redeploying my application, the network connection to the
database was not released. I fixed this by implementing destroy() like this:

public void destroy()
{
    try
    {
        if (sessionFactory != null)
        {
            Session session = sessionFactory.getCurrentSession();
            if (session.isOpen()) session.close();
            sessionFactory.close();
        }
    }
    catch (HibernateException e)
    {
        logger.error("Failed to close session in destroy()", e);
    }
}

I'm not sure if this code is perfect, but it works for me. The resources
are now properly released when I redeploy the application.
 
Exception handling with Struts 14 Feb 2007, 04:59 damiel
First of all, my last comment was about HibernateSessionRequestFilter,
not about HibernateSessionConversationFilter as I wrote (I don't know if
it also applies to the latter) - sorry for that.

It was also hard for me to find out what to do in place of the "Let
others handle it..." comment in the HibernateSessionRequestFilter. We
are using Hibernate in a Struts application and of course would like to
present error messages on the next page to the user if the commit fails.

I had some success with the following method to create Struts error
messages:

/**
 * Append an error message to the next user visible page.
 * @param request HttpServletRequest
 * @param key Message key for this message 
 * @param value0 First replacement value
 */
private void addErrorMessage(ServletRequest request, String key, Object
value0)
{
    if (request instanceof HttpServletRequest)
    {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpSession session = httpRequest.getSession();

        ActionErrors actionErrors = (ActionErrors)
session.getAttribute(Globals.ERROR_KEY);
        if (actionErrors == null)
        {
            actionErrors = new ActionErrors();
            session.setAttribute(Globals.ERROR_KEY, actionErrors);
        }

        ActionMessage newMessage = new ActionMessage(key, value0);
        actionErrors.add(ActionErrors.GLOBAL_MESSAGE, newMessage);
    }
    else
    {
        logger.error("servlet filter request is no HttpServletRequest");
    }
}

In the exception handler, I check for several cases to create suitable
messages like this (shortended, there are more cases in reality):

if (ex instanceof JDBCException)
{
    logger.error("JDBCException", ex);
    SQLException sqlException = ((JDBCException)ex).getSQLException(); 
    addErrorMessage(request, "global.error.jdbcException",
sqlException.toString());
}
else
{
    logger.error("Unknown session error", ex);
    addErrorMessage(request, "global.error.unknown", ex.toString());
}

It's questionable if the Struts developers expected anybody to do this
from inside a servlet filter, but currently I have no better idea how to
pass this information to the presentation layer.
 
Re: Using this pattern in a Struts Application 09 May 2007, 15:04 RJAM
Can you send me the code example for this? I mean The zipped version of
this code.. ? By any Chance? I'm working on a Hibernate / Struts
Application and i have the Lazy Initialization problem. Please help.

Thanks
RJ
 
example on repeatable reads 08 May 2008, 03:51 deanhiller
This wiki has a great section on Why can't Hibernate just load objects
on demand? but it would be nice if someone could throw a concrete very
common example on why it is important to make sure you have repeatable
reads. 

My crappy example was you might be navigating from 2 different objects
to the same object and end up with two versions of that same object.  ie. 

child.getParent() which returns User object
shirt.getBuyers() which returns a list of User objects.

The list would have the same User object as the getParent method
returned but all of the data could have been changed.  Then you might
display that in a GUI.  Of course, the challenge back was that this
happens like .05% of the time so why complicate things by always having
to fix the LazyInitializationException...people spend more time with
that and fixing that so it is not worth it.  It seemed like a decent
argument to me.  Anyone with better examples, PLEASE post them!!!!
 
LazyInitializationException: Session has been closed... 25 Dec 2008, 19:22 jps
>> A common issue in a typical (web-)application
>> is the rendering of the view, after the main logic
>> of the action has been completed, and therefore,
>> the Hibernate Session has already been closed and
>> the database transaction has ended.
>> If you access detached objects that have been
>> loaded in the Session inside your JSP
>> (or any other view rendering mechanism),
>> you might hit an unloaded collection
>> or a proxy that isn't initialized.

I see this thread started in 2003, and I still encounter the same
problem in late 2008 with a very simple web-application...

Shoudnt there just be a function in the framework to FORCE 
the read of the whole data-structure before closing the connection?
Or is there such a function somewhere?
Didnt see that mentioned...

Might not be a practical solution for all applications,
but if your data isnt too large seems like it would be a
simple way to overcome this?

"Open Session in View"... 
doesnt seem like a very good solution when you try
to keep presentation and data-logic separate...
 
© Copyright 2006, Red Hat Middleware, LLC. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc. [Privacy Policy]