Hi!
I have been using the
Open Session in View pattern as described
here with hibernate 3.2.4.sp1 and in a portal environment for quite a while without any problems. Recently though, while doing some cleanup, I noticed that I had DAO code in my jsp:
Code:
<%
DAOFactory factory = DAOFactory.instance(DAOFactory.HIBERNATE);
PseudoPotentialDAO pseudoDao = factory.getPseudoPotentialDAO();
AtomDAO atomDao = factory.getAtomDAO();
List<PseudoPotential> list = pseudoDao.findAll();
%>
etc...
(I'm also using the DAO pattern as illustrated
here)
So I moved this code to the portlet class, and after getting LazyInitializationExceptions, found out that I was not actually using the
Open Session in View pattern.
After some banging of wall against head, I stumbled onto the apache Portlet Filter:
http://portals.apache.org/bridges/multi ... index.htmlA painful process later, in which more walls were hurt, I removed the servlet filter configuration from my web.xml:
Code:
- <filter>
- <filter-name>HibernateFilter</filter-name>
- <filter-class>org.vlab.pseudo.persistence.HibernateSessionRequestFilter</filter-class>
- </filter>
- <filter-mapping>
- <filter-name>HibernateFilter</filter-name>
- <servlet-name>PortletServlet</servlet-name>
- <!-- See Servlet 2.4 spec SRV.6.2.5 -->
- <dispatcher>INCLUDE</dispatcher>
- <dispatcher>FORWARD</dispatcher>
- </filter-mapping>
and configured my portlet.xml to use a newly-created portlet filter
Code:
<portlet>
<description xml:lang="en">A portlet for managing the pseudo-potential repository</description>
<portlet-name>PseudoAdminPortlet</portlet-name>
<display-name xml:lang="en">Pseudo-Repository Administration</display-name>
- <portlet-class>edu.umn.msi.vlabPortlets.portlets.PseudoAdminPortlet</portlet-class>
+ <portlet-class>org.apache.portals.bridges.portletfilter.FilterPortlet</portlet-class>
+ <init-param>
+ <name>portlet-class</name>
+ <value>edu.umn.msi.vlabPortlets.portlets.PseudoAdminPortlet</value>
+ </init-param>
+ <init-param>
+ <name>portlet-filters</name>
+ <value>edu.umn.msi.vlabPortlets.HibernatePortletFilter</value>
+ </init-param>
<expiration-cache>0</expiration-cache>
<supports><mime-type>text/html</mime-type></supports>
<supported-locale>en</supported-locale>
<portlet-info>....</portlet-info>
</portlet>
I then got my mysterious error. Could anybody shed more light on this?
Code:
java.lang.ExceptionInInitializerError
at org.vlab.pseudo.persistence.HibernateUtil.<clinit>(HibernateUtil.java:17)
at edu.umn.msi.vlabPortlets.HibernatePortletFilter.init(HibernatePortletFilter.java:32)
at org.apache.portals.bridges.portletfilter.PortletFilterConfig.<init>(PortletFilterConfig.java:124)
at org.apache.portals.bridges.portletfilter.PortletFilterChain.<init>(PortletFilterChain.java:87)
at org.apache.portals.bridges.portletfilter.FilterPortlet.init(FilterPortlet.java:95)
at org.gridlab.gridsphere.provider.portlet.jsr.PortletServlet.service(PortletServlet.java:184)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:802)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:252)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:173)
at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:672)
at org.apache.catalina.core.ApplicationDispatcher.doInclude(ApplicationDispatcher.java:539)
at org.apache.catalina.core.ApplicationDispatcher.include(ApplicationDispatcher.java:499)
at org.gridlab.gridsphere.portletcontainer.impl.SportletDispatcher.include(SportletDispatcher.java:287)
at org.gridlab.gridsphere.portletcontainer.impl.SportletDispatcher.init(SportletDispatcher.java:72)
at org.gridlab.gridsphere.portletcontainer.PortletInvoker.initPortletWebApp(PortletInvoker.java:385)
at org.gridlab.gridsphere.services.core.registry.impl.PortletManager.initPortletWebApplication(PortletManager.java:275)
at org.gridlab.gridsphere.services.core.registry.impl.PortletManager.initAllPortletWebApplications(PortletManager.java:258)
at org.gridlab.gridsphere.filters.GridSphereFilter.doFilter(GridSphereFilter.java:67)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:202)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:173)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:213)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:178)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:126)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:105)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:107)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:148)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:869)
at org.apache.coyote.http11.Http11BaseProtocol$Http11ConnectionHandler.processConnection(Http11BaseProtocol.java:664)
at org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpoint.java:527)
at org.apache.tomcat.util.net.LeaderFollowerWorkerThread.runIt(LeaderFollowerWorkerThread.java:80)
at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:684)
at java.lang.Thread.run(Thread.java:595)
Caused by: java.lang.ExceptionInInitializerError
at net.sf.cglib.proxy.Enhancer.getMethods(Enhancer.java:432)
at net.sf.cglib.proxy.Enhancer.generateClass(Enhancer.java:456)
at net.sf.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25)
at net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:216)
at net.sf.cglib.proxy.Enhancer.createHelper(Enhancer.java:377)
at net.sf.cglib.proxy.Enhancer.createClass(Enhancer.java:317)
at org.hibernate.proxy.pojo.cglib.CGLIBLazyInitializer.getProxyFactory(CGLIBLazyInitializer.java:127)
at org.hibernate.proxy.pojo.cglib.CGLIBProxyFactory.postInstantiate(CGLIBProxyFactory.java:43)
at org.hibernate.tuple.entity.PojoEntityTuplizer.buildProxyFactory(PojoEntityTuplizer.java:162)
at org.hibernate.tuple.entity.AbstractEntityTuplizer.<init>(AbstractEntityTuplizer.java:135)
at org.hibernate.tuple.entity.PojoEntityTuplizer.<init>(PojoEntityTuplizer.java:55)
at org.hibernate.tuple.entity.EntityEntityModeToTuplizerMapping.<init>(EntityEntityModeToTuplizerMapping.java:56)
at org.hibernate.tuple.entity.EntityMetamodel.<init>(EntityMetamodel.java:295)
at org.hibernate.persister.entity.AbstractEntityPersister.<init>(AbstractEntityPersister.java:434)
at org.hibernate.persister.entity.SingleTableEntityPersister.<init>(SingleTableEntityPersister.java:109)
at org.hibernate.persister.PersisterFactory.createClassPersister(PersisterFactory.java:55)
at org.hibernate.impl.SessionFactoryImpl.<init>(SessionFactoryImpl.java:226)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1294)
at org.vlab.pseudo.persistence.HibernateUtil.<clinit>(HibernateUtil.java:13)
... 31 more
Caused by: java.lang.ClassCastException: net.sf.cglib.core.MethodWrapper$MethodWrapperKey$$KeyFactoryByCGLIB$$d45e49f7
at net.sf.cglib.core.KeyFactory$Generator.create(KeyFactory.java:145)
at net.sf.cglib.core.KeyFactory.create(KeyFactory.java:117)
at net.sf.cglib.core.KeyFactory.create(KeyFactory.java:108)
at net.sf.cglib.core.KeyFactory.create(KeyFactory.java:104)
at net.sf.cglib.core.MethodWrapper.<clinit>(MethodWrapper.java:22)
... 50 more
24164:ERROR:(GridSphereFilter.java:doFilter:70)
< GridSphere initialization failed! >
After some fumbling around in the dark and trying random things, I got it to work, using both filters. (the old servlet filter only to initialize HibernateUtil's SessionFactory, and the new portlet filter to open the session during processing, and close it after rendering). However, it feels wrong to leave behind a servlet filter in a large program, especially one that accomplishes a small and unexplained task.
I was wondering if someone knows why it didn't work and/or why this magically works now? I have a feeling it has to do with classloaders...
here is the relevant code:
HibernateInitializerFilter - the old and slimmed-down servlet filter
Code:
public class HibernateInitializerFilter implements Filter {
private static Log log = LogFactory.getLog(HibernateInitializerFilter.class);
public void doFilter(ServletRequest request,
ServletResponse response,
FilterChain chain)
throws IOException, ServletException {
chain.doFilter(request, response);
}
public void init(FilterConfig filterConfig) throws ServletException {
log.debug("Initializing filter...");
log.debug("Obtaining SessionFactory from static HibernateUtil singleton");
HibernateUtil.getSessionFactory();
}
public void destroy() {}
}
(note that this is very similar to the HibernateSessionRequestFilter from
http://www.hibernate.org/43.html#A3, except that the doFilter method doesn't do anything.)
HibernatePortletFilter - the new apache portlet filter
Code:
public class HibernatePortletFilter implements PortletFilter {
private static Log log = LogFactory.getLog(HibernatePortletFilter.class);
private SessionFactory sf;
public void destroy() {}
public void init(PortletFilterConfig arg0) throws PortletException {
System.out.println("Initializing filter...");
log.debug("Initializing filter...");
log.debug("Obtaining SessionFactory from static HibernateUtil singleton");
sf = HibernateUtil.getSessionFactory();
}
public void processActionFilter(ActionRequest request, ActionResponse response,
PortletFilterChain chain) throws PortletException, IOException {
try {
log.debug("Starting a database transaction");
System.out.println("Starting a database transaction");
sf.getCurrentSession().beginTransaction();
// Call the next filter (continue request processing)
chain.processActionFilter(request, response);
} 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 PortletException(ex);
}
}
public void renderFilter(RenderRequest request, RenderResponse response,
PortletFilterChain chain) throws PortletException, IOException {
// begin transaction if no transaction is active
log.debug("Starting a database transaction");
System.out.println("Starting a database transaction");
if ( !sf.getCurrentSession().getTransaction().isActive() )
sf.getCurrentSession().beginTransaction();
chain.renderFilter(request, response);
// Commit and cleanup
log.debug("Committing the database transaction");
System.out.println("Committing the database transaction");
}
}
(also very similar to the HibernateSessionRequestFilter, except molded to extend
apache portal portlet filter's PortletFilter interface)
excerpt from
web.xml:
Code:
<filter>
<filter-name>HibernateFilter</filter-name>
<filter-class>edu.umn.msi.vlabPortlets.HibernateInitializerFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HibernateFilter</filter-name>
<servlet-name>PortletServlet</servlet-name>
</filter-mapping>
excerpt from
portlet.xml:
Code:
<portlet>
<description xml:lang="en">A portlet for managing the pseudo-potential repository</description>
<portlet-name>PseudoAdminPortlet</portlet-name>
<display-name xml:lang="en">Pseudo-Repository Administration</display-name>
<portlet-class>org.apache.portals.bridges.portletfilter.FilterPortlet</portlet-class>
<init-param>
<name>portlet-class</name>
<value>edu.umn.msi.vlabPortlets.portlets.PseudoAdminPortlet</value>
</init-param>
<init-param>
<name>portlet-filters</name>
<value>edu.umn.msi.vlabPortlets.HibernatePortletFilter</value>
</init-param>
<expiration-cache>0</expiration-cache>
<supports><mime-type>text/html</mime-type></supports>
<supported-locale>en</supported-locale>
<portlet-info>
<title>Manage Pseudo-Potential Repository</title>
<short-title>Pseudo-Repository Administration</short-title>
<keywords>Manage Pseudo-Potential Repository</keywords>
</portlet-info>
</portlet>
My deepest thanks!!
-- Dan