brush clojure

Tuesday, April 15, 2008

Open Session In View with JSF and Spring

I expected that a quick google session would immediately deliver the standard solution for this situation, but it didn't go this way.

The problem: I want Open Session in View for an JSF/Spring application. Ok, I know there is something fishy about open session in view, but believe me, for this application this is just fine. There is a chance that the application will become a portlet eventually, so I didn't want to have to handle portlet and servlet filters issues too. Instead, I want to use the convenient hooks provided by JSF to open and close the hibernate session - phase listeners. Happily, the Spring-provided OpenSessionInViewFilter reveals the technicalities of how Spring deals with the hibernate session factory.

Here is the result:

public class HibernateRestoreViewPhaseListener implements PhaseListener {

public void afterPhase(PhaseEvent event) {
}

protected SessionFactory lookupSessionFactory() {

FacesContext context = FacesContext.getCurrentInstance();
ServletContext servletContext = (ServletContext) context
.getExternalContext().getContext();
WebApplicationContext wac = WebApplicationContextUtils
.getWebApplicationContext(servletContext);
return (SessionFactory) wac.getBean("hibernate-session-factory",
SessionFactory.class);
}

public void beforePhase(PhaseEvent event) {
SessionFactory sessionFactory = lookupSessionFactory();
if (!TransactionSynchronizationManager.hasResource(sessionFactory)) {
Session session = getSession(sessionFactory);
TransactionSynchronizationManager.bindResource(sessionFactory,
new SessionHolder(session));
}
}

public PhaseId getPhaseId() {
return PhaseId.RESTORE_VIEW;
}

protected Session getSession(SessionFactory sessionFactory)
throws DataAccessResourceFailureException {
Session session = SessionFactoryUtils.getSession(sessionFactory, true);
session.setFlushMode(FlushMode.MANUAL);
return session;
}
}

The session gets closed when Render Response phase is finished:


public class HibernateRenderResponsePhaseListener implements PhaseListener {

public void afterPhase(PhaseEvent event) {
SessionFactory sessionFactory = lookupSessionFactory();

SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager
.unbindResource(sessionFactory);
closeSession(sessionHolder.getSession(), sessionFactory);
}
. . .



Don't forget to register the listeners in faces-config.xml

<lifecycle>
<phase-listener>
...HibernateRestoreViewPhaseListener
</phase-listener>
<phase-listener>
...HibernateRenderResponsePhaseListener
</phase-listener>
</lifecycle>



I have the feeling this is not the final solution and this post will be edited soon.

1 comment:

  1. Hello,
    I see your code however
    I could not make it work. I saw that no one party, could send it to me (wagner.gsantos%gmail.com)?
    Congratulations and thank you.

    ReplyDelete