Define Composite Component using Java Annotation in ZK6

From Documentation
DocumentationSmall Talks2011DecemberDefine Composite Component using Java Annotation in ZK6
Define Composite Component using Java Annotation in ZK6

Author
Ian Tsai, Engineer, Potix Corporation
Date
December 06, 2011
Version
ZK 6

Introduction

ZK Composite is a way to encapsulate a bunch of components as a component with ZK MVC support. In ZK6, ZK Composite brings you the ability to define and implement your component with simple Java API and annotation, your composite component can be used almost 100% like a native component in ZK6.

This article will guide you through the following topics:

  • Why Composite?
  • When should we use Composite?
  • How to design our Composite?

The idea of Composite

In previous article Envisage ZK 6: An Annotation Based Composer For MVC Simon Pai showed us the new approach to do ZK MVC in ZK6, which might be the best common solution for page layout fragment controller implementation. However, in some cases, we have some requirements to some special UI parts that simple ZK MVC cannot satisfy, for example, when

  • This UI fragment is supposed to be reused in a lot of places.
  • It needs to be attached and detached according to conditions.
  • It should be able to interact with other UI parts just like a ZK Component (ex: a Permission Inquiry Dialog).

In ZK5, we introduced a concept named ZK Composite Component which is more like a practice. And now in ZK 6, granted with the power brought about by Java Annotation, we are able to design an utility API and a "define by annotation" mechanism to provide more conveniences.

How to Use

Before I start to show you how to get and install, and show you the many features that a Composite has, I'd much prefer to use a quick sample code to show you how it works.


The use case: An in-place editable ImageLabel

Let's imagine that today we want to build a Component with a look & feel like the following:

Smalltalks-define-composite-using-java-anno-in-zk6-01.png

The ZUL file of this UI part is very simple:

<groupbox id="item" width="800px" closable="false" sclass="item">
	<caption>
		<label id="titleLabel" sclass="title" />
	</caption>
	<hlayout>
		<image id="labelImage" sclass="image" />
		<div sclass="desc-div">
			<label id="descLabel" sclass="desc" />
		</div>
	</hlayout>
</groupbox>

This component has three properties: title, description and image. Now, by clicking the title of this component, the in-place editor will show up:

Smalltalks-define-composite-using-java-anno-in-zk6-02.png

The ZUL structure of an in-place editor is also very simple:

<zk>
	<hlayout width="790px">
		<textbox id="editTitle" width="650px" />
		<button id="submitBtn" label="Submit" />
		<button id="cancelBtn" label="Cancel" />
	</hlayout>
	<textbox id="editDesc" rows="5" width="790px" />
</zk>

As you can see, an editing area showed up where we can edit title and description for this ImageLabel. Now that we have scratches of an UI usage that we want to have, let's think about what kind of component API we want to implement for this component.

Usage of ImageLabel in ZUL file

<window title="Composite Demo" border="normal" width="1000px">

	<imglabel title="test" 
		description="this is description!!" 
		imagePath="~./partial/img/Centigrade-Widget-Icons/Button-24x24.png">
		
		<attribute name="onAfterEdit"><![CDATA[
			alert("new title is: "+event.title);
		]]></attribute>
		
	</imglabel>

</window>

This sample code shows us three things:

  • The imageLabel that we finally have can be used directly in ZUL, this means that our final Composite class needs to be registered in to ZK's Language Definition as a Component Definition.
  • This ImageLabel has to have setters/getters for title, description and imagePath properties for developers to configure.
  • This imageLabel supports it's own event type: onAfterEdit

Implementation of your Composite Class

Here is a sample code of how ZK 6 Composite technology is used:

 1 package demo.ui.composite;
 2 
 3 import org.zkoss.composite.Composite;
 4 import org.zkoss.composite.Composites;
 5 import org.zkoss.zk.ui.IdSpace;
 6 import org.zkoss.zk.ui.select.Listen;
 7 import org.zkoss.zk.ui.select.Wire;
 8 ...
 9 
