Friday, July 27, 2007

ZK, EL and XML Escaping

If you've worked with ZK for a bit, you will know that it uses an EL style of expression to set values and perform actions anywhere in the page. Which means you should be able to do something like:

<radio label="Sale" onCheck="${priceLabel.value='fruit'}"/>

However, this is not correct, in fact EL expressions will not be evaluated at all for the above line. The correct way to do it is as follows:

<radio label="Sale" onCheck="priceLabel.value=&quot;fruit&quot;"/>

Why? The developers guide explains it: "you could use EL expressions in any part of ZUML pages, except the names of attributes,
elements and processing instructions"

As the above is a processing instruction, you need to drop the EL syntax, which is a little strange as the syntax remains the same and is apparently still processed by BeanShell. Oh well. As for the escaping, that's just well-formed XML.

Sunday, July 22, 2007

Transaction management with Spring / Hibernate + ZK

Normal Spring transaction management for Hibernate does not work out of the box with ZK. Actually to be exact the transaction management works fine, but the Hibernate session is not kept open after the transaction until the end of the request as it should when using OpenSessionInViewFilter. The end result is that you get LazyInitializationException when trying to access proxies, since the session is closed.

To fix this, a file called WEB-INF/zk.xml must be created with the following contents:
<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>
</zk>



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):


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>

Friday, July 20, 2007

Getting Maven to do ZK

I couldn't find the Maven dependecies for ZK on the zkoss site, so here is what I had to include in my pom.xml to get it working. Beanshell is pretty central to ZK so I'm not sure why it doesn't get pulled in with the base ZK dependency. The jhlabs dependency is needed for captchas, if you're going to need that. By the way I would post the actual XML except then I have to escape the tags which is painful.

org.zkoss.zk:zkplus:2.4.1
org.zkoss.common:zweb:2.4.1
org.zkoss.common:zcommon:2.4.1
org.zkoss.zkforge:fckez:2.3-3
org.zkoss.zk:zul:2.4.1
org.zkoss.zk:zhtml:2.4.1
org.zkoss.zkforge:timelinez:1.1_3
org.zkoss.zk:zk:2.4.1

com.jhlabs:filters:2.0.235
org.beanshell:bsh:2.0b4

ZK + Eclipse: XML schema validation / Content assist

To get Eclipse to use content assist with ZK, I had to declare the schema as follows. This took me a while to figure out for some reason. I use MyEclipse, by the way, so WTP should be similiar.

<window xmlns="http://www.zkoss.org/2005/zul" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.zkoss.org/2005/zul http://www.zkoss.org/2005/zul/zul.xsd">

</window>