To fix this, a file called WEB-INF/zk.xml must be created with the following contents:
<zk><</zk>listener>
<
description>ThreadLocal Variables Synchronizer
</description>
<
listener-class>org.zkoss.zkplus.util.ThreadLocalListener
</listener-class>
</listener>
<preference>
<
name>ThreadLocal
</name>
<
value>
org.springframework.transaction.support.TransactionSynchronizationManager=resources,synchronizations,currentTransactionName,currentTransactionReadOnly,actualTransactionActive;
org.springframework.orm.hibernate3.SessionFactoryUtils=deferredCloseHolder;
org.springframework.transaction.interceptor.TransactionAspectSupport=transactionInfoHolder;<
/value>
</preference>
The problem is that the Spring OpenSessionInViewFilter opens a session, and binds it to the request's thread. However, ZK uses a multi-threaded event driven approach, so the actual processing happens in a new thread that gets kicked off by the ZK servlet - this breaks the connection to the open session. Adding the above listener copies the ThreadLocal variables with the session etc from the request thread's context into the event thread. As you can see, more prefs can be added to copy other objects from the ThreadLocal context.
I had to inspect a lot of code to fix this, turns out it was documented in great detail all along (but sort of all over the place):
- The 'old' way of fixing the issue, and only sufficient if you use Hibernate without Spring transactions: http://zkoss.org/javadoc/2.4.1/zkplus/org/zkoss/zkplus/hibernate/HibernateSessionContextListener.html
- The 'new' way of fixing it, but the example only shows how to emulate the above, so again not sufficient for Spring transactions: http://www.zkoss.org/smalltalks/zk2.4.1/zk2.4.1.dsp
- The javadoc with the 'new' way, surprisingly enough with exactly the example prefs I was looking for: http://java.sun.com/j2se/1.4.2/docs/api/java/lang/ThreadLocal.html
Another possible solution is to make the ZK servlet perform all processing within its own thread, this was a new feature in ZK 2.4. I haven't tried this though and it looks like this may be dangerous, since the thread will block the entire servlet if it blocks for any reason. To enable this, the following is required in the zk.xml:
<system-config>
<
disable-event-thread/>
<
/system-config>
3 comments:
Thanks Andre for this. I couldn't get Spring OSIV working with ZK until I ran across your blog!
For the sake of completeness, I include my snippet from web.xml:
<!-- Hibernate OpenSession Filter -->
<filter>
<filter-name>hibernateFilter</filter-name>
<filter-class>
org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
</filter-class>
<init-param>
<param-name>sessionFactoryBeanName</param-name>
<param-value>sessionFactoryHBE</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>hibernateFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Together with the ThreadLocalListener in zk.xml it does the trick!
I also tried the disable-event-thread configuration but it rendered our ZK application undeployable. I can hardly think that it could be helpful for anyone.
Can anyone send me your entire zk.xml and web.xml?
I really need to resolve this issue very soon.
Thanks,
Celso
Who knows where to download XRumer 5.0 Palladium?
Help, please. All recommend this program to effectively advertise on the Internet, this is the best program!
Post a Comment