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.
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.
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. An AJAX-based event-driven engine
2. A rich set of XUL and XHTML components
3. ZUML (ZK User Interface Markup Language)
Before we go on, we should get familiar with a few buzzwords, which we mentioned before.
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 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 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.
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. An AJAX-based event-driven engine
2. A rich set of XUL and XHTML components
3. ZUML (ZK User Interface Markup Language)
Before we go on, we should get familiar with a few buzzwords, which we mentioned before.
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 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 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.
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.
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. zkdemo-all.war
2. zkdemo.war
3. zkdemos-all.ear
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("Hello "+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"
; for'
and&
; 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).
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.
On the user side there are only HTML pages. In ZK these pages are build on desktops, pages, and components.
Component |
Framework representation: 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: A page contains components. Therefore, a page is a container for
components. If the ZK loader is interpreting a ZUML page, a Note: A page can have multiple root components. |
Desktop |
Framework representation: 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.
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.
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")
The lifecycle of loading a ZK page consists of four phases. These phases are illustrated in the figure below.
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
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
).
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.
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.
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("Hello "+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.
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.
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 inork.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
ornotifyAll
method oforg.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.
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.
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.
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:
The XUL component set | |
The XHTML component set | |
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" />
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>
Beyond the normal attributes of elements (for example: width)
there are some special attributes, which are called ZK Attributes.
|
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" />
|
|
The element is rendered only if the condition is true. Example: <textbox if="${b==1}" />
|
|
The element is rendered only if the condition is false Example: <textbox unless="${c==1}" />
|
|
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}" />
|
|
This is used in conjunction with the Example: <listitem label="${each}" forEach="${elements}" forEachBegin="1" />
|
|
This is used in conjunction with the Example: <listitem label="${each}" forEach="${elements}" forEachEnd="1" />
|
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.
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.
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
, androw)
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).
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.
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.
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>
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.
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.
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>
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.