From Documentation

Jump to: navigation, search

An Introduction of ZK Composer -- an Example of Fusioning Component and Model






  • Author
    Ryan Wu, Engineer, Potix Corporation.
  • Date
    Dec 17, 2008
  • Version
    Applicable to ZK 3.5.2.


Contents

Introduction

Model-view-controller (MVC) is an architectural pattern used in software engineering. Like previous articles, we always look for the best practice for ZK to realize MVC approach perfectly. That's why we created interfaces for every ZK components in ZK 3.5.2. This article mainly introduce a new feature - "Fusion Invoker". By using it, we can separate the View and the Controller more clearly. I will create some cases to show how and why using it.

Finally, in the Appendix, I create a diagram to show the life cycle of composers we have introduced.


For further information, please refer to ZK Developer's Reference: Composer.

The Example

This is a simple example, it has a window which contains a listbox and a textbox. Now we have a list of customers' name from Class DataResource, we want to set the list into the listbox by using "model".

Case.PNG
public class DataResource {
	//Constructor
	public DataResource() {...}

	/**
	 * @return the ListModel
	 */
	public ListModel getCustomers() {
	   ...
		return listmodel;
	}
}

After choosing a customer, once the textbox get focused, it's value will change to "Dear : Customer's Name".

Case2.PNG

Historical Approach

In order to satisfy the requirements, we have several ways to do that. Following are some ways we usually use :

Using the "Use"

Extend the layout window, then use the "use" attribute :

  • View
  • Controller
<window id="win" title="Customized Window" border="normal"
	use="composer.CustomWin" width="300px">
	<listbox id="list" width="200px" rows="5"   model="$ {win.customers}" />
	<separator />
	<textbox id="text" value="Click to get value" width="200px"
		  onFocus="win.onFocusName()" />
</window>
public class CustomWin extends Window {
	DataResource _dr = new DataResource();

	public ListModel getCustomers() {
		return _dr.getCustomers();
	}

	public void onFocusName() {
		final Textbox text = (Textbox) this.getFellow("text");
		final Listbox list = (Listbox) this.getFellow("list");
		text.setValue("Dear : " + (list.getSelectedItem() == null ? "Null" : 
					list.getSelectedItem().getValue().toString()));
	}
}
  • Pros and Cons
  • Pros
  • Easy to understand - only attach some new method to Window.
  • Cons
  • The controller have to extends the component which existed in view (Window).

Composer Enhanced

Create a class extend AutowiredComposer :

  • View
  • Controller
<window id="win" title="Auto wire Composer" border="normal"
	apply="composer.MyAutowireComposer" width="300px">
	<listbox id="list" width="200px" rows="5" />
	<separator />
	<textbox id="text" value="Click to get value" width="200px"
		forward="onFocus=onFocusName" />
</window>
public class MyAutowireComposer extends GenericAutowireComposer {
	private Listbox list ;
	private Textbox text ;

	public void doAfterCompose(Component comp) throws Exception {
		super.doAfterCompose(comp);
		DataResource dr = new DataResource();
		ListModel lm = dr.getCustomers();
		list.setModel(lm);
	}

	public void onFocusName(Event event) {
		text.setValue("Dear : " + (list.getSelectedItem() == null ? "Null" : 
						list.getSelectedItem().getValue().toString()));
	}
}


  • Pros and Cons
Pros
  • The class in controller don't have to extend the view component.
Cons
  • The model of listbox was set in the controller (it should be set in view).

Now - Fusion Them All

Intro Fusion Invoker

This is a new feature in ZK 3.5.2, which realize the proxy design pattern by using Dynamic Proxy Classes. In ZK's cases, it can fusion some objects' interfaces into one object then we can use it anywhere.


How to use

In the example case, we want to use $ {win.customers} to get the data from window in the zul file , so we have to fusion Window and DataResource together.


First: Interfaces
Window already have interfaces so we have to create DataInterface and implement it in DataResource only.
public interface DataInterface {
	public ListModel getCustomers();
	
}


Second: Composer
In the life cycle of ZK, the EL will parse the $ {...} before the component be rendered, so we have to create a special composer which implement the ComposerExt Interface. Then implement doBeforeComposeChildren in ComposerExt.
abstract public class FusionComposer extends GenericAutowireComposer implements ComposerExt {
		...
		...
}
Notice : if you don't know what is Composer or AutowireComposer, you might want to take a look the articles beforehand.


Third: Usage
Using FusionInvoker in the composer of window.
import org.zkoss.lang.reflect.FusionInvoker;
FusionInvoker.newInstance(new Object[] { ... });

The static method "newInstance" will return an object which contains the interfaces of given objects. In the case below, we can modify the code like following :

  • View
<window id="win" title="Fusion Composer" border="normal"
	 apply="composer.MyFusionComposer" width="300px">
	<listbox id="list" width="200px" model="$ {win.customers}" rows="5" />
	<separator />
	<textbox id="text" value="Click to get value" width="200px"
		forward="onFocus=onFocusName" />
</window>


  • Controller
public class MyFusionComposer extends FusionComposer {
	private Listbox list;
	private Textbox text;

	public void doBeforeComposeChildren(Component cmp) throws Exception {
		super.doBeforeComposeChildren(cmp);
		DataResource dr = new DataResource();
		Object obj = FusionInvoker.newInstance(new Object[] { cmp, dr });
		//set the new object to original component's name then we can use it by EL
	   cmp.setVariable(cmp.getId(), obj, true);
	}

	public void onFocusName(Event event) {
		text.setValue("Dear : "
				+ (list.getSelectedItem() == null ? "Null" : list
						.getSelectedItem().getValue().toString()));
	}
}


  • Pros and Cons
Pros
  • Better separate view and controller
Cons
  • Must create interface for class we want to fusion


Appendix

  • Life cycle of Composer

Composer.PNG

  • Related Article


  • Download




Copyright © Potix Corporation. This article is licensed under GNU Free Documentation License.
You got stuck here?
Let us know why!
For questions please use the forum