ZK Developer's Guide

By Jurgen Schumacher , Markus Stäuble
  • Instant online access to over 7,500+ books and videos
  • Constantly updated with 100+ new titles each month
  • Breadth and depth in over 1,000+ technologies

About this book


Publication date:
March 2008
Publisher
Packt
Pages
184
ISBN
9781847192004

 

Chapter 1. Getting Started with ZK

The world of web application development grows and grows. We can read many articles and books that explain how to develop a web application. Nearly every week a new framework emerges in the sphere of development. However, each new technology and framework means that we have to learn it. Without learning, it's not possible to leverage the complete power of the chosen technique. There are some reasons for the emergence of such a wide range of possibilities for developing a web application. The evolution of technology is one reason, and another is the demand for a faster and more efficient way to develop a web application. Each developer has his or her own preference for the way of development. However, not only issues in development demand new ways of building a web application. The big picture is about Web 2.0 and the underlying techniques AJAX (Asynchronous JavaScript and XML) also need new ways.

With ZK the developer gets a new alternative for solving the daily problems that occur in web projects and for building Web 2.0 applications. Through the chapters of this book, we show how to develop applications with ZK. After reading it and trying the framework there should be no need for more convincing.

Before we dive into the ZK framework it's important to clarify that this introductory chapter is not a replacement for the developers' guide from ZK (see http://www.zkoss.org/doc/ZK-devguide.pdf). The aim of this chapter is to give you an understanding of the basics and some important aspects of ZK, which are essential for daily development with the framework.

The following browsers are supported by ZK:

  • Internet Explorer 6+/7

  • Firefox 1+

  • Safari 2+

  • Mozilla 1+

  • Opera 9+

  • Camino 1+

Browsers without decent support for DOM and JavaScript are not supported. ZK is offered with a dual licensing model. On one side there is the GPL license, and on the other there is a commercial license with commercial support, which is offered from ZK (see http://www.zkoss.org/license/). Actually there are some IDEs that support the ZK framework. For example, there is ZeroKoder and the commercial zk-bench. These tools are presented in Chapter 7 of this book. To start programming with ZK you only need a basic knowledge of Java and XUL (XML User Interface Language). It's very easy to develop a front-end to a database. There are existing integrations of some OR-Mappers to ZK (e.g. for Hibernate). At present there are no external providers for controls. However, there is a defined interface (zk-forge) for creating controls.

The benefits of ZK are:

  • AJAX-based Rich User Interfaces

  • Event-driven Model

  • ZK User-interface Markup Language

  • Server-Centric Processing

  • Script in Java and EL Expressions

  • Modal Dialogs

  • Simple Thread Model

  • Live Data

  • GPL

The disadvantage of frameworks like JSF, or the Echo framework is lack of a good IDE support.

What is ZK?

If somebody asks about ZK, a good answer is: ZK is AJAX without JavaScript. That's an answer for some merchandising prospects. The technical answer to the question is that ZK is a component-based framework, which is driven through events.

There are three cornerstones:

  1. 1. An AJAX-based event-driven engine

  2. 2. A rich set of XUL and XHTML components

  3. 3. ZUML (ZK User Interface Markup Language)

Before we go on, we should get familiar with a few buzzwords, which we mentioned before.

XHTML

XHTML is the abbreviation of Extensible HyperText Markup Language. XHTML is very similar to HTML. Briefly, XHTML is HTML written in XML syntax. The following points are the most important differences:

  • The notation (uppercase/lowercase) of an element/attribute is important in XHTML (unlike of HTML).

  • Elements without content (e.g.<br>) must be closed in XHTML (e.g.<br />).

Example:

<?xml version="1.0" encoding="iso-8859-1" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="de" xml:lang="de">
<head>
<title>A XHTML example</title>
</head>
<body>
<h1>Testpage</h1>
<p>A paragraph</p>
<p>another<br />paragraph
</p>
</body>
</html>

XUL

XUL is the abbreviation for XML User Interface Markup Language. This "language" is not a new invention from the ZK team. It was originally defined by the Mozilla team. The project page of XUL is http://www.mozilla.org/projects/xul/. The intention of Mozilla is to have a platform-independent language to define user interfaces. And therefore, a ZK developer can benefit from the big community around XUL, and can use XUL widgets.

Example:

<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<window
id="findfile-window"
title="Find Files"
orient="horizontal"
xmlns="http://www.mozilla.org/keymaster/gatekeeper
/there.is.only.xul">
<button id="find-button" label="Find"/>
<button id="cancel-button" label="Cancel"/>
</window>

ZUML

ZUML is the abbreviation for ZK User Interface Markup Language. ZUML is based on XUL. There are some extensions to the XUL standard like the possibility of embedding program code.

<window title="Hello" border="normal">
Hello World!
</window>

For the user, the application feels like a desktop application. For the developer, the programming is like a standalone application. ZK uses an event-driven paradigm, which encapsulates the request-response paradigm from a web application. These technical infrastructure things are done through the framework. Therefore, no JavaScript usually needs to be written for the browser side. Here, it's important to say that the framework automatically includes some JavaScript libraries, and generates the JavaScript code for the user. Therefore, the developer has nothing to do with JavaScript.

Note

It's important to know that ZK does only things that should be done from a UI Framework. This means that we do not have a new framework that solves all development problems in the world. Only the UI layer is addressed. Therefore, things like persistence must be done with other frameworks. However, there are many possibilities for integrating other frameworks (e.g. Hibernate, http://www.hibernate.org) into ZK.

 

What is ZK?


If somebody asks about ZK, a good answer is: ZK is AJAX without JavaScript. That's an answer for some merchandising prospects. The technical answer to the question is that ZK is a component-based framework, which is driven through events.

There are three cornerstones:

  1. 1. An AJAX-based event-driven engine

  2. 2. A rich set of XUL and XHTML components

  3. 3. ZUML (ZK User Interface Markup Language)

Before we go on, we should get familiar with a few buzzwords, which we mentioned before.

XHTML

XHTML is the abbreviation of Extensible HyperText Markup Language. XHTML is very similar to HTML. Briefly, XHTML is HTML written in XML syntax. The following points are the most important differences:

  • The notation (uppercase/lowercase) of an element/attribute is important in XHTML (unlike of HTML).

  • Elements without content (e.g.<br>) must be closed in XHTML (e.g.<br />).

Example:

<?xml version="1.0" encoding="iso-8859-1" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="de" xml:lang="de">
<head>
<title>A XHTML example</title>
</head>
<body>
<h1>Testpage</h1>
<p>A paragraph</p>
<p>another<br />paragraph
</p>
</body>
</html>

XUL

XUL is the abbreviation for XML User Interface Markup Language. This "language" is not a new invention from the ZK team. It was originally defined by the Mozilla team. The project page of XUL is http://www.mozilla.org/projects/xul/. The intention of Mozilla is to have a platform-independent language to define user interfaces. And therefore, a ZK developer can benefit from the big community around XUL, and can use XUL widgets.

Example:

<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<window
id="findfile-window"
title="Find Files"
orient="horizontal"
xmlns="http://www.mozilla.org/keymaster/gatekeeper
/there.is.only.xul">
<button id="find-button" label="Find"/>
<button id="cancel-button" label="Cancel"/>
</window>

ZUML

ZUML is the abbreviation for ZK User Interface Markup Language. ZUML is based on XUL. There are some extensions to the XUL standard like the possibility of embedding program code.

<window title="Hello" border="normal">
Hello World!
</window>

For the user, the application feels like a desktop application. For the developer, the programming is like a standalone application. ZK uses an event-driven paradigm, which encapsulates the request-response paradigm from a web application. These technical infrastructure things are done through the framework. Therefore, no JavaScript usually needs to be written for the browser side. Here, it's important to say that the framework automatically includes some JavaScript libraries, and generates the JavaScript code for the user. Therefore, the developer has nothing to do with JavaScript.

Note

It's important to know that ZK does only things that should be done from a UI Framework. This means that we do not have a new framework that solves all development problems in the world. Only the UI layer is addressed. Therefore, things like persistence must be done with other frameworks. However, there are many possibilities for integrating other frameworks (e.g. Hibernate, http://www.hibernate.org) into ZK.

 

First Step: Say Hello to ZK


To get a feel of working with ZK, it's wise to do a small example. To follow the long tradition of many programming technologies, we will start with the traditional "Hello World" example.

Note

For the examples, we are using version 2.3.0 of the ZK framework.

The best way to start with ZK is to download the zkdemo application from the ZK team. The application can be downloaded from: http://www.zkoss.org/download/. The application comes in a ZIP archive. This archive contains four files:

  1. 1. zkdemo-all.war

  2. 2. zkdemo.war

  3. 3. zkdemos-all.ear

  4. 4. zkdemos.ear

The WAR files are for deploying inside a J2EE web container. The EAR files are for deploying inside a J2EE application server. To start, just throw the zkdemo.war inside the webapps directory of Tomcat. After this the application is available with the URL http://localhost:8080/zkdemo (if Tomcat runs at port 8080). Now create a new file with the name hello.zul, and copy this page to the decompressed application zkdemo. The page can be accessed with http://localhost:8080/zkdemo/hello.zul.

<window title="Hello" border="normal">
Hello World!
</window>

Note

The downloaded archive of the demo contains zkdemo.war, zkdemo-all.war, zkdemos-all.ear, and zkdemos.ear. The files without the suffix -all does not contain a complete application. The libraries from ZK are missing. For a first start you can copy the zkdemo-all.war to your Tomcat webapps directory. If you want to use the zkdemo.war please copy all libraries from your zk-2.3.0 (directory zk-2.3.0/dist/lib) into the expanded directory of the web application. Without a copy of the libraries you get an error while executing your application.

After this small example, we will make a second example with an input element inside. This application consists of one main screen. This screen has a label (Insert your name), an input field, and a hidden button (Say Hello). The following screenshot shows the screen.

The definition of this screen is done in a single file. Its name is helloworld.zul. Both the layout and logic is done in that page. The page is realized with the previously mentioned ZK User Interface Markup Language.

Now it's time to draw the curtain and show the implementation of this simple application as follows:

<?xml version="1.0" encoding="UTF-8"?>
<zk xmlns="http://www.zkoss.org/2005/zul">
<window title="My First window" border="normal" width="400px">
<label value="Insert your name:" />
<textbox width="60%" id="username">
<!-- implement an event listener for the even onChanging -->
<attribute name="onChanging"><![CDATA[
//The eventcode is pure Java and therefore we can use the
standard comment signs
//Caution: We can not use the ampersand for the if-clause
because we have to produce valid XML and
//the ampersand is the indicator of an entity in XML
/** Comments spanning
more than one line
are possible, too **/
if (event.getValue().length() > 0 && event.getValue().trim()
.length() > 0)
{
buttonToSayHello.setVisible(true);
}
else
{
buttonToSayHello.setVisible(false);
}
]]>
</attribute>
</textbox>
<!-- The alert is not a javascript alert, it’s a global function -->
<button id="buttonToSayHello" label="Say Hello" visible="false">
<attribute name="onClick"><![
CDATA[
alert('Hello '+username.value);
]]>
</attribute>
</button>
</window>
</zk>

It was mentioned before that the page contains one hidden button (Say Hello). This button has the buttonToSayHello id. The idea behind this is that the button is only shown if there is some input in the textbox with the username id. After the input of some content (at least one character that is not a white space character) the output looks like the following screenshot.

One way to define this "event listener" is to define the onChanging attribute for the textbox username. The implementation of the event is done in Java.

Note

Each main element should have an id attribute. With the id of an element it's easy to access such an element. In the example, we set the button visible with buttonToSayHello.setVisible(true).

If we click on the Say Hello button a window with a message is opened (see the following screenshot).

To show this messagebox the onClick attribute of the button is defined as alert(&quot;Hello &quot;+username.value). We used the globally defined method alert to show the message. The parameter for the method is a text string. We first have a constant Hello text, and then the value of the username (username.value) textbox.

Note

Always in development, it's important to remember that a ZUL file is just an XML file. Also if we want to use Java in that file, we have to keep in mind that some characters could conflict with XML. Therefore, we have to use the XML entities for special characters. In the example, we used&quot; for' and&amp; for the& sign.

It's notable that the alert method is not JavaScript, it's Java. The code within a ZUL page is interpreted inside the BeanShell interpreter (http://www.beanshell.org). To use JavaScript for the onClick event handler we have to explicitly prefix the command with javascript:. The difference between a JSP and ZUL page is that the code inside a ZK page is run inside the BeanShell, whereas a JSP is compiled to a Java class.

The ZK framework itself runs in a JEE (Java Enterprise Edition) Web container. And to fulfill the requirements to run into such a container, we have to do (unfortunately) more than just creating such a page. The succeeding screenshot shows the project layout for the sample project.

One part of the project is the ZK framework itself (which can be downloaded under http://www.zkoss.org). Here, we have to copy the libraries, tld and xsd files to our project. The following libraries (inside the lib directory) are necessary to run the application:

The last artifact that we have to create is the deployment descriptor for the web application, web.xml. The descriptor for the demo application is depicted below. The .zul files are interpreted by a servlet defined inside the zk.jar. The ZK framework also provides session management. Therefore, a predefined web.xml file is provided.

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<description><![
CDATA[ZK Demo]]></description>
<display-name>zk-hello</display-name>
<!--
<icon>
<small-icon></small-icon>
<large-icon></large-icon>
</icon>
-->
<!-- //// -->
<!-- ZK -->
<listener>
<description>
Used to cleanup when a session is destroyed
</description>
<display-name>ZK Session Cleaner</display-name>
<listener-class>
org.zkoss.zk.ui.http.HttpSessionListener
</listener-class>
</listener>
<servlet>
<description>ZK loader for ZUML pages</description>
<servlet-name>zkLoader</servlet-name>
<servlet-class>
org.zkoss.zk.ui.http.DHtmlLayoutServlet
</servlet-class>
<!-- Required. Specifies URI of the update engine
(DHtmlUpdateServlet).It must be the same as <url-pattern>
for the update engine.-->
<init-param>
<param-name>update-uri</param-name>
<param-value>/zkau</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>zkLoader</servlet-name>
<url-pattern>*.zul</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>zkLoader</servlet-name>
<url-pattern>*.zhtml</url-pattern>
</servlet-mapping>
<!-- Optional. Uncomment it if you want to use richlets.-->
<servlet-mapping>
<servlet-name>zkLoader</servlet-name>
<url-pattern>/zk/*</url-pattern>
</servlet-mapping>
<servlet>
<description>The asynchronous update engine for ZK</description>
<servlet-name>auEngine</servlet-name>
<servlet-class>
org.zkoss.zk.au.http.DHtmlUpdateServlet
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>auEngine</servlet-name>
<url-pattern>/zkau/*</url-pattern>
</servlet-mapping>
<!-- /////////// -->
<!-- Miscellaneous -->
<session-config>
<session-timeout>120</session-timeout>
</session-config>
<welcome-file-list>
<welcome-file>index.zul</welcome-file>
<welcome-file>index.zhtml</welcome-file>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
</welcome-file-list>
</web-app>

Now the application is ready to run in a JEE Web container, such as Apache Tomcat (http://tomcat.apache.org).

 

Inside ZK—How ZK Works


Before we start building a sample application, it's time to explain the internals of ZK. When building a simple application, or using a good tool, it is not important to understand its architecture. However, in case of an exception (Bad news: There are exceptions in programming with ZK, too.) it's better to know where you can look for the error.There are three components in the ZK architecture that can be identified as the main elements of the framework.

ZK Loader

This component is responsible for the loading and interpretation of a ZK page. The selection of the page is done based on the incoming URL Request from the client browser.

ZK Client Engine

This component sends "ZK Requests" to the server, and gets "ZK Responses" from the server. With these responses the DOM (Document Object Model) tree on the client side is updated. Therefore, we could call that the client part of the AJAX.

ZK AU (Asynchronous Update) Engine

The ZK AU Engine is the server part of the AJAX.

The following Insert figure gives a short overview to the architecture of ZK.

The sending of ZK Requests and ZK Responses, and the resulting updates constitute the mentioned event-driven programming model.

Note

One of the first things every Java programmer gets to know from his or her new programming heaven is that there is no need to care about memory, because the JVM (Java Virtual Machine) does the job for the developer. However, after that good message the next thing a Java programmer has to learn about is Garbage Collection. The ZK framework has no method for destroying a component. Since a page is detached from a page, the framework doesn't have any control over that component. After the detachment, the JVM takes care of the memory that was occupied by the component.

The Three Relatives—Desktop, Page, and Component

On the user side there are only HTML pages. In ZK these pages are build on desktops, pages, and components.

Component

Framework representation: org.zkoss.zk.ui.Component

A component is a UI object (for example: button, textbox, or label). The component besides being a Java object on the server has a visual representation in the browser. This is created at the moment of attachment to a page. At the moment of detachment the visual part is removed.

A component could have children. A component without any parent is called a root component.

Page

Framework representation: org.zkoss.zk.ui.Page

A page contains components. Therefore, a page is a container for components. If the ZK loader is interpreting a ZUML page, a org. zkoss.zk.ui.Page is created.

Note: A page can have multiple root components.

Desktop

Framework representation: org.zkoss.zk.ui.Desktop

It's possible for a ZUML page to include another ZUML page. This is because these pages are available under the same URL and they are grouped to a desktop. Therefore, a desktop is a container for the pages.

The following figure gives a small overview of how the three "relatives" belong together.

Identification in ZK

If we talk about identification in ZK, we have to handle three paradigms:

  • Identifiers

  • UUID

  • ID Space

At the moment of creation of a component the Identifier for the component is created (each one has an identifier). It's possible to change the identifier at any time. To set the identifier for a component you can use the id attribute.

<button label="test" id="theIdOfTheButton" />

It's not really necessary to set an id for the component. If no id is set from the developer, the framework generates a unique ID.

In addition to the mentioned identifier the, id of a component, each component has another identifier, the Universal Unique ID (UUID). This identifier is created automatically at the creation phase of a component.

Note

In most cases, an application developer has no contact with the UUID.

The identifier is used from the Client Engine to manipulate the Document Object Model at the client. For HTML components the id, and the UUID are the same. Therefore, if you change the id you change the UUID.

One attribute of an identifier should be that it is unique. If the project grows it's difficult to guarantee that an identifier is unique within the whole application. Therefore, in ZK we have the feature of ID Spaces. For example, an org.zkoss.zul.Window is an ID space. All identifiers in an ID Space must be unique instead of all identifiers in the whole application. Each component that implements the interface org.zkoss.zk.ui.IdSpace has its own ID Space. You could compare an ID Space with an XML Namespace.

For programmatic navigation inside and outside of the ID Spaces there is the helper class org.zkoss.zk.ui.Path.

A simple page hierarchy is shown in the figure below.

The class org.zkoss.zk.ui.Path offers two general possibilities to access a component. One is a static way, and the other is with an org.zkoss.zk.ui.Path instance.

The static way:

Path.getComponent("/5")

The way with an ork.zkoss.ui.Path instance:

new Path().getComponent("/1/2", "4")

Loading and Updating a ZK Page

The lifecycle of loading a ZK page consists of four phases. These phases are illustrated in the figure below.

Phase: Page Initial

In this phase, the page is initialized. To control this phase, it is possible to define a class or zscript for that phase.

Following is an example of defining a class for the init sequence:

<?init class="sample.InitSample" ?>

In the above example, the InitSample class from sample package is used. This class has to implement the org.zkoss.zk.util.util.Initiator interface.

The second way is to define a zscript for the init sequence:

<?init zscript="/init/init-sample.zs" ?>

Note

Note: It's not necessary to define an init sequence.

Note

Why to use an absolute class name in init?

In the description of the "Page Initial" phase the possibilities for the definition of the init sequence are shown. The use of org.zkoss.zk.util.util.Initiator interface to implement it is a good way. In most cases, the implementation class is placed in some package. To use the class you have to use the absolute name of the class.

<?init class="sample.InitSample" ?>

The reason for this is explained through the lifecycle. If you don't want to use an absolute class name in a Java program you have to import the class. In a ZUL file, you can do that with a zscript.

<zscript><![
CDATA[
import sample.InitSample;
]]>
</zscript>

However, if you now just use the name InitSample for the init sequence you will get a java.lang.ClassNotFoundException. To understand this, just add an output to the zscript.

<zscript><![
CDATA[
import sample.InitSample;
System.out.println(InitSample.class);
]]>
</zscript>

Note

Now we will implement doInit() and doAfterCompose().

package sample;
import org.zkoss.zk.ui.Page;
import org.zkoss.zk.ui.util.Initiator;
public class InitSample implements Initiator
{
public void doAfterCompose(Page page) throws Exception
{
System.out.println("doAfterCompose");
}
public void doInit(Page page, Object[] args) throws Exception
{
System.out.println("doInit");
}
public void doCatch(Throwable throwable)
{
}
public void doFinally()
{
}
}

The result is the following output:

doInit

class sample.InitSample

doAfterCompose

The init sequence is called before the zscript, and therefore, your import has no consequence for that sequence. Instead of writing an init class you can do the necessary actions in a ZUL file (init.zs).

Phase: Component Creation

In this phase, the ZK loader is responsible for the interpretation of the pages. The components of each page are created and initialized.

The following steps are performed in this phase:

Composing Phase

Step 1: Before the creation and initialization is started, the optional values of if and unless attributes are evaluated (<window if="expression" /> or<window unless="expression" />). With these attributes it's possible to control the layout depending on some conditions.

Step 2: The component is created. In the case of specification of the use attribute (<window use="MyClass" />) the specified class is used to create the component. Otherwise the component is created based on the name. After that the members are initialized.

Step 3: The nested elements are interpreted.

After the Composing Phase

Step 4: If the component implements the org.zkoss.zk.ui.ext.AfterCompose interface, afterCompose() is called.

Step 5: After the creation of all children the event onCreate is send to the created component.

Note

If we use the forEach attribute the steps are done for each element in the collection.

<zscript><![
CDATA[
elements = new String[] {"ZK", "AJAX", "FRAMEWORK"};
]]>
</zscript>
<listbox width="200px">
<listitem label="${each}" forEach="${elements}"/>
</listbox>

Phase: Event Processing

For each event that is queued, the event listeners are called in a thread. The processing of other events is not affected by the processing of code of a single event listener.

Phase: Rendering

The last stage is to compose from all components one single HTML page. For the rendering of a component redraw() is called.

The lifecycle of updating a ZK page consists of three phases. These phases are illustrated in the diagram below:

Note

It's worth mentioning that requests to the same desktop are processed sequentially, and requests to different desktops are processed in parallel. That's important if you are using frames, and each frame is a desktop.

Phase: Request Processing

The ZK Asynchronous Update Engine updates the appropriate components.

Phase: Event Processing

This is the same as the event processing on creation of a page.

Phase: Rendering

ZK renders the affected components. The Client Engine updates the DOM tree on the browser on the basis of the ZK responses.

Events in ZK—Listening and Processing

In the introduction to ZK with the "Hello World" example, we actually used a way to register an event listener. We directly defined it as an attribute of a component in the page:

<button id="buttonToSayHello" label="Say Hello" onClick="alert(&quot;Hello &quot;+username.value)" visible="false"/>.

The next way to define an event listener is in the component class. Here, we have the first use of the use attribute of an element. When using the use attribute, the given class should implement the base class of the control.

<window use="sample.ExampleComponent" />

Now we can implement the event. In the example below, we implement the event onOK. If the event contains necessary information for the processing it's possible to give the method an argument org.zkoss.zk.ui.event.KeyEvent. However, the implementation of the method is correct without the argument, too.

package sample;
import org.zkoss.zk.ui.event.KeyEvent;
import org.zkoss.zul.Window;
public class ExampleComponent extends Window
{
//It is possible to implement the method with an argument
public void onOK(final KeyEvent event)
{
}
}

The org.zkoss.zk.ui.Component interface offers two methods: addEventListener() and removeEventListener(). With these methods it's possible to add and remove event listeners dynamically. The event listener must be from type org.zkoss.zk.ui.event.EventListener.

package sample;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
public class SampleEventListener implements EventListener
{
public boolean isAsap()
{
return true;
}
public void onEvent(final Event event)
{
//here we process the necessary instructions
}
}

Now we can add this event listener in some initialization method.

public void init(final Component component)
{
component.addEventListener("onClick", new SampleEventListener());
}

Note

When should it be done?—ASAP

The interface org.zkoss.zk.ui.event.EventListener has a method isAsap with the return value boolean.

If the method returns true, the event will be sent to the server the moment the events occurs. However, if the method returns false, the event won't be sent to the server directly. It will be sent if another event occurs that has a positive isAsap. In case of performance problems there is a possibility to directly affect that point.

Another way to handle events is to add an event listener to org.zkoss.zk.ui.Page. The consequence is that all events that belong to component from the page are send to that registered listener, too.

What is the Priority?—The Order of Event Processing

An interesting point in the processing of events is the sequence in which the events are processed. For the explanation, we assume that the onSelect event is sent and received.

First Step: All event listeners for the onSelect event for the targeting component are invoked that implement the marker interface org.zkoss.zk.ui.event.Express.

Second Step: Now the script for the onSelect attribute for the target component is executed. It's notable that if we don't have an event listener that implements org.zkoss.zk.ui.event.Express then the event listener in the first attribute is executed.

Third Step: Now all event listeners of the targeting component that do not implement the mentioned org.zkoss.ui.event.Express interface are executed.

Fourth Step: If the targeting component has an onSelect method it will be executed.

Fifth Step: All event listeners for the onSelect event that are registered to the parent page of the target component are executed.

Note

The only way to change the order of execution is with the help of the org.zkoss.ui.event.Express interface. If we have to register multiple event listeners for the same event on the same component that implements that interface then the event listener that is added first is the first to execute its event code. This interface only has a consequence if the event listener is registered on a component not on a page.

Note

Mark up your classes

The org.zkoss.zk.ui.event.Express interface is a marker interface. The characteristic of such an interface is that it has an empty body. Such an interface is used only as a marker. It's useful to have such interfaces to emphasize that a class can have a special attribute.

The best known marker interface in the Java world is java.io.Serializable.

Note

How to send an event—Asynchronous or Synchronous ?

It's possible to send events with the help of the org.zkoss.zk.ui.event.Events class. There are two methods: postEvent (the asynchronous way) and sendEvent (the synchronous way). With the postEvent method the event is placed at the end of the event queue. The method returns immediately. With the usage of the sendEvent method it can be specified that the event should be executed immediately. The method returns after the specified event is executed.

How Can We Parallelize Event Listeners?

We mentioned before that requests to one desktop are done in a sequence. Therefore, if one event listener is processing its instructions then all other event listeners for that desktop are blocked. There is no problem if we only have short instructions, but in the case of long instructions we come across the problem that it's not acceptable to wait.

  • To suspend working threads we have to use the wait method in ork.zkoss.zk.ui.Executions.

  • We have to provide all necessary information to the working thread. This is because the working thread is not an event listener, and therefore, we have no direct access to the desktop.

  • To proceed with the working we have to use the notify or notifyAll method of org.zkoss.zk.ui.Executions.

  • To resume the event listener we use org.zkoss.zul.Timer.

For better illustration, we will provide a small example. First we have to implement a thread, which will do the work asynchronously. This thread is an implementation of the java.lang.Thread.

package sample.thread;
public class SampleWorkingThread extends Thread
{
private static int counter;
private Desktop desktop;
private Label label;
//Mutex variable for synchronization
private final Object mutex = new Integer(0);
/** Called by thread.zul to create a label asynchronously.
* To create a label, it starts a thread, and waits for its
completion.
*/
public static final Label asyncCreate(final Desktop desktop) throws
InterruptedException
{
//Create a new instance of the working thread
final SampleWorkingThread worker = new
SampleWorkingThread(desktop);
synchronized (worker.mutex)
{
worker.start();
//Suspend the thread
Executions.wait(worker.mutex);
return worker.label;
}
}
/**
* Implementation of the standard run method from java.lang.Thread.
*/
public void run()
{
++this.counter;
this.label = new Label("Execute, counter : " + counter);
synchronized (this.mutex)
{
//Proceed working of threads which are suspend with mutex
Executions.notify(this.desktop, this.mutex);
}
}
/**
* Constructor.
*
* @param desktop The reference to the acutal desktop instance.
*/
public WorkingThread(final Desktop desktop)
{
this.desktop = desktop;
}
}

Now we have to provide a ZUL page that starts the thread.

<window id="main" title="A Sample for a working Thread">
<button label="Start the thread">
<attribute name="onClick">
timer.start();
Label label = sample.thread.SampleWorkingThread
.asyncCreate(desktop);
main.appendChild(label);
timer.stop()
</attribute>
</button>
<timer id="timer" running="false" delay="1000" repeats="true"/>
</window>

When the user clicks on the button Start the thread, the thread starts doing the work asynchronously.

Event Processing Thread—Initialize and Cleanup

One important thread in a ZK application is the event processing thread. In this thread an event listener is processed.

Sometimes there is a demand to initialize or clean up the thread. For this we have the org.zkoss.zk.ui.event.EventThreadInit-interface. This interface has the method init(Component, Event) which must be implemented (and the prepare method). To register the listener it's necessary to make an entry in WEB-INF/zk.xml.

<zk>
<listener>
<listener-class>sample.SampleEventThreadInit</listener-class>
</listener>
</zk>

For cleanup there is the org.zkoss.zk.ui.event.EventThreadCleanup interface. Here, we have to implement the cleanup(Component, Event, List)method; additionally we also have to implement the complete method. The last parameter for the method cleanup is a list of exceptions that occur before the method is executed. To register the listener it's necessary to make an entry in WEB-INF/zk.xml.

<zk>
<listener>
<listener-class>sample.SampleEventThreadCleanup</listener-class>
</listener>
</zk>

An example implementation of such a listener is shown in Appendix A.

Until now we have used ZUML, but we haven't really explained what ZUML is and how to use it. The next section should you give some idea about working with ZUML. Before we start, it's important to note that the next section is not a reference for ZUML, it's just a guide to help in the development of a ZUML page.

Event Types

The following event types exist in ZK:

  • Mouse Events (e.g. onClick)

  • Keystroke Events (e.g. onOK)

  • Input Events (e.g. onChange)

  • List and Tree Events (e.g. onSelect)

  • Slider and Scroll Events (e.g. onScroll)

  • Other Events (e.g. onZIndex)

It depends on the component whether an event is supported or not. It's noteworthy to say that an event is sent after the content of the component is updated.

ZUML - ZK User Interface Markup Language

The first thing a new ZK developer is confronted with is the ZUML (ZK User Interface Markup Language). It's noteworthy to say that this is not a new proprietary language; it's just an XML with namespace.

There are at least three namespaces that are important for working with ZK:

http://www.zkoss.org/2005/zul

The XUL component set

http://www.w3.org/1999/xhtml

The XHTML component set

http://www.zkoss.org/2005/zk

ZK-specific attributes

Inside a ZUML page, we can use for example: EL expressions, Java, JavaScript, Ruby, and Groovy.

Note

Where is the session?

In some situations it could be faster to place some zscripts into the page, and for that we may want to access the session or some other object (for example the page itself).

In such situations there are some implicit objects that can be accessed in the pages. The objects are: self, spaceOwner, page, desktop, session, componentScope, spaceScope, pageScope, desktopScope, sessionScope, applicationScope, requestScope, arg, each, forEachStatus, and event.

You can use these objects in a zscript block, or in an element (<button label="simple test" onClick="alert(self.label)" />).

If you need information about the current execution you could use the org.zkoss.zk.ui.Execution interface. If you are in a component use getDesktop().getExecution(). When you don't have any component reference use the static method, getCurrent() from the class org.zkoss.zk.ui.Executions. After this introduction to ZUML, we present some important points in ZUML.

Note

Are there some predefined Dialogs?

Each UI framework offers some predefined Dialogs, and ZK is no exception. We used the org.zkoss.zul.Messagebox in the "Hello World" example through the globally defined alert method.

Beyond the mentioned Messagebox, the next important predefined dialog is the org.zkoss.zul.Fileupload. With this dialog, it's possible to do an HTTP Upload.

Beyond the usage of the standard components such as window, textbox, and button it's possible to create components for a particular page. For that purpose there exists the component element.

With the style attribute of a component, it is possible to change the visual appearance of a component. You have the possibility to define the style each time.

For example:

<button label="Say Hello" style="border:2px red" />

However, if you want to use that button more than once, you can define a component.

For example:

<?component name="mybutton" extends="button" style="border:2px red"
label="Say Hello" ?>

Now you can use this component as follows:

<mybutton />
<mybutton label="My label" />

It's possible to override the definitions of the predefined components:

<?component name="button" extends="button" style="border:2px red"
label="Say Hello" ?>
<mybutton />
<mybutton label="My label" />

Molds

A mold is an attribute that is used to customize pages in ZK. The org.zkoss.zk.ui.Component interface has the setMold method. If there isn't a mold defined; the mold with the name default is used.

Some components come with more than the default mold. For example, groupbox (represented by the class org.zkoss.zul.Groupbox) has the default and 3d molds.

To use the default mold nothing special is necessary.

<groupbox open="true" width="250px">
<caption label="Title of the group box"></caption>
</groupbox>

To use the 3d mold we have to specify the mold attribute.

<groupbox mold="3d" open="true" width="250px">
<caption label="Title of the group box"></caption>
</groupbox>

ZK Attributes

Beyond the normal attributes of elements (for example: width) there are some special attributes, which are called ZK Attributes.

use

With this attribute you can specify another class for the rendering of a concrete element instead of the default element..

Example:

<window use="sample.SampleWindow" />

if

The element is rendered only if the condition is true.

Example:

<textbox if="${b==1}" />

unless

The element is rendered only if the condition is false

Example:

<textbox unless="${c==1}" />

forEach

This attribute is used in conjunction with collections. For each element in the collection, the element is rendered with the concrete value.

Example:

<listitem label="${each}" forEach="${elements}" />

forEachBegin

This is used in conjunction with the forEach attribute. Here, you could specify the index of the first element of the collection that should be used for forEach

Example:

<listitem label="${each}" forEach="${elements}"
forEachBegin="1" />

forEachEnd

This is used in conjunction with the forEach attribute. Here, you could specify the index of the last element of the collection that should be used for forEach.

Example:

<listitem label="${each}" forEach="${elements}"
forEachEnd="1" />

ZK Elements

There are special elements that aren't responsible for creating components, the so called ZK Elements. The task of these elements is to control a ZUML page.

The following is a list of ZK Elements:

  • Element: zk,<zk>...</zk>

  • Element: zscript,<zscript>...</zscript>

  • Element: attribute,<attribute />

  • Element: custom-attributes,<custom-attributes />

The zk element is an element for grouping other components. Important at this juncture is that the zk element gets no member in the component tree.

Sample:

<window>
<zk>
<button id="buttonToSayHello" label="Say Hello" />
<button id="buttonToSayHelloAgain" label="Say Hello Again" />
</zk>
</window>

For layout and component tree, it's same as having no zk element.

A good question could be why to use the zk element. One important reason is that in a XML document there can be only one root element. And therefore, if we want to have more root elements (for example, more than one window) then we can use a zk element as root.

Another area of application is the possibility of iterating over components, or conditional evaluation. For that zk elements supports the following attributes:

  • forEach

  • if

  • unless

A small example of usage is as follows:

<window>
<zk forEach="${element}">
<label value="${element.name}" />
<button id="buttonToSayHello" label="Say Hello"
if="${element.showSayHello}" />
<button id="buttonNotToSayHello" label="Say not Hello"
unless="${element.showSayHello}" />
</zk>
</window>

The zscript element is used for embedding Java code into ZUML pages. At the time of page evaluation the code will be interpreted by the BeanShell (http://www.beanshell.org). It's possible to embed Java code directly between the opening and closing zscript tags. Another way is to use the src attribute of the zscript element. In this attribute, you could specify a URI to a file, which contains the Java code. The zscript element supports conditional evaluation with the help of the if and unless attributes.

Note

Beyond zscript you could use EL (Expression Language) Expressions in your ZK pages.

The attribute element defines an attribute of the enclosing element. We have used this ZK Element in the "Hello World" example.

<textbox width="60%" id="username">
<attribute name="onChanging">
...
</attribute>
</textbox>

One area of application is event listeners. The attribute element supports conditional evaluation with if and unless, too.

The custom-attributes element is used to define an object in a special scope (for example, page scope).

An example for defining a custom-attributes element is as follows:

<window>
<custom-attributes test="simple" />
</window>

This is the same as:

<window>
<zscript>
self.setAttribute("test", "simple");
</zscript>
</window>

It's possible to use the scope attribute:

<window>
<custom-attributes test="simple" scope="desktop" />
</window>

This is the same as:

<window>
<zscript>
desktop.setAttribute("test", "simple");
</zscript>
</window>

The custom-attributes element supports conditional evaluation with if and unless, too.

Layout Techniques

If we talk about UI, we have to talk about the layout of the pages. There are some elements that help you in the layout of a ZK page.

Some important elements are:

  • vbox

  • hbox

  • box

  • grid (in conjunction with: columns, column, rows, and row)

An example for using div and vbox elements is as follows:

<div align="center" style="vertical-align:center">
<vbox>
<groupbox mold="3d" open="true" width="250px">
<caption label="testbox"></caption>
<radiogroup id="master">
<radio label="Apple"/>
<radio label="Orange"/>
<radio label="Banana"/>
</radiogroup>
</groupbox>
<groupbox mold="3d" open="true" width="250px">
<caption label="another testbox"></caption>
<radiogroup id="client">
<radio label="Apple"/>
<radio label="Orange"/>
<radio label="Banana"/>
</radiogroup>
</groupbox>
</vbox>
</div>

The following screenshot shows the layout.

Note

Prevent XHTML, where it is possible

There are some disadvantages in the usage of XHTML in ZK. We have only one identifier and not two (see the section Identification in ZK ). Therefore, the id attribute has to be unique for the same desktop. There is no invalid XML element because ZK uses org.zkoss.zhtml.Raw for constructing any unrecognized XML element. The elements are case insensitive, and have no mold support (the attribute is ignored). Therefore, in most cases it's better to port an XHTML page to a ZK page.

Instead of using the layout control it's possible to do the layout with a XHTML, and using Cascading Stylesheets (see Chapter 6: Creating Custom Components).

Separation of Concerns

One important paradigm in object-oriented programming is Separation of Concerns (SoC). This paradigm says that an application should be broken into distinct features that overlap in functionality as little as possible (see http://en.wikipedia.org/wiki/Separation_of_concerns).

For large applications, it's not advisable to do the layout, and the logic together in one page. For such applications, you should follow the programming principle of separation of concerns. This separation is not only for architecture, but also for better maintenance of your application. This is because if you have your logic directly in Java classes, you can leverage the full power of your IDE, e.g. you can have a good debugger, and you can easily write unit tests.

 

Configuration and Deployment


The configuration for the ZK framework is separated in two files: web.xml for servlet and mapping definition, and zk.xml, which gives the possibility of overriding the default ZK system settings. The following figure shows that there are some mandatory settings, and some optional additional settings. The configuration in web.xml is mandatory for correct working of the ZK framework.

Configuration of web.xml

The most important place to configure a web application is the web.xml file. Without correct settings nothing will work. In the next paragraphs, we will have a detailed look at the settings that are necessary for the ZK framework.

First we need the zkLoader servlet, which loads the ZUML pages when the web container receives a request for a page.

This servlet is named org.zkoss.zk.ui.http.DHtmlLayoutServlet. Since this is the first entry for the ZK framework it is really necessary to load this first. Use the parameter:

<load-on-startup>1</load-on-startup>

The servlet has two init parameters:

  • Update-uri

    This is a mandatory parameter. It specifies the URI the ZK AU engine is mapped to. The browser needs that URI to send the correct pattern of AJAX URL requests to the DHtmlLayoutServlet. For default, we use /zkau.

  • Log_level

    This is an optional parameter. It specifies the default log level for the org.zkoss package. Possible values are OFF, ERROR, DEBUG, INFO, and WARNING.

This servlet supports static XHTML pages natively.

The complete settings are as follows:

<servlet>
<description>ZK loader for ZUML pages</description>
<servlet-name>zkLoader</servlet-name>
<servlet-class>
org.zkoss.zk.ui.http.DHtmlLayoutServlet
</servlet-class>
<init-param>
<param-name>update-uri</param-name>
<param-value>/zkau</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>

The second important and mandatory servlet is org.zkoss.zk.au.http.DHtmlUpdateServlet. It handles AJAX requests asynchronously. The mapped URL pattern must be the same as for the update-uri parameter in the DHtmlLayoutServlet.

The last mandatory servlet is the ZK Session Cleaner. It is a listener and it cleans up the memory when a session is closed. The class is org.zkoss.zk.ui.http.HttpSessionListener.

The question is now what to do if any other technique like JSP or JSF should be integrated as well. ZK has a filter servlet, which post-process the output from other servlets processors.

The servlet class is org.zkoss.zk.ui.http.DHtmlLayoutFilter and has two optional parameters:

  • Extension

    This describes how to process the output. The default is html.

  • Charset

    This specifies the charset of the output. The default is UTF-8.

A sample part of web.xml looks as follows:

<listener>
<description>
Used to cleanup when a session is destroyed
</description>
<display-name>ZK Session Cleaner</display-name>
<listener-class>
org.zkoss.zk.ui.http.HttpSessionListener
</listener-class>
</listener>
<servlet>
<description>ZK loader for ZUML pages</description>
<servlet-name>zkLoader</servlet-name>
<servlet-class>
org.zkoss.zk.ui.http.DHtmlLayoutServlet
</servlet-class>
<init-param>
<param-name>update-uri</param-name>
<param-value>/zkau</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>zkLoader</servlet-name>
<url-pattern>*.zul</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>zkLoader</servlet-name>
<url-pattern>*.zhtml</url-pattern>
</servlet-mapping>
<servlet>
<description>The asynchronous update engine for ZK</description>
<servlet-name>auEngine</servlet-name>
<servlet-class>
org.zkoss.zk.au.http.DHtmlUpdateServlet
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>auEngine</servlet-name>
<url-pattern>/zkau/*</url-pattern>
</servlet-mapping>

Configuration of zk.xml

The zk.xml file is an optional file, and stays in the WEB-INF/ folder on the same level as web.xml. As the above overview has shown, there are many settings, which already have default values. The purpose of the zk.xml file is to extend, or overwrite existing settings for ZK application. A list of these settings is given in the Appendix A.

Deployment

The deployment via Ant or any other IDE integrated tools is rather simple. Just copy the ZK distribution under WEB-INF/lib and that's it. If you wish to optimize the distribution you may omit the libraries you didn't use like dojoz or timeline.

Deployment of ZK Applications with Maven

If you like to work with Maven (http://maven.apache.org) it takes a little bit more effort. This is because of the rapid rate of releases in ZK; sometimes the Maven repositories have a bit of a delay in publishing. The most famous Maven repositories include the ZK framework, i.e. http://repo1.maven.org/maven2. The structure of the ZK framework in a Maven repository looks like:

As the illustration shows the ZK framework within the Maven repository has three different groupIDs:

  • org.zkoss.common

  • org.zkoss.zk

  • org.zkoss.zkforge

The artifacts zcommon and zweb are common. The second group contains the artifacts of the ZK framework itself, and the last contains the additional tools like FCKEZ. See the complete part of the POM.XML for the deployment of ZK in a Maven project:

<dependency>
<groupId>org.zkoss.common</groupId>
<artifactId>zcommon</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>org.zkoss.common</groupId>
<artifactId>zweb</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>org.zkoss.zk</groupId>
<artifactId>zk</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>org.zkoss.zk</groupId>
<artifactId>zul</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>org.zkoss.zk</groupId>
<artifactId>zhtml</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>org.zkoss.zk</groupId>
<artifactId>zkplus</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>org.zkoss.zkforge</groupId>
<artifactId>gmapsz</artifactId>
<version>2.0-2</version>
</dependency>
<dependency>
<groupId>org.zkoss.zkforge</groupId>
<artifactId>fckez</artifactId>
<version>2.3-2</version>
</dependency>
<dependency>
<groupId>org.zkoss.zkforge</groupId>
<artifactId>dojoz</artifactId>
<version>0.2.2-2</version>
</dependency>
 

Summary


In this chapter, we give an introduction into, and behind the ZK framework. The example illustrated in the section First Step - Say Hello to ZK gave us a feeling of how a simple ZK application is created. It's a good point to start your own small ZK projects or do some rapid prototyping with ZK.

The section "Inside ZK - How ZK works" is not really necessary if you just want to do small projects with ZK. However, if you think about major projects it's wise to know a little bit about what is inside ZK, and how ZK works.

The last section of this chapter, we show some important issues from the ZK User Interface Language (ZUML). Here, it's not possible to show you the complete ZUML. We just want to pick some points to show you how these important cornerstones are working.

However, now we have talked enough about inside ZK. In the following chapter, the main focus will be on using the ZK framework, and get "infected" by the ZK framework.

About the Authors

  • Jurgen Schumacher

    Hans-Jurgen Schumacher studied mathematics at the University of Karlsruhe, Germany. Since 17 years he is working as a Software Developer and Architect. Right now he is in the position of a Senior Architect for J2EE. One of his special fields are GUIs for web applications as well as Improvements in the Software Build process.

    Browse publications by this author
  • Markus Stäuble

    Markus Stäuble is currently working as CTO at namics (deutschland) gmbh. He has a Master degree in Computer Science. He started programming with Java in the year 1999. After that he has earned much experience in building enterprise java systems, especially web applications. He has a deep knowledge of the java platform and the tools and frameworks around Java.

    Browse publications by this author
Book Title
Access this book, plus 7,500 other titles for FREE
Access now