Integrates ZK with Grails

Island Chen, Senior System Engineer, BEA China
November 12, 2007

Introduction

ZK is an event-driven, component-based framework to enable rich user interfaces for web application, with ZK plugin, you can develop your web application by using ZK as the view layer and grails as the service & domain(GROM) layer.

Install and Test the ZK plug-in

Install Grails first

Please follow this article

Create a simple Grails App

Please Follow the Grails Quikc Start, to build a simple Grails project with the Book domain class

Install ZK plugin

Download it grails-zkplugin-0.2.zip, the source code also included. Make sure you are in the root directory of your project, type


 grails install-plugin full_path_to_zk_plugin
 

Test the plug-in

Create a new file "list.zul" under "your_project\web-app" with the following content


<?xml version="1.0" encoding="UTF-8"?>
<?page zscriptLanguage="Groovy"?>

<window  border="normal" title="Groovy Test" id="MainWindow"  width="400px">
<zscript>
        books = Book.findAll()
</zscript>
<listbox>
        <listhead>
                <listheader label="ID"/>
                <listheader label="Title"/>
                <listheader label="Author"/>
        </listhead>
        <listitem forEach="${books}">
                <listcell label="${each.id}"/>
                <listcell label="${each.title}"/>
                <listcell label="${each.author}"/>
        </listitem>
</listbox>
</window>

then browse to "http://localhost:8080/your_project/list.zul", you should be able to view the following list.

How does ZK plugin do it?

Right now, ZK plugin is made up of three parts:

  1. maintaining the basic ZK realted java libaries
  2. Participating in web.xml Generation to add ZK related servlets
  3. Modifying sitemesh's configuration file, to exclude url patterns of ZK

With version 0.2, Grails controllers can work with ZK now!

Accessing the domain class

As you can see in the above sample, Grails domain classes can be accessed directly in ZK, just as what you can do in Grails controller.

Accessing the service

Accessing grails services in ZK is also very easy. Grails will define a bean with name "xxxService" of each service "XxxService", and you can access the Services in zscript directly with the help of DelegatingVariableResolver.

Create a service

Create a new file "HelloService.groovy" under "your_project\grails-app\services" with the following content


class HelloService {
   def serviceMethod(username) {
      return username+", welcome to ZK&Grails world!"
   }
}

Create a zul file

Create a new file "service.zul" under "your_project\web-app" with the following content


<?xml version="1.0" encoding="UTF-8"?>
<?variable-resolver class="org.zkoss.zkplus.spring.DelegatingVariableResolver"?>
<?page zscriptLanguage="Groovy"?>

<window  border="normal" title="Groovy Test" id="MainWindow"  width="400px">
    <textbox id="username"/>
    <button label="Call HelloService"
        onClick="result.value=helloService.serviceMethod(username.value)"/>
    <separator/>
    <label id="result"/>
</window>

Test it

Browse to "http://localhost:8080/your_project/service.zul", input a name and click the button!

Other things

Thanks to ZK & Grails, now writing a AJAX web-app is more easy!

Island Chen is Sr. system engineer of BEA China.

Copyright © Island Chen. This article is licensed under GNU Free Documentation License
Comments
 
Grails
2007-11-12

See also http://docs.codehaus.org/display/GRAILS/ZK+Plugin

cxvm
2007-11-14

kjhjkhkjhkj

Rosso
2007-12-11

list.zul doesn't work with Grails 1.0 RC3 ..... any hints ?

xiaocase
2007-12-13

in 1.0 rc3, you must add jstl-2.4.jar, standard-2.4.jar, hibernate-annotation.jar(option) to your project/grail-app/conf/config.groovy, at line 62 grails.war.dependencies. I've test and success.

Rosso
2007-12-14

Problem solved. I switched from JDK 1.6 back to JDK 1.5 and its working ;-)

robbiecheng
2007-12-18

Posted by danstadler on SF.NET

A little more information that might help:

1) I'm using Grails RC2, which I downloaded on november 8.

2) I'm using command-line and Eclipse 3.3 to manage this grails project.

3) Don't name your project starting with "grails-" - this can lead to strange
behavior (it was strange for me with "grails-zk-bookdemo", and I saw a bug on
this from someone else too:

http://www.nabble.com/Re%3A-Domain-class-not-found-p12522577.html


4) As of the version of RC2 I'm using, you can't run the .zul pages until you've
run enough of the Book controller that Book.get() is called at least once.
Viewing a book once or editing it should be enough to invoke Book.get(). This
bug is filed here:

http://jira.codehaus.org/browse/GRAILS-1672

They show it fixed now, but you can't get the latest RC2 at the moment; automated
builds are currently failing. If you want to check that out, go to

http://build.canoo.com/grails/


5) pushing a little bit beyond the basic demo: notice that in the .zul pages
in the plugin demo, there is the line <?page zscriptLanguage="Groovy"?>, whereas
the ZK developer guide (PDF from their website) does it more like this: <zscript
language="Groovy">. The second way didn't seem to work nicely at all for me,
but I haven't taken the time to really document this.

If I think of anything else, I'll post it. In general, the grails-zk plugin
demo, as described in the Grails plugin pages, works perfectly for me.


- dan

GoDeeper
2007-12-25

I had problem with this sample on 1.0-RC3 of grails. It complained:

org.codehaus.groovy.runtime.metaclass.MissingPropertyExceptionNoStack: No such property: Book for class: Script2

After some struggle, figured out:
Added the following line:

<?variable-resolver class="org.zkoss.zkplus.spring.DelegatingVariableResolver"?>

in list.zul. Things worked then.

Serge
2008-09-22

Can someone tell a link to working example of any groovy script with grails 1.0.3 and grails-zk-0.6 which uses any of the models for data binding .......

I have tried tree and combobox scripts from small talk but after i convert them to groovy components don't populate!

Chanwit
2008-10-27

Hi Serge,

I'm personally using BindingListModelList to wrap around a list returning from Grails (GORM query). Then use annotation to bind with UI elements and it's worked fine so far (however, sometime you need to fire custom events).

I'm trying to extract proper patterns from my going on project and will be posting them on ZKGrails wiki soon. Anyway, contribution is welcome, if you've got any best practice to share.

JDSC
2008-10-29

Thanks to GoDeeper's sollution, it worked. I think the instructions above should be updated.

Before adding the line:

<?variable-resolver class="org.zkoss.zkplus.spring.DelegatingVariableResolver"?>

to the list.zul file, I was getting the following error:

org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
Caused by: java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.

Anders
2009-12-22

GoDeeper,

Indeed, this line is required in the list.zul file

<?variable-resolver class="org.zkoss.zkplus.spring.DelegatingVariableResolver"?>


without it I also ran into this problem


2009-12-22 19:21:01,640 ERROR . - Servlet.service() for servlet zkLoader threw exception
groovy.lang.MissingPropertyException: No such property: Book for class: Script2
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:49)
at org.codehaus.groovy.runtime.callsite.PogoGetPropertySite.getProperty(PogoGetPropertySite.java:49)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callGroovyObjectGetProperty(AbstractCallSite.java:241)
at Script2.run(Script2.groovy:15)
at groovy.lang.GroovyShell.evaluate(GroovyShell.java:561)
at groovy.lang.GroovyShell.evaluate(GroovyShell.java:536)
at org.zkoss.zkmax.scripting.groovy.GroovyInterpreter.exec(GroovyInterpreter.java:66)
at org.zkoss.zk.scripting.util.GenericInterpreter.interpret(GenericInterpreter.java:310)
at org.zkoss.zk.ui.impl.PageImpl.interpret(PageImpl.java:796)
at org.zkoss.zk.ui.impl.UiEngineImpl.execNonComponent(UiEngineImpl.java:753)
at org.zkoss.zk.ui.impl.UiEngineImpl.execCreate0(UiEngineImpl.java:553)
at org.zkoss.zk.ui.impl.UiEngineImpl.execCreate(UiEngineImpl.java:498)
at org.zkoss.zk.ui.impl.UiEngineImpl.execCreateChild0(UiEngineImpl.java:631)
at org.zkoss.zk.ui.impl.UiEngineImpl.execCreateChild(UiEngineImpl.java:587)
at org.zkoss.zk.ui.impl.UiEngineImpl.execCreate0(UiEngineImpl.java:531)
at org.zkoss.zk.ui.impl.UiEngineImpl.execCreate(UiEngineImpl.java:498)
at org.zkoss.zk.ui.impl.UiEngineImpl.execNewPage0(UiEngineImpl.java:378)
at org.zkoss.zk.ui.impl.UiEngineImpl.execNewPage(UiEngineImpl.java:299)
at org.zkoss.zk.ui.http.DHtmlLayoutServlet.process(DHtmlLayoutServlet.java:229)
at org.zkoss.zk.ui.http.DHtmlLayoutServlet.doGet(DHtmlLayoutServlet.java:165)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:707)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.codehaus.groovy.grails.web.mapping.filter.UrlMappingsFilter.processFilterChain(UrlMappingsFilter.java:282)
at org.codehaus.groovy.grails.web.mapping.filter.UrlMappingsFilter.doFilterInternal(UrlMappingsFilter.java:211)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.zkoss.zkgrails.ZKGrailsPageFilter.doFilter(ZKGrailsPageFilter.java:116)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.springframework.orm.hibernate3.support.OpenSessionInViewFilter.doFilterInternal(OpenSessionInViewFilter.java:198)
at org.codehaus.groovy.grails.orm.hibernate.support.GrailsOpenSessionInViewFilter.doFilterInternal(GrailsOpenSessionInViewFilter.java:64)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.codehaus.groovy.grails.web.servlet.filter.GrailsReloadServletFilter.doFilterInternal(GrailsReloadServletFilter.java:101)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.codehaus.groovy.grails.web.servlet.mvc.GrailsWebRequestFilter.doFilterInternal(GrailsWebRequestFilter.java:65)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.codehaus.groovy.grails.web.filters.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:66)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:237)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:167)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:849)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:454)
at java.lang.Thread.run(Thread.java:619)

 
 
Leave a Reply
 
Name (required)
Mail (will not be published) (required)
Website
(Case Insensitive)
Bold textItalic textUnderLine textSource CodeHorizontal rulerExternal Link
Post
Preview