10 @Composite
11 public class ImageLabel extends Div implements IdSpace {
12 	
13 	@Wire
14 	private Groupbox item;
15 	@Wire
16 	private Image labelImage;
17 	@Wire
18 	private Label titleLabel;
19 	@Wire
20 	private Label descLabel;
21 	
22 	public ImageLabel(){
23 		Composites.doCompose(this, null);
24 	}
25 	
26 	private InplaceEditor fInplaceEditor;
27 	
28 	@Listen("onClick= #titleLabel")
29 	public void doTitleClick(){
30 		if(fInplaceEditor==null){
31 			fInplaceEditor = new InplaceEditor();
32 			fInplaceEditor.setParent(item);
33 		}else{
34 			fInplaceEditor.doCancel();
35 		}
36 	}

The concept is very simple: you declare a Java class which extends a ZK Component, annotate this class, call Composites.doCompose(this, null); in your constructor, and that's it.

The detailed steps are listed bellow:

  • Create a Java class extends from an existing ZK Component (ex: Div or Window)
  • Normally your composite class will extend from a container component such as Div or Window, but cases where it extends from a Collection Component such as Grid or Listbox are also very common, this part is very flexible, all depends on your needs.
  • Ensure your class implements IdSpace
  • ZK Composite requires a ZUL as the content template and will do the field-variable auto wiring & Event Listening method registration. In order to prevent id conflict, you must make your Composite class implements IdSpace.
  • Call Composites.doCompose in constructor
  • org.zkoss.composite.Composites is the utility API which will do the real hard works. While doCompose(...), Composites will get the meta information(Java annotation) from given instance type and perform the following process:
    1. Getting macroURI from annotation(@Composite) if any, use referenced resource to generate content components of this composite.
    2. Using ZK6 org.zkoss.zk.ui.select.Selectors to wire annotated member fields and annotated methods(as event listening methods).

ZK Composite Definition can be registered through package scanning

Use annotated class as some kind of configuration with package scan while application starts is a common practice used in a lot of application frameworks such as Spring, JBoss, Seam and EJB3. Now in ZK Composite, we support the same mechanism to register a composite as a component definition into application's ZUL Language Definition, which means by given packages in zk.xml, ZK Composite will find all annotated public Composite class and register them. This is a very convenient feature for users to define a composite without creating & configuring metainfo/zk/lang-addon.xml in your source directory.


Set up zk.xml library property for your target package

Here is an example of how to config packages in your application:

1 <library-property>
2     	<name>org.zkoss.composite.packageScan</name>
3     	<value>demo.ui.homepage.composite, demo.ui.product.composite</value>
4 </library-property>

As this example illustrated, by now ZK Composite use ZK Library properties as the configuration interface, if in your case instead of going through this strategy you want to configure it by yourself, here is the API:

1 org.zkoss.composite.CompositeCtrls.scan(pkg, wapp);

Currently ZK Composite depends on ZK-CPR and ASM4.0 to implement it's package resource scanning, please make sure you have these jars(which are already packed inside the zip)in your project.

Use @Composite to annotate your Composite class

Import: org.zkoss.composite.Composite then mark your component class with @Composite annotation. @Composite has two attributes:

1. macroURI: by default, you don't have to assign this attribute and ZK Composite technology will use [package]/[class_name to lowerCase].zul to get the content template. The macro uri that you can assigned can be a class path resource which use "/" as separator, a zk web context path or a URL that current application can resolve.

2. name: by default, ZK Composite technology will use lower-cased class simple name as component name, which is the tag name that you can use in zul under zul namespace(default xml namespace in ZK).

Here is an example with most detail:

10 import org.zkoss.composite.Composite;
11 ...
12 
13 @Composite(name="imglabel", macroURI="/WEB-INF/partial/_ImageLabel.zul")
14 public class ImageLabel extends Div implements IdSpace {
15 ...

Installation

Here is the prerequisite stuff of using Composite in ZK6.

Install ZK 6 into your Web Project

I assume the reader of this article has used ZK before so I won't explain too much on this part, if you don't know how to start with ZK, please take a look at ZK Installation Guide

(Download link listed at the bottom of this article.)

Download ZK-Composite.zip from Github.com

Here is the project's link: ZK-Composite

Download the ZK-Composite.zip from this web site and unpack it. I assume you already has a ZK project, if you don't have, please read the user guide to create one, now copy every jar files(asm4.0.jar, zkcomposite.jar, zkcpr.jar) under /lib/* to your project's /WEB-INF/lib/.

(Download link listed at the bottom of this article.)

Copy the sample code into your project

inside the unpacked archive there are two folders: src_demo/ and WebContent/ , copy them into your project.

Download & Other Resources



Comments



Copyright © Potix Corporation. This article is licensed under GNU Free Documentation License.