The Developer's Guide

Version 3.0.7


Table of Contents

1. Introduction
Traditional Web Applications
Ad-hoc AJAX Applications
ZK: What It Is
ZK: What It Is Not
ZK: Limitations
2. Getting Started
Hello World!
Interactivity
The zscript Element
The Scripting Language
The Scripting Codes in a Separate File
The attribute Element
The EL Expressions
The id Attribute
The if and unless Attributes
The forEach Attribute
The use and apply Attribute
The use Attribute
The apply Attribute
Used with the forward Attribute
Implement Java Classes in zscript
Create Components Manually
Developing ZK Applications without ZUML
Define New Components for a Particular Page
3. The Basics
Architecture Overview
The Execution Flow
Components, Pages and Desktops
Components
Pages
Desktops
Forest of Trees of Components
Component: a Visual Part and a Java Object
Identifiers
UUID
The ID Space
Namespace and ID Space
Variable and Functions Defined in zscript
Events
Desktops and Event Processing
Desktops and the Creation of Components
ZUML and XML Namespaces
4. The Component Lifecycle
The Lifecycle of Loading Pages
The Page Initial Phase
The Component Creation Phase
The Event Processing Phase
The Rendering Phase
The Lifecycle of Updating Pages
The Request Processing Phase
The Event Processing Phase
The Rendering Phase
The Molds
Component Garbage Collection
5. Event Listening and Processing
Add Event Listeners by Markup Languages
Add and Remove Event Listeners by Program
Declare a Member
Add and Remove Event Listeners Dynamically
Deferrable Event Listeners
Add and Remove Event Listeners to Pages Dynamically
The Invocation Sequence
Abort the Invocation Sequence
Send, Post and Echo Events from an Event Listener
Post Events
Send Events
Echo Events
Thread Model
Suspend and Resume
Long Operations
Initialization and Cleanup of Event Processing Thread
Initialization Before Processing Each Event
Cleanup After Processed Each Event
6. The ZK User Interface Markup Language
XML
Elements Must Be Well-formed
Special Character Must Be Replaced
Attribute Values Must Be Specified and Quoted
Comments
Character Encoding
Namespace
Conditional Evaluation
Iterative Evaluation
The each Variable
The forEachStatus Variable
How to Use each and forEachStatus Variables in Event Listeners
Load on Demand
Load-on-Demand with the fulfill Attribute
Load-on-Demand with an Event Listener
Implicit Objects
List of Implicit Objects
Information about Request and Execution
Processing Instructions
The page Directive
The component Directive
The init Directive
The variable-resolver Directive
The import Directive
The link and meta Directives
ZK Attributes
The apply Attribute
The use Attribute
The if Attribute
The unless Attribute
The forEach Attribute
The forEachBegin Attribute
The forEachEnd Attribute
The fulfill Attribute
The forward Attribute
ZK Elements
The zk Element
The zscript Element
The attribute Element
The variables element
The custom-attributes element
Component Sets and XML Namespaces
Standard Namespaces
7. ZUML with the XUL Component Set
Basic Components
Label
Buttons
Radio and Radio Group
Image
Imagemap
Audio
Input Controls
Calendar
Progressmeter
Slider
Timer
Paging
Windows
Titles and Captions
The closable Property
The sizable Property
The Style Class (sclass)
The contentStyle Property
Borders
Overlapped, Popup, Modal, Highlighted and Embedded
The position Property
Common Dialogs
The Layout Components
A Nested borderlayout Component
The size and border Properties
The splittable and collapsible Properties
The flex property
The open Property
The onOpen Event
The Box Model
The spacing Property
The widths and heights Properties
Splitters
Tab Boxes
Nested Tab Boxes
The Accordion Tab Boxes
The orient Property
The align Property of Tabs
The closable Property
The disabled Property
Load-on-Demand for Tab Panels
Grids
Scrollable Grid
Sizable Columns
Grids with Paging
Sorting
Live Data
Auxiliary Headers
Special Properties
More Layout Components
Separators and Spaces
Group boxes
Toolbars
Menu bars
Execute a Menu Command
Use Menu Items as Check Boxes
The autodrop Property
The onOpen Event
More Menu Features
Context Menus
Customizable Tooltip and Popup Menus
The onOpen Event
List Boxes
Multi-Column List Boxes
Column Headers
Column Footers
Drop-Down List
Multiple Selection
Scrollable List Boxes
Sizable List Headers
List Boxes with Paging
Sorting
Special Properties
Live Data
List Boxes Contain Buttons
Tree Controls
The open Property and the onOpen Event
Multiple Selection
Paging
Special Properties
Create-on-Open for Tree Controls
Comboboxes
The autodrop Property
The description Property
The onOpen Event
The onChanging Event
Bandboxes
The closeDropdown Method
The autodrop Property
The onOpen Event
The onChanging Event
Chart
Live Data
Drill Down (The onClick Event)
Manipulate Areas
Drag and Drop
The draggable and droppable Properties
The onDrop Event
Dragging with Multiple Selections
Multiple Types of Draggable Components
Work with HTML Tags
The html Component
The Native Namespace, http://www.zkoss.org/2005/zk/native
The XHTML Namespace, http://www.w3.org/1999/xhtml
The include Component
The style Component
The script Component
The iframe Component
Work with HTML FORM and Java Servlets
The name Property
Components that Support the name Property
Rich User Interfaces
Client Side Actions
Reference to a Component
The onshow and onhide Actions
CSA JavaScript Utilities
Events
Mouse Events
Keystroke Events
Input Events
List and Tree Events
Slider and Scroll Events
Other Events
8. ZUML with the XHTML Component Set
The Goal
A XHTML Page Is A Valid ZUML Page
Server-Centric Interactivity
Servlets Work As Usual
The Differences
A Component Created for Each Tag
UUID Is ID
All Tags Are Valid
Case Insensitive
No Mold Support
The DOM Tree at the Browser
The TABLE and TBODY Tags
Events
Integrate with JSF, JSP and Others
Work with Existent Servlets
Enrich by Inclusion
Enrich Static HTML Pages
Use of ZK JSP Tags
Use of ZK JSF Components
Enrich a Dynamically Generated Page with ZK Filter
9. Macro Components
Three Steps to Use Macro Components
Step 1. The Implementation
Step 2. The Declaration
Step 3. The Use
Inline Macros
An Example
Regular Macros
Macro Components and The ID Space
Provide Additional Methods
10. Advanced Features
Identify Pages
Identify Components
The Component Path
Sorting
Browser's Information and Controls
The onClientInfo Event
The org.zkoss.ui.util.Clients Class
Prevent User From Closing a Window
Browser's History Management
Add the Appropriate States to Browser's History
Listen to the onBookmarkChanged Event and Manipulate the Desktop Accordingly
A Simple Example
Component Cloning
Component Serialization
Serializable Sessions
Serialization Listeners
Inter-Page Communication
Post and Send Events
Attributes
Inter-Web-Application Communication
Web Resources from Classpath
Annotations
Annotate ZUML Pages
Annotate Components Created Manually
Retrieve Annotations
Richlets
Implement the org.zkoss.zk.ui.Richlet interface
Configure web.xml and zk.xml
Session Timeout Management
Error Handling
Error Handling When Loading Pages
Error Handing When Updating Pages
Miscellaneous
Configure the ZK Loader Not to Compress the Output
11. Performance Tips
Use Compiled Java Codes
Use the deferred Attribute
The deferred Attribute and the onCreate Event
Use the forward Attribute
Use the Servlet Thread to Process Events
Modal Windows
Message Boxes
File Upload
Use the Native Namespace instead of the XHTML Namespace
Prolong the Period to Check Whether a File Is Modified
Defer the Creation of Child Components
Use Live Data and Paging for Large List Boxes
Use ZK JSP Tags or ZK JSF Components instead of ZK Filter
12. Other Devices and Output Formats
ZK Mobile
The Mobile Component Set, http://www.zkoss.org/2007/mil
XML Output
Three Steps to Generate XML Output with a ZUML Page
The XML Component Set
13. Internationalization
Locale
The px_preferred_locale Session Attribute
The Request Interceptor
Time Zone
The px_preferred_time_zone Session Attribute
The Request Interceptor
Labels
Locale-Dependent Files
Browser and Locale-Dependent URI
Locating Browser and Locale Dependent Resources in Java
Messages
Themes
Use the Theme with Smaller Fonts
Use the Theme with Larger Fonts
Use the Theme that Depends on Locale
Use Your Own Theme
The Theme Provider
14. Database Connectivity
ZK Is Presentation-Tier Only
Simplest Way to Use JDBC (but not recommended)
Use with Connection Pooling
Connect and Close a Connection
Configure Connection Pooling
ZK Features Applicable to Database Access
The org.zkoss.zk.ui.event.EventThreadCleanup Interface
Access Database in EL Expressions
Transaction and org.zkoss.zk.util.Initiator
15. Portal Integration
Configuration
WEB-INF/portlet.xml
WEB-INF/web.xml
The Usage
The zk_page and zk_richlet Parameter and Attribute
Examples
16. Beyond ZK
Logger
How to Configure Log Levels with ZK
Content of i3-log.conf
Location of i3-log.conf
Disable All Logs
DSP
iDOM

SIMPLY RICH

ZKTM

August 2008

Potix Corporation

Revision 215

Copyright © Potix Corporation. All rights reserved.

The material in this document is for information only and is subject to change without notice. While reasonable efforts have been made to assure its accuracy, Potix Corporation assumes no liability resulting from errors or omissions in this document, or from the use of the information contained herein.

Potix Corporation may have patents, patent applications, copyright or other intellectual property rights covering the subject matter of this document. The furnishing of this document does not give you any license to these patents, copyrights or other intellectual property.

Potix Corporation reserves the right to make changes in the product design without reservation and without notification to its users.

The Potix logo and ZK are trademarks of Potix Corporation.

All other product names are trademarks, registered trademarks, or trade names of their respective owners.

1. Introduction

Welcome to ZK, the simplest way to make Rich Web Applications.

The Developer's Guide describes the concepts and features of ZK. For installation refer to the Quick Start Guide. For a full description of component properties and methods refer to the Developer's Reference.

This chapter describes the historical background of Web programming, AJAX technologies and the ZK project. You may skip this chapter if you prefer to familiarize yourself with the ZK features right away.

Traditional Web Applications

Aimed at simply and effectively exchanging documents Web technologies such as, HTTP and HTML are originated from the page-based stateless-communication model. In this model a page is self-contained and is a minimal unit that communicates between clients and servers.

Since the Web has emerged as the default platform for application development this model faces a substantial challenge: the inability to visually represent the complexities in today's applications. For example, to give a customer a quotation, you might have to open another page to search his trading records, another page for the recent prices, and another page for current stocking. Users are forced to leave the page they are working in, and navigate among several pages. It is easy to get lost and confused resulting in unhappy customers, lost sales and low productivities.

The challenge to develop a modern application upon this page-based model is also substantial. In this model, applications running at the server have to take care of everything: from parsing the request, rendering the response, routing processes that link users from one page to another, and handling versatile errors made by users. Many different frameworks such as: Struts, Tapestry and JSF have emerged to simplify this development process. Due to the huge gap between the page-based model and modern applications learning and using these frameworks is never a pleasant process, not to mention intuitive or simplistic.

Ad-hoc AJAX Applications

Over a decade of evolution, Web applications have evolved from static HTML pages to Dynamic HTML pages, from applets to Flash, and finally to AJAX[1] technologies (Asynchronous JavaScript and XML). Illustrated by Google Maps and Suggest, AJAX breaths new life into Web applications by delivering the same level of interactivity and responsiveness as desktop applications do. Unlike applets or Flash, AJAX is based on the standard browser and JavaScript with no proprietary plugins required.

AJAX is a kind of new generation DHTML. Like DHTML, it heavily relies on JavaScript to listen to events triggered by user's activity, and then manipulate visual presentation of a page (aka. DOM) in the browser dynamically. Moreover, it takes a step further by enabling communication with the server asynchronously without leaving or rendering the whole page again. It breaks the page-based model by introducing light-weight communication between clients and servers. With proper design AJAX could bring rich components, common to desktop applications, to life in Web applications allowing dynamic updates and more control over the application.

When providing the interactivity that users demand, AJAX adds more complexities and skill prerequisites to the already costly development of Web applications. Developers have to manipulate DOM in the browser and communicate with the server via incompatible and even buggy JavaScript APIs. For better interactivity developers have to replicate application data and business logic in the browser, increasing maintenance costs and the challenge of synchronizing data between the server and the client.

The bottom line is that ad hoc AJAX applications are no different from traditional Web applications in regards to the way processes are requested. Developers still have to fill the gap caused by the page-based and stateless model.

ZK: What It Is

ZK is an event-driven, component-based framework to enable rich user interfaces for Web applications. ZK includes an AJAX-based event-driven engine, a rich set of XUL and XHTML components and a markup language called ZUML (ZK User Interface Markup Language).

With ZK, you represent your application in feature-rich XUL and XHTML components and manipulate them upon events triggered by user's activity, similar to what is done in desktop applications. Unlike most of other AJAX frameworks, as far as ZK is concerned, AJAX is a behind-the-scene technology. The synchronization of component content and the pipelining of events are done automatically by the ZK engine.

Your users get the same engaging interactivity and responsiveness of the desktop application, while your development retains the simplicity of developing desktop applications.

In addition to a simple model and rich components ZK also supports a markup language called ZUML. ZUML, like XHTML, enables developers to design user interfaces without programming. With XML namespaces, ZUML seamlessly integrates different set of tags[2] into the same page. Currently ZUML supports two set of tags, XUL and HTML.

For fast prototyping and customization ZUML allows developers to embed EL expressions, and scripting codes in your favorite languages including but not limited to: Java[3], JavaScript[4], Ruby[5] and Groovy[6]. Developers could choose not to embed any scripting codes at all if they prefer a more rigid discipline. Unlike JavaScript embedded in HTML, ZK executes all embedded scripting code on the server.

It is interesting to note that everything running at the server is from the viewpoint of the application developers. Component developers have to balance the interactivity and simplicity by deciding what tasks will done at the browser and what tasks will be done at the server.

ZK: What It Is Not

ZK assumes nothing about persistence or inter-server communication. ZK is designed to be as thin as possible. It is only aimed at the presentation tier. It does not require or suggest any other back-end technologies. All of your favorite middleware technologies such as: JDBC, Hibernate, Java Mail, EJB or JMS work as they used to.

ZK doesn't provide a tunnel, RMI or other API for developers to communicate between clients and servers. This is because all code runs at the server within the same JVM.

ZK doesn't enforce developers to use MVC or other design patterns. Whether to use them is the developer's choice.

ZK is not a framework aiming to bring XUL to Web applications. It is aimed to bring the desktop programming model to Web applications. Currently, it supports XUL and XHTML, in future it might support XAML, XQuery and others.

ZK embeds AJAX in the current implementation but it doesn't end in where AJAX does. With ZK API for Mobile devices, your applications could reach any devices that support J2ME such as: PDA, mobiles and game consoles. Moreover, you don't need to modify your application at all[7].

ZK: Limitations

ZK is not for applications that run most of tasks at the clients, such as 3D action games.

Unless you write a special component, ZK is not for applications that want to leverage the computing power at the clients.



[1] AJAX is coined by Jesse James Garrett in Ajax: A New Approach to Web Applications.

[2] A tag is an XML element. When a ZUML page is interpreted, a corresponding component is created.

[3] The Java interpreter is based on BeanShell (http://www.beanshell.org).

[4] The JavaScript interpreter is based on Rhino (http://www.mozilla.org/rhino).

[5] The Ruby interpreter is based on JRuby (http://jruby.codehaus.org/).

[6] The Groovy interpreter is based on Groovy (http://groovy.codehaus.org/).

[7] For devices with small screen, you usually have to adjust the presentation pages.

2. Getting Started

This chapter describes how to write your first ZUML page. It is suggested to read at least this chapter, if you are in hurry.

This chapter uses XUL to illustrate ZK features, but it is usually applicable to other markup languages that ZK supports.

Hello World!

After ZK is installed into your favorite Web server[8], writing applications is straight forward. Just create a file, say hello.zul, as follows[9] under a proper directory.

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

Then, browse to the right URL, say http://localhost/myapp/hello.zul, and you got it.

In a ZUML page, a XML element describes what component to create. In this example, it is a window (org.zkoss.zul.Window). The XML attributes are used to assign values to properties of the window component. In this example, it creates a window with a title and border, which is done by setting the title and border properties to "Hello" and "normal", respectively.

The text enclosed in the XML elements is also interpreted as a special component called label (org.zkoss.zul.Label). Thus, the above example is equivalent to the following.

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

Also, it is equivalent to

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

Interactivity

Let us put some interactivity into it.

<window title="Hello" border="normal">
    <button label="Say Hello" onClick="alert(&quot;Hello World!&quot;)"/>    
</window>

Then, when you click the button, you see as follows.

The onClick attribute is a special attribute used to add an event listener to the component. The attribute value could be any legal Java codes. Notice that we use &quot; to denote the double quot (") to make it a legal XML document. If you are not familiar with XML, you might take a look at the XML section in the ZK User Interface Markup Language chapter.

The alert function is a global function to display a message dialog box. It is a shortcut to one of the show methods of the org.zkoss.zul.Messagebox class.

<button label="Say Hello" onClick="Messagebox.show(&quot;Hello World!&quot;)"/>

Notes:

  • The scripts embedded in ZUML pages can be written in different languages, including but not limited to Java, JavaScript, Ruby and Groovy. Moreover, they are running at the server.

  • ZK uses BeanShell to interpret Java at run time, so you could declare global functions, such as alert, for it. Similarly, almost all scripting language provides a simple way to define global functions, and, sometimes, classes.

  • All classes in the java.lang, java.util, org.zkoss.zk.ui, org.zkoss.zk.ui.event and org.zkoss.zul package are imported before evaluating the scripting codes embedded in ZUML pages.

The zscript Element

The zscript element is a special element to define the scripting codes that will be evaluated when a ZUML page is rendered. Typical use includes initialization and declaring global variables and methods.

Note: You cannot use EL expressions in zscript codes.

For example, the following example displays a different message each time the button is pressed.

<window title="Hello" border="normal">
    <button label="Say Hello" onClick="sayHello()"/>    
    <zscript>    
    int count = 0;    
    void sayHello() { //declare a global function    
        alert("Hello World! "+ ++count);        
    }    
    </zscript>    
</window>

Note: zscript is evaluated only once when the page is loaded. It is usually used to define methods and initial variables.

The Scripting Language

By default, the scripting language is assumed to be Java. However, you can select different language by specifying the language attribute as follows. The language attribute is case insensitive.

<zscript language="javascript">
    alert('Say Hi in JavaScript');    
    new Label("Hi, JavaScript!").setParent(win);    
</zscript>

To specify the scripting language for an event handler, you can prefix with, say, javascript: as follows. Notice: don't put whitespace before or after the language name.

<button onClick="javascript: do_something_in_js();"/>

You may have the script codes writing in different scripting languages in the same page.

The Scripting Codes in a Separate File

To separate codes and views, developers could put the scripting codes in a separated file, say sayHello.zs, and then use the src attribute to reference it.

<window title="Hello" border="normal">
    <button label="Say Hello" onClick="sayHello()"/>    
    <zscript src="sayHello.zs"/>    
</window>

which assumes the content of sayHello.zs is as follows.

int count = 0;
void sayHello() { //declare a global function
    alert("Hello World! "+ ++count);    
}

The attribute Element

The attribute element is a special element to define a XML attribute of the enclosing element. With proper use, it makes the page more readable. The following is equivalent to hello.zul described above.

<button label="Say Hello">
     <attribute name="onClick">alert("Hello World!");</attribute>    
</button>

You can control whether to omit the leading and trailing whitespaces of the attribute value by use of the trim attribute as follows. By default, no trim at all.

<button>
    <attribute name="label" trim="true">    
        The leading and trailing whitespaces will be omitted.        
    </attribute>    
</button>

The EL Expressions

Like JSP, you could use EL expressions in any part of ZUML pages, except the names of attributes, elements and processing instructions.

EL expressions use the syntax ${expr}. For example,

<element attr1=”${bean.property}”.../>
${map[entry]}
<another-element>${3+counter} is ${empty map}</another-element>

Tip: empty is an operator used to test whether a map, a collection, an array or a string is null or empty.

Tip: map[entry] is a way to access an element of a map. In other words, it is the same as map.get(entry) in Java.

When an EL expression is used as an attribute value, it could return any kind of objects as long as the component accepts it. For example, the following expression will be evaluated to a Boolean object.

<window if="${some > 10}">

Tip: The + operator in EL is arithmetic. It doesn't handle string catenations. If you want to catenate strings, simple use "${expr1} is added with ${expr2}".

Standard implicit objects, such as param and requestScope, and ZK implicit objects, such as self and page, are supported to simplify the use.

<textbox value="${param.who} does ${param.what}"/>

To import a method, you can use a processing instruction called the xel-method as follows.

<?xel-method prefix="c" name="forName"
    class="java.lang.Class"    
    signature="java.lang.Class forName(java.lang.String)"?>    
<textbox value="${c:forName('java.util.List')}"/>

To import EL functions from TLD files, you could use a processing instruction called taglib as follows.

<?taglib uri="http://www.zkoss.org/dsp/web/core" prefix="c" ?>

The Developer's Reference provides more details on EL expressions. Or, you might refer to JSP 2.0 tutorials or guides for more information about EL expressions.

The id Attribute

To access a component in Java codes and EL expressions, you could assign an identifier to it by use of the id attribute. In the following example, we set an identifier to a label such that we could manipulate its value when one of the buttons is pressed.

<window title="Vote" border="normal">
    Do you like ZK? <label id="label"/>    
    <separator/>    
    <button label="Yes" onClick="label.value = self.label"/>    
    <button label="No" onClick="label.value = self.label"/>    
</window>

After pressing the Yes button, you will see the following.

The following is any example for referencing a component in an EL expression.

<textbox id="source" value="ABC"/>
<label value="${source.value}"/>

The if and unless Attributes

The if and unless attributes are used to control whether to create a component. In the following examples, both labels are created only if the request has a parameter called vote.

<label value="Vote 1" if="${param.vote}"/>
<label value="Vote 2" unless="${!param.vote}"/>

If both attributes are specified, the component won't be created unless they are both evaluated to true.

The forEach Attribute

The forEach attribute is used to control how many components shall be created. If you specify a collection of objects to this attribute, ZK Loader will create a component for each item of the specified collection. For example, in the following ZUML page, the listitem element will evaluated three times (for "Monday", "Tuesday" and "Wednesday") and then generate three list items.

<zscript>contacts = new String[] {"Monday", "Tuesday", "Wednesday"};</zscript>
<listbox>
<listitem label="${each}" forEach="${contacts}"/>
</listbox>

When evaluating the element with the forEach attribute, the each variable is assigned one-by-one with objects from the collection, i.e., contacts in the previous example. Thus, the above ZUML page is the same as follows.

<listbox>
<listitem label="Monday"/>
<listitem label="Tuesday"/>
<listitem label="Wednesday"/>
</listbox>

Alternatively, you can specify a list of items in the forEach attribute by separating them with comma.

<listbox>
<listitem label="${each}" forEach="Monday, Tuesday, Wednesday"/>
</listbox>

In additions to forEach, you can control the iteration with forEachBegin and forEachEnd. Refer to the ZK Attributes section in the ZK User Interface Markup Language chapter for details.

The use and apply Attribute

Embedding codes improperly in pages might cause maintenance headache. There are several ways to separate codes from views.

First, you could listen to events you care, and then invoke the proper methods accordingly. For example, you could invoke your methods to initialize, process and cancel upon the onCreate[10], onOK[11] and onCancel[12] events.

<window onCreate="MyManager.init(main)"onOK="MyManager.process(main)" onCancel="MyManager.cancel(main)"/>

In addition, you must have a Java class called MyManager shown as follows.

import org.zkoss.zul.Window;

public class MyManager {
    public static void init(Window main) { //does initialization    
    }    
    public static void save(Window main) { //saves the result    
    }    
    public static void cancel(Window main) { //cancel any changes    
    }    
}

However, the above approach requires you to embed some codes in the ZUML pages. The advantage of embedding codes in UI is easy to change the behavior dynamically (particularly in the prototype phase), but it still reveals some maintenance codes and the performance is bit slower[13].

The use Attribute

If you prefer not to use any Java codes in the ZUML pages, you can extend the implementation of a component to handle the events as follows.

import org.zkoss.zul.Window;

public class MyWindow extends Window {
    public void onCreate() { //does initialization    
    }    
    public void onOK() { //save the result    
    }    
    public void onCancel() { //cancel any changes    
    }    
}

Then, specify the class with the use attribute as shown below.

<window use="MyWindow">
    ...    
</window>

The apply Attribute

If you prefer the MVC (Model-View-Controller) approach, i.e., you prefer not to embed the handling codes in the window (the view), you can implement a class to initialize the window. The class must implement the org.zkoss.zk.ui.util.Composer interface.

import org.zkoss.zk.ui.util.Composer;
import org.zkoss.zul.Window;
public class MyComposer implements Composer {
    public void doAfterCompose(Component comp) {    
        ((Window)comp).setTitle("My Title"); //do whatever initialization you want        
            //comp is Window since we will specify it to a window later            
    }    
}

where assumes you have three event listeners, MyCreate, MyOK, and MyCancel. Refer to the Event section below for the explanation of event listeners.

Then, specify the class with the apply attribute as shown below.

<window apply="MyComposer">
...
</window>

The window is still created as an instance of org.zkoss.zul.Window, and it will be passed to the doAfterCompose method as the comp argument. Then, you can do any initialization you want.

If you want to apply multiple composers, separate them with comma. In addition, you can use an EL expression to return the class, its name, an instance of Composer, or a collection of Composer instances.

<window apply="MyComposer, AnotherComposer">
    <textbox apply="${c:mycomposer()}"/>    
</window>

Used with the forward Attribute

A window usually consists of several buttons, menu items and other controls. For example,

<window use="MyWindow">
    ...    
    <button label="OK"/>    
    <button label="Cancel"/>    
</window>

When the user clicks the button, the onClick event is sent to the button itself. However, these events are better to process in the window rather than scattering around these buttons. To do that, you can use the forward attribute as follows.

<window use="MyWindow">
    ...    
    <button label="OK" forward="onOK"/>    
    <button label="Cancel" forward="onCancel"/>    
</window>

where the forward attribute of the OK button specifies that the onClick event, if received, shall be forwarded to the space owner (i.e., the window) as the onOK event. Similarly, the onClick event targeting the Cancel button is forwarded as the onCancel event. Thus, you can handle the onOK and onCancel events in the space owner, MyWindow, as follows.

public class MyWindow extends Window {
    public void onOK() {    
        //called when the OK button is clicked (or the ENTER button is pressed)        
    }    
    public void onCancel() {    
        //called when the Cancel button is clicked (or the ESC button is pressed)        
    }    
}

In addition to forward the onClick event to the space owner, you can forward any event to any component with the forward attribute. Refer to the forward Attribute section in the ZK User Interface Markup Language chapter for more details.

Implement Java Classes in zscript

Thanks to the power of BeanShell[14], the implementation of Java classes can be done in zscript as follows.

<zscript>
    public class MyWindow extends Window {    
    }    
</zscript>
<window use="MyWindow"/>

Tip: Many scripting languages, e.g., JRuby, also allow developers to define classes that are accessible by JVM. Please consult the corresponding manuals for details.

To separate codes from the view, you can put all zscript codes in a separated file, say mywnd.zs, and then,

<zscript src="/zs/mywnd.zs"/>
<window use="MyWindow"/>

Tip: You can use the init directive to specify a zscript file, too. The difference is the init directive is evaluated before any component is created (in the Page Initial phase). For more information, refer to the init Directive section in the ZK User Interface Markup Language chapter.

Create Components Manually

In addition to describe what components to create in ZUML pages, developers could create them manually. All component classes are concrete. You create them directly[15] with their constructors.

<window id="main">
    <button label="Add Item">    
        <attribute name="onClick">        
    new Label("Added at "+new Date()).setParent(main);    
    new Separator().setParent(main);    
        </attribute>        
    </button>    
    <separator bar="true"/>    
</window>

When a component is created manually, it won't be added to any page automatically. In other words, it doesn't appear at user's browser. To add it to a page, you could invoke the setParent, appendChild or insertBefore method to assign a parent to it, and it becomes a part of a page if the parent is a part of a page.

There is no destroy or close method for components[16]. A component is removed from the browser as soon as it is detached from the page. It is shown as soon as it is attached to the page.

<window id="main">
    <zscript>Component detached = null;</zscript>    
    <button id="btn" label="Detach">    
        <attribute name="onClick">        
    if(detached != null) {    
        detached.setParent(main);        
        detached = null;        
        btn.label = "Detach";        
    } else {    
        (detached = target).setParent(null);        
        btn.label = "Attach";        
    }    
        </attribute>        
    </button>    
    <separator bar="true"/>    
    <label id="target" value="You see this if it is attached."/>    
</window>

In the above example, you could use the setVisible method to have a similar effect. However, setVisible(false) doesn't remove the component from the browser. It just makes a component (and all its children) invisible.

After a component is detached from a page, the memory it occupies is release by JVM's garbage collector if the application has no reference to it.

Developing ZK Applications without ZUML

For developers who preferred not to use ZUML at all, they can use the so-called richlet to create all components manually.

import org.zkoss.zul.*;
public class TestRichlet extends org.zkoss.zk.ui.GenericRichlet {
    public void service(Page page) {    
        page.setTitle("Richlet Test");        

        final Window w = new Window("Richlet Test", "normal", false);        
        new Label("Hello World!").setParent(w);        
        final Label l = new Label();        
        l.setParent(w);        
        //...        
        w.setPage(page);        
    }    
}

Refer to the Richlets section in the Advanced Features chapter.

Define New Components for a Particular Page

As illustrated, it is simple to assign properties to a component by use of XML attributes.

<button label="OK" style="border:1px solid blue"/>

ZK provides a powerful yet simple way to let developers define new components for a particular pages. It is useful if most components of the same type share a set of properties.

First, you use the component directive to define a new component.

<?component name="bluebutton" extends="button" style="border:1px solid blue" label="OK"?>

<bluebutton/>
<bluebutton label="Cancel"/>

is equivalent to

<bluebutton style="border:1px solid blue" label="OK"/>
<bluebutton style="border:1px solid blue" label="Cancel"/>

Moreover, you can override the definition of button altogether as follows. Of course, it won't affect any other pages.

<?component name="button" extends="button" style="border:1px solid blue" label="OK"?>

<button/>
<button label="Cancel"/>

For more information, refer to the component Directive section in the ZK User Interface Markup Language chapter.



[8] Refer to the Quick Start Guide.

[9] The other way to try examples depicted here is to use the live demo to run them.

[10] The onCreate event is sent when a window defined in a ZUML page is created.

[11] The onOK event is sent when user pressed the ENTER key.

[12] The onCancel event is sent when user pressed the ESC key.

[13] The codes specified in ZUML pages are interpreted a the run time by the Java interpreter.

[14] http://www.beanshell.org

[15] To make things simpler, the factory design pattern is not used.

[16] The concept is similar to W3C DOM. On the other hand, Windows API required developers to manage the lifecycle.

3. The Basics

This chapter describes the basics of ZK. It uses XUL to illustrate ZK features, but it is usually applicable to other markup languages that ZK supports.

Architecture Overview

ZK includes an AJAX-based mechanism to automate interactivity, a rich set of XUL-based components to enrich usability, and a markup language to simplify development.

The AJAX-based mechanism consists of three parts as depicted below: ZK loader, ZK AU Engine[17] and ZK Client Engine.

Based on the user's request, the ZK Loader loads a ZK page, interprets it, and renders the result into HTML pages in response to URL requests. A ZK page is written in a markup language called ZUML. ZUML, like HTML, is used to describe what components to create and how to represent them visually. These components, once created, remain available until the session is timeout.

The ZK AU[18] Engine and the ZK Client Engine then work together as pitcher and catcher. They deliver events happening in the browser to the application running at the server, and update the DOM tree at the browser based on how components are manipulated by the application. This is so-called event-driven programming model.

The Execution Flow

  1. When a user types an URL or clicks an hyperlink at the browser, a request is sent to the Web server. ZK loader is then invoked to serve this request, if the URL matches which ZK is configured for[19].

  2. ZK loader loads the specified page and interprets it to create proper components accordingly.

  3. After interpreting the whole page, ZK loader renders the result into a HTML page. The HTML page is then sent back to the browser accompanied with ZK Client Engine[20].

  4. ZK Client engine sits at the browser to detect any event triggered by user's activity such as moving mouse or changing a value. Once detected, it notifies ZK AU Engine by sending a ZK request[21].

  5. Upon receiving ZK requests from Client Engine, AU Engine updates the content of corresponding component, if necessary. And then, AU Engine notifies the application by invoking relevant event handlers, if any.

  6. If the application chooses to change content of components, add or move components, AU Engine send the new content of altered components to Client Engine by use of ZK responses.

  7. These ZK responses are actually commands to instruct Client Engine how to update the DOM tree accordingly.

Components, Pages and Desktops

Components

A component is an UI object, such as a label, a button and a tree. It defines the visual presentation and behaviors of a particular user interface. By manipulating them, developers control how to represent an application visually in the client.

A component must implement the org.zkoss.zk.ui.Component interface.

Pages

A page (org.zkoss.zk.ui.Page) is a collection of components. A page confines components belonging to it, such that they will be displayed in a certain portion of the browser. A page is automatically created when ZK loader interprets a ZUML page.

Page Title

Each page could have a title that will be displayed as part of the browser's window caption. Refer to the Processing Instructions section in the ZK User Interface Markup Language chapter for details.

<?page title="My Page Title"?>

Desktops

A ZUML page might include another ZUML pages directly or indirectly. Since these pages are created for serving the same URL request, they are collectively called a desktop (org.zkoss.zk.ui.Desktop). In other word, a desktop is a collection of pages for serving the same URL request.

As a ZK application interacts with user, more pages might be added to a desktop and some might be removed from a desktop. Similarly, a component might be added to or removed from a page.

The createComponents Method

Notice that both pages and desktops are created and remove implicitly. There are no API to create or remove them. A page is create each time ZUML loads a page. A page is removed when ZK finds it is no longer referenced. A desktop is created when the first ZUML page is loaded. A desktop is removed if too many desktops are created for the specific session.

The createComponents method in the org.zkoss.zk.ui.Executions class creates only components, not page, even though it loads a ZUML file (aka., page).

Forest of Trees of Components

A component has at most one parent. A component might have multiple children. Some components accept only certain types of components as children. Some must be a child of certain type of components. Some don't allow any child at all. For example, Listbox in XUL accepts Listcols and Listitem only. Refer to Javadoc or XUL tutorials for details.

A component without any parent is called a root component. A page might have multiple root components, which could be retrieved by the getRoots method.

Component: a Visual Part and a Java Object

Besides being a Java object in the server, a component has a visual part[22] in the browser, if and only if it belongs to a page. When a component is attached to a page, its visual part is created[23]. When a component is detached from a page, its visual part is removed.

There are two ways to attach a component into a page. First, you could call the setPage method to make a component to become a root component of the specified page. Second, you could call the setParent, insertBefore or appendChild method to make it to become a child of another component. Then, the child component belongs to the same page as to which the parent belongs.

Similarly, you could detach a root component from a page by calling setPage with null. A child is detached if it is detached from a parent or its parent is detached from a page.

Identifiers

Each component has an identifier (the getId method). It is created automatically when a component is created. Developers could change it anytime. There is no limitation about how an identifier shall be named. However, if an alphabetical identifier is assigned, developers could access it directly in Java codes and EL expression embedded in the ZUML page.

<window title="Vote" border="normal">
    Do you like ZK? <label id="label"/>    
    <separator/>    
    <button label="Yes" onClick="label.value = self.label"/>    
    <button label="No" onClick="label.value = self.label"/>    
</window>

UUID

A component has another identifier called UUID (Universal Unique ID), which application developers rarely need.

UUID is used by components and Client Engine to manipulate DOM at the browser and to communicate with the server. More precisely, the id attribute of a DOM element at the client is UUID.

UUID is generated automatically when a component is created. It is immutable, except the identifiers of components for representing HTML tags.

HTML relevant components handle UUID different from other set of components: UUID is the same as ID. If you change ID of a HTML relevant component, UUID will be changed accordingly. Therefore, old JavaScript codes and servlets will remain to work without any modification.

The ID Space

It is common to decompose a visual presentation into several ZUML pages. For example, a page for displaying a purchase order, and a modal dialog for entering the payment term. If all components are uniquely identifiable in the same desktop, developers have to maintain the uniqueness of all identifiers for all pages that might created to the same desktop.

The concept of ID spaces is then introduced to resolved this issue. An ID space is a subset of components of a desktop. The uniqueness is guaranteed only in the scope of an ID space.

The simplest form of an ID space is a window (org.zkoss.zul.Window). All descendant components of a window (including the window itself) forms an independent ID space. Thus, you could use a window as the topmost component of each page, such that developers need to maintain the uniqueness of each page separately.

More generally, any component could form an ID space as long as it implements the org.zkoss.zk.ui.IdSpace interface. Page also implements the IdSpace interface, so it is also a space owner.

The topmost component of an ID space is called the owner of the ID space, which could be retrieved by the getSpaceOwner method in the Component interface.

If an ID space, say X, is a descendant of another ID space, say Y, then space X's owner is part of space Y but descendants of X is not part of space Y.

As depicted in the figure, there are three spaces: P, A and C. Space P includes P, A, F and G. Space A includes A, B, C and D. Space C includes C and E.

Components in the same ID spaces are called fellows. For example, A, B, C and D are fellows of the same ID space.

To retrieve another fellow, you could use the getFellow method in the IdSpace interface or the Component interface.

Notice that the getFellow method can be invoked against any components in the same ID space, not just the space owner. Similarly, the getSpaceOwner method returns the same object for any components in the same ID space, no matter it is the space owner or not.

The org.zkoss.zk.ui.Path class provides utilities to simplify the location of a component among ID spaces. Its use is similar to java.io.File.

Path.getComponent("/A/C/E");

new Path("A/C", "E").getComponent();

Namespace and ID Space

To let the interpreter able to access the components directly, the namespace concept (org.zkoss.scripting.Namespace) is introduced. First, each ID space has exactly one namespace. Second, variables defined in a namespace are visible to the scripting codes and EL expressions that belong to the same namespace.

<window border="normal">
    <label id="l" value="hi"/>    
    <zscript>    
        l.value = "Hi, namespace";        
    </zscript>    
    ${l.value}    
</window>

In the following example, there are two namspaces. One belongs to window w1 and the other to window w2[24]. Thus, the b1 button's onClick script refers to the label defined in window w1, while the b2 button's onClick script refers to the checkbox defined in window w2.

<window id="w1">
    <window id="w2">    
        <label id="c"/>        
        <button id="b1" onClick="c.value = &quot;OK&quot;"/>        
    </window>    
    <checkbox id="c"/>    
    <button id="b2" onClick="c.label = &quot;OK&quot;"/>    
</window>

Notice the namespace is hierarchical. In other words, zscript in window w2 can see components in window w1, unless it is overridden in window w2. Thus, clicking button b1 will change label c in the following example.

<window id="w1">
    <window id="w2">    
        <button id="b1" onClick="c.value = &quot;OK&quot;"/>        
    </window>    
    <label id="c"/>    
</window>

In addition to ZK's assigning components to the namespace, you can assign your variables to them by use of the setVariable method, such that zscript can reference them directly.

Variable and Functions Defined in zscript

In addition to executing codes, you could define variables and functions in the zscript element directly as depicted below.

<window id="A>
    <zscript>    
        Object myvar = new LinkedList();        
        void myfunc() {        
            ...            
        }        
    </zscript>    
    ...    
    <button label="add" onClick="myvar.add(some)"/>    
    <button label="some" onClick="myfunc()"/>    
</window>

The variables and methods defined in zscript are stored in the interpreter of the corresponding scripting language.

zscript and EL Expressions

Like namespaces[25], variable defined in zscript are all visible to EL expressions.

<window>
    <zscript>    
    String var = "abc";    
    self.setVariable("var2", "xyz", true);    
    </zscript>    
    ${var} ${var2}    
</window>

is equivalent to

<window>
abc xyz
</window>

Notice that variables defined in zscript has the higher priority than those defined in the namespace.

<window>
    <zscript>    
    String var = "abc";    
    self.setVariable("var", "xyz", true);    
    </zscript>    
    ${var}    
</window>

is equivalent to

<window>
abc
</window>

It is sometimes confusing, if you declare a component later as shown in the following example.

<window>
    <zscript>    
    String var = "abc";    
    </zscript>    
    <label id="var" value="A label"/>    
    ${var.value} <!-- Wrong! var is "abc", not the label -->    
</window>

Therefore, it is suggested to use some naming pattern to avoid the confusion. For example, you can prefix all interpreter variables with zs_.

In additions, you shall use local variables if possible. A local variable is declared with the class name, and it is visible only to a particular scope of zscript codes.

<zscript>
Date now = new Date();
</zscript>

Furthermore, you can make a local variable invisible to EL expressions by enclosing it with curly braces as follows.

<zscript>
{ //create a new logic scope
    String var = "abc"; //visible only inside of the enclosing curly brace    
}
</zscript>

Multi-Scope Interpreters

Depending on the implementation, an interpreter might have exactly one logical scope, or one logic scope per ID space to store these variables and methods. For sake of description, we call them the single-scope and multi-scope interpreters, respectively.

Java interpreter (BeanShell) is a typical multi-scope interpreter[26]. It creates an interpreter-dependent scope for each ID space. For example, two logical scopes are created for window A and B, respectively in the following example. Therefore, var2 is visible only to window B, while var1 is visible to both window A and B in the following example.

<window id="A">
    <zscript>var1 = "abc";</zscript>    
    <window id="B">    
        <zscript>var2 = "def";</zscript>        
    </window>    
</window>
Java Interpreter (BeanShell)

With Java Interpreter (BeanShell), you can declare an interpreter variable local to the logical scope of the nearest ID space (i.e., a window) by specifying the class name as below,

<window id="A">
    <window id="B">    
        <zscript>        
    String b = "local to window B";    
        </zscript>        
    </window>    
</window>

The following is a more sophisticated example which will generate abc def.

<window id="A">
    <zscript>    
    var1 = var2 = "abc";    
    </zscript>    
    <window id="B">    
        <zscript>        
    Object var1 = "123";    
    var2 = "def";    
    var3 = "xyz";    
        </zscript>        
    </window>    
    ${var1} ${var2} ${var3}    
</window>

where Object var1 = "123" actually creates a variable local to window B since the class name, Object, is specified. On the other hand, var2 = "def" causes the interpreter to look up any variable called var2 defined in the current scope or any scope in the upper layers. Since var2 was defined in window A, the variable is overridden. In the case of var3 = "xyz", a variable local to window B is created, since window A doesn't define any variable called var3.

Single-Scope Interpreters

Ruby, Groovy and JavaScript interpreters don't support multi-scope yet[27]. It means all variables defined in, say, Ruby are stored in one logical scope (per interpreter). Thus, the interpreter variables defined in one window override those defined in another window if they are in the same page. To avoid confusion, you could prefix the variable names with special prefix denoting the window.

Tip: Each page has its own interpreter to evaluate zscript codes. If a desktop has multiple pages, then it might have multiple instances of the interpreters (per scripting language).

Multiple scripting Languages in One Page

Each scripting language is associated with one interpreter. Thus, variables and methods defined in one language are not visible to another language. For example, var1 and var2 belong to two different interpreters in the following example.

<zscript language="Java">
    var1 = 123;    
</zscript>
<zscript language="JavaScript">
    var2 = 234;    
</zscript>

getVariable versus getZScriptVariable

Variables defined in the namespace can be retrieved by use of the getVariable method.

On the other hand, variables defined in zscript is part of the interpret that interprets it. They are not a part of any namespace. In other words, you can not retrieve them by use of the getVariable method.

<zscript>
    var1 = 123; //var1 belongs to the interpreter, not any namespace    
    page.getVariable("var1"); //returns null    
</zscript>

Instead, you have to use getZScriptVariable to retrieve variables defined in zscript. Similarly, you can use getZScriptClass to retrieve classes and getZScriptMethod to retrieve methods defined in zscript. These methods will iterate through all loaded interpreters until the specified one is found.

If you want to search a particular interpreter, you can use the getInterpreter method to retrieve the interpreter first, as follows.

page.getInterpreter("JavaScript").getVariable("some"); //interpreter for JavaScript
page.getInterpreter(null).getVariable("some"); //interpreter for default language

Events

An event (org.zkoss.zk.ui.event.Event) is used to notify application what happens. Each type of event is represented by a distinct class. For example, org.zkoss.zk.ui.event.MouseEvent denotes a mouse activity, such as clicking.

To response to an event, an application must register one or more event listeners to it. There are two ways to register an event listener. One is by specifying the onXxx attribute in the markup language. The other is by calling the addEventListener method for the component or the page you want to listen.

In addition to event triggered by user's activity at the browser, an application could fire events by use of the sendEvent, postEvent and echoEvent methods from the org.zkoss.zk.ui.event.Events class.

Desktops and Event Processing

As mentioned above, a desktop is a collection of pages for serving the same URL request. A desktop is also the scope that an event listener could access.

When an event is fired, it is associate with a desktop. ZK separates events based on the associated desktops, and pipelines events into separated queues. Therefore, events for the same desktop are processed sequentially. On the other hand, events for different desktops are processed in parallel.

An event listener is allowed to access any components of any pages of the desktop associated with the event. It is also allowed to moving components from one page to another as long as they are in the same desktop. On the other hand, it cannot access components belonging to other desktops.

Note: Developers can detach a component from one desktop in one event listener, and then attach it to another desktop in other event listener.

Desktops and the Creation of Components

When a component is created in an event listener, it is assigned automatically to the associated desktop of the event being processed. This assignment happens even if the component is not attached to a page. It means that any component you created in an event listener can be used in the same desktop that the listener is handling.

When a component is created in a thread other than any event listener, it doesn't belong to any desktop. In this case, you could attach to any desktop you want as long as the attachment occurs in a proper event listener. Of course, once the component is attached to a desktop, it belongs to the desktop forever.

For most applications, it is rarely necessary to create components in a thread other than event listeners. However, if you have a long operation, you might want to execute it in a background thread. Then, you could prepare the component tree at the background and then add it to a desktop when a proper event is received. Refer to the Long Operations section in the Event Listening and Processing chapter.

ZUML and XML Namespaces

The ZK User Interface Markup Language (ZUML) is a XML-based language used by developers to describe the visual presentation. ZUML is aimed to separate the dependency of the set of components to use. In other words, different set of components[28], such as XUL and XHTML, could be used simultaneously in the same ZUML page. Different markup languages could be added transparently. If two or more set of components are used in the same page, developers have to use the XML namespaces to distinguish them. Refer to the Component Sets and XML Namespaces section in the ZK User Interface Markup Language chapter if you want to mix multiple component sets, say XUL and XHTML, in the same page.

Tip: Using XML namespaces in ZUML is optional. You need it only if you want to mix two or more.



[17] Also known as ZK Update Engine.

[18] AU stands for Asynchronous Update.

[19] Refer to Appendix A in the Developer's Reference.

[20] ZK Client Engine is written in JavaScript. Browsers cache ZK Client engine, so the engine is usually sent only once at the first visit.

[21] ZK requests are special AJAX requests. However, for the mobile edition, ZK requests are special HTTP requests.

[22] If the client is a browser, the visual presentation is a DOM element or a set of DOM elements.

[23] The visual part is created, updated and removed automatically. Application developers rarely need to notice its existence. Rather, they manipulate the object part in the server.

[24] A window implements org.zkoss.zk.ui.IdSpace, so it forms an independent ID space and namespace.

[25] org.zkoss.zk.scripting.Namespace

[26] Java interpreter supports multi-scope after 2.3.1 (included) and before 2.2.1 (included).

[27] We may support it in the near future.

[28] Also known as tags. There is one-to-one mapping between components and tags.

4. The Component Lifecycle

This chapter describes the lifecycles of loading pages and updating pages.

The Lifecycle of Loading Pages

It takes four phases for ZK loaders to load and interpret a ZUML page: the Page Initial Phase, the Component Creation Phase, the Event Processing Phase, and the Rendering Phase.

The Page Initial Phase

In this phase, ZK processes the processing instructions, called init. If none of such processing instructions are defined, this phase is skipped.

For each init processing instruction with the class attribute, an instance of the specified class is constructed, and then its doInit method is called. What the class will do, of course, depends on your application requirements.

<?init class="MyInit"?>

Another form of the init processing instruction is to specify a file containing the scripting codes with the zscript attribute, as follows. Then, the file will be interpreted at the Page Initial phase.

<?init zscript="/my/init.zs"?>

Notice that the page is not yet attached to the desktop when the Page Initial phase executes.

The Component Creation Phase

In this phase, ZK loader interprets an ZUML page. It creates and initializes components accordingly. It takes several steps as follows.

  1. For each element, it examines the if and unless attribute to decide whether it is effective. If not, the element and all of its child elements are ignored.

  2. If the forEach attribute is specified with a collection of items, ZK repeats the following steps for each item in the collection.

  3. Creates a component based on the element name, or by use of the class specified in the use attribute, if any.

  4. Initializes the members one-by-one based on the order that attributes are specified in the ZUML page.

  5. Interprets the nested elements and repeat the whole procedure.

  6. Invokes the afterCompose method if the component implements the org.zkoss.zk.ui.ext.AfterCompose interface[29].

  7. After all children are created, the onCreate event is sent to this component, such that application could initialize the content of some elements later. Notice that the onCreate events are posted for child components first.

Note: an developer can perform some application-specific initialization by listening to the onCreate event or implementing AfterCompose. AfterCompose is called in the Component Creation Phase, while the onCreate event is handled by an event listener.

An event listener is free to suspend and resume the execution (such as creating modal dialogs), while AfterCompose is a bit faster since no need to fork another thread.

The Event Processing Phase

In this phase, ZK invokes each listener for each event queued for this desktop one-by-one.

An independent thread is started to invoke each listener, so it could be suspended without affecting the processing of other events.

During the processing, an event listener might fire other events. Refer to the Event Listening and Processing chapter for details.

The Rendering Phase

After all events are processed, ZK renders these components into a regular HTML page and sends this page to the browser.

To render a component, the redraw method is called. The implementation of a component shall not alter any content of the component in this method.

The Lifecycle of Updating Pages

It takes three phases for ZK AU Engine to process the ZK requests sent from the clients: the Request Processing Phase, the Event Processing Phase, and the Rendering Phase.

ZK AU Engine pipelines ZK requests into queues on a basis of one queue per desktop. Therefore, requests for the same desktop are processed sequentially. Requests for different desktops are processed in parallel.

The Request Processing Phase

Depending on the request, ZK AU Engine might update the content of affected components such that their content are the same as what are shown at the client.

Then, it posts corresponding events to the queue.

The Event Processing Phase

This phase is the same as the Event Processing Phase in the Component Creation Phase. It processes events one-by-one in an independent thread.

The Rendering Phase

After all events are processed, ZK renders affected components, generates corresponding ZK responses, and sends these responses back to the client. Then, Client Engine updates the DOM tree at the browser based on the responses.

Whether to redraw the whole visual presentation of a component or to update an attribute at the browser all depend on the implementation of components. It is the job of component developers to balance between interactivity and simplicity.

The Molds

A component could have different appearance even at the same page. The concept is called mold (aka., template). Developers could dynamically change the mold by use of the setMold method in the Component interface. All components support a mold called default, which is the default value. Some components might have support two or more molds For example, tabbox supports both default and accordion molds.

<tabbox><!-- if not specified, the default mold is assumed. -->
    <tabs>    
        <tab label="Default"/>        
    </tabs>    
    <tabpanels>    
        <tabpanel>        
        <tabbox mold="accordion">        
            <tabs>            
                <tab label="First Accordion"/>                
                <tab label="Second Accordion"/>                
            </tabs>            
            <tabpanels>            
                <tabpanel>The first panel.</tabpanel>                
                <tabpanel>The second panel.</tabpanel>                
            </tabpanels>            
        </tabbox>        
        </tabpanel>        
    </tabpanels>    
</tabbox>

Component Garbage Collection

Unlike many component-based GUI, ZK has no destroy or close method for components. Like W3C DOM, a component is removed from the browser as soon as it is detached from the page. It is shown as soon as it is attached to the page.

More precisely, once a component is detached from a page, it is no longer managed by ZK. If the application doesn't have any reference to it. The memory occupied by the component will be released by JVM's Garbage Collector.



[29] The step 3-5 is so-called composing. That is why AfterCompose is named.

5. Event Listening and Processing

This chapter describes how an event is processed.

Add Event Listeners by Markup Languages

The simplest way to add an event listener is to declare an attribute in a ZUML page. The value of the attribute for listening an event is any Java codes that could be interpreted by BeanShell.

<window title="Hello" border="normal">
    <button label="Say Hello" onClick="alert(&quot;Hello World!&quot;)"/>    
</window>

Add and Remove Event Listeners by Program

There are two ways to add event listeners by program.

Declare a Member

When overriding a component by use of your own class, you could declare a member function to be an event listener as follows.

In a ZUML page, you declare the use attribute to specify what class you want to use instead of the default one. As illustrated below, it asks ZK to use the MyWindow class instead of org.zkoss.zul.Window[30].

<window use="MyWindow">
...
</window>

Then, you implement MyWindow.java by extending from the default class as follows.

public class MyWindow extends org.zkoss.zul.Window {
    public void onOK() { //add an event listener    
        ...//handles the onOK event (sent when ENTER is pressed)        
    }    
}

If you want to retrieve more information about the event, you could declare as follows.

public void onOK(org.zkoss.zk.ui.event.KeyEvent event) {...}

or

public void onOK(org.zkoss.zk.ui.event.Event event) {...}

Different events might be associated with different event objects. Refer to Append C for more details.

Add and Remove Event Listeners Dynamically

Developers could use the addEventListener and removeEventListener methods of the org.zkoss.zk.ui.Component interface to dynamically add or remove an event listener. As illustrated below, the event listener to be added dynamically must implement the org.zkoss.zk.ui.event.EventListener interface.

void init(Component comp) {
    ...    
    comp.addEventListener("onClick", new MyListener());    
    ...    
}
class MyListener implements org.zkoss.zk.ui.event.EventListener {
    public void onEvent(Event event) throws UiException {    
        ...//processing the event        
    }    
}

Deferrable Event Listeners

By default, events are sent the server when it is fired at the client. However, many event listeners are just used to maintain the status at the server, rather than providing visual response to the user. In other words, the events for these listeners have no need to be sent immediately. Rather, they shall be sent at once to minimize the traffic between the client and the server, and then to improve the server's performance. For the sake of the description convenience, we call them the deferrable event listeners.

To make an event listener deferrable, you have to implement the org.zkoss.zk.ui.event.Deferrable interface (with EventListener) and return true for the isDeferrable method as follows.

public class DeferrableListener implements EventListener, Deferrable {
    private boolean _modified;    
    public void onEvent(Event event) {    
        _modified = true;        
    }    
    public boolean isDeferrable() {    
        return true;        
    }    
}

When an event is fired at the client (e.g., the user selects a list item), ZK won't send the event if no event listener is registered for it or only deferrable listeners are registered. instead, the event is queued at the client.

On the hand, if at least one non-deferrable listener is registered, the event are sent immediately with all queued events to the server at once. No event is lost and the arriving order is preserved.

Tip: Use the deferrable listeners for maintaining the server status, while the non-deferrable listeners for providing the visual responses for the user.

Add and Remove Event Listeners to Pages Dynamically

Developers could add event listeners to a page (org.zkoss.zk.ui.Page) dynamically. Once added, all events of the specified name the are sent to any components of the specified page will be sent to the listener.

All page-level event listeners are non-ASAP. In other words, the isArap method is ignored.

A typical example is to use a page-level event listener to maintain the modification flag as follows.

public class ModificationListener implements EventListener, Deferrable {
    private final Window _owner;    
    private final Page _page;    
    private boolean _modified;    

    public ModificationListener(Window owner) {    
        //Note: we have to remember the page because unregister might        
        //be called after the owner is detached        
        _owner = owner;        
        _page = owner.getPage();        
        _page.addEventListener("onChange", this);        
        _page.addEventListener("onSelect", this);        
        _page.addEventListener("onCheck", this);        
    }    
    /** Called to unregister the event listener.    
     */    
    public void unregister() {    
        _page.removeEventListener("onChange", this);        
        _page.removeEventListener("onSelect", this);        
        _page.removeEventListener("onCheck", this);        
    }    
    /** Returns whether the modified flag is set.    
     */    
    public boolean isModified() {    
        return _modified;        
    }    
    //-- EventListener --//    
    public void onEvent(Event event) throws UiException {    
        _modified = true;        
    }    
    //-- Deferrable --//    
    public boolean isDeferrable() {    
        return true;        
    }    
}

Note: Whether to implement the Deferrable interface is optional in this example, because the page's event listeners are always assumed to be deferrable, no matter Deferrable is implemented or not.

The Invocation Sequence

The sequence of invoking event listeners is as follows. Let us assume the onClick event is received.

  1. Invoke event listeners for the onClick event one-by-one that are added to the targeting component, if the listeners also implement the org.zkoss.zk.ui.event.Express interface. The first added, the first called.

  2. Invoke the script specified in the onClick attribute of the targeting component, if any.

  3. Invoke event listeners for the onClick event one-by-one that are added to the targeting component, if the listeners don't implement the org.zkoss.zk.ui.event.Express interface. The first added, the first called.

  4. Invoke the onClick member method of the targeting component, if any.

  5. Invoke event listeners for the onClick event one-by-one that are added to the page that the targeting component belongs. The first added, the first called.

The org.zkoss.zk.ui.event.Express interface is a decorative interface used to alter the invocation priority of an event listener. Notice that it is meaningless if the event listener is added to pages, instead of components.

Abort the Invocation Sequence

You could abort the calling sequence by calling the stopPropagation method in the org.zkoss.zk.ui.event.Event class. Once one of the event listeners invokes this method, all following event listeners are ignored.

Send, Post and Echo Events from an Event Listener

In addition to receiving events, an application could communicate among event listeners by posting or sending events to them.

Post Events

By use of the postEvent method in the org.zkoss.zk.ui.event.Events class, the application could post an event to the end of the event queue. This method returns immediately after placing the event into the queue. The event will be processed later after all events preceding it have been processed.

Send Events

By use of the sendEvent method in the org.zkoss.zk.ui.event.Events class, the application could ask ZK to process the specified event immediately. This method won't return until all event listeners of the specified event has been processed. The event is processed at the same thread.

Echo Events

By use of the echoEvent method in the org.zkoss.zk.ui.event.Events class, the application could ask the client to echo back the event for processing later. This method returned immediately after queuing the response asking the client to echo back the event.

Notice that, unlike sendEvent and postEvent, the event won't be processed in the current execution. Rather, it is processed later after the client echoes back the event. In other words, the event is processed later after the client has updated its user interfaces. Thus, it is useful to prompt the user before starting a long operation.

For example, you can open a highlighted window and then invoke echoEvent to do the long operation after the client shows the window (and echoes back the event).

For example, we can use the org.zkoss.zk.ui.util.Clients.showBusy method to show the busy message such that the user knows the system is busy. So, the end user will see "Execute..." first and then, after two seconds, "Done." in the following example. If you use postEvent, the end user will see "Execute..." and "Done" at the same time after two seconds.

<window id="w" title="Test echoEvent">
    <attribute name="onLater">    
    Thread.sleep(2000);    
    Clients.showBusy(null, false);    
    new Label("Done.").setParent(w);    
    </attribute>    

    <button label="echo">    
    <attribute name="onClick">    
    Clients.showBusy("Execute...", true);    
    Events.echoEvent("onLater", w, null);    
    </attribute>    
    </button>    
</window>

Thread Model

For each desktop, events are processed sequentially, so thread model is simple. Like developing desktop applications, you don't need to worry about racing and multi-threading. All you need to do is to register an event listener and process the event when invoked.

Tip: Each event listener executes in an independent thread called event processing thread, while the ZUML page is evaluated in the servlet thread.

Tip: The use of the event processing thread can be disabled such that all events are processed in the Servlet threads. It has a little bit better performance and less integration issues. However, you can not suspend the execution. Refer to the Use the Servlet Thread to Process Events section in the Advanced Features chapter.

Suspend and Resume

For advanced applications, you might have to suspend an execution until some condition is satisfied. The wait, notify and notifyAll methods of the org.zkoss.zk.ui.Executions class are designed for such purpose.

When an event listener want to suspend itself, it could invoke wait. Another thread could then wake it up by use of notify or notifyAll, if the application-specific condition is satisfied. The modal dialog is an typical example of using this mechanism.

public void doModal() throws InterruptedException {
    ...Executions.wait(_mutex); //suspend this thread, an event processing thread}    
public void endModal() {
...
    Executions.notify(_mutex); //resume the suspended event processing thread    
}

Their use is similar to the wait, notify and notifyAll methods of the java.lang.Object class. However, you cannot use the methods of java.lang.Object for suspending and resuming event listeners. Otherwise, all event processing will be stalled for the associated desktop.

Notice that, unlike Java Object's wait and notify, whether to use the synchronized block to enclose Executions' wait and notify is optional. In the above case, we don't have to, because no racing condition is possible. However, if there is an racing condition, you can use the synchronized block as what you do with Java Object's wait and notify.

//Thread 1
public void request() {
    ...    
    synchronized (mutex) {    
        ...//start another thread        
        Executions.wait(mutex); //wait for its completion        
    }    
}

//Thread 2
public void process() {
    ... //process it asynchronously    
    synchronized