Skip to main content

By clicking Submit, you agree to the developerWorks terms of use.

The first time you sign into developerWorks, a profile is created for you. Select information in your profile (name, country/region, and company) is displayed to the public and will accompany any content you post. You may update your IBM account at any time.

All information submitted is secure.

  • Close [x]

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerworks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

By clicking Submit, you agree to the developerWorks terms of use.

All information submitted is secure.

  • Close [x]

Integrate the rich Internet application framework ZK with Informix to build real-world applications

Rapid web application development for Informix

Timothy Clare (timothyclare@zkoss.org), Technology Evangelist, Potix Corp.
Photo of author Timothy Clare
Timothy Clare is a Technology Evangelist for the Potix Corporation which produces the ZK Framework. He has been working with various web and mobile technologies for over 10 years.
Sachin K Mahajan , Consultant, IBM  
Sachin Mahajan photo
Sachin Mahajan graduated with a Masters degree from University of Utah, Salt Lake City, Utah. He has worked in small and large-sized companies in the U.S. and India performing various technical and managerial roles.

Summary:  This tutorial presents a real-world example that integrates IBM® Informix® and ZK, a rich Internet application (RIA) framework. Informix is a flagship IBM RDBMS product, while ZK is a Java-based web application framework supporting Ajax applications. This event-driven framework enables creation of rich user interfaces with minimal knowledge and use of JavaScript. ZK's unique server-centric approach enables synchronization of components and events across the client and server via the core engine.

Date:  18 Aug 2011
Level:  Intermediate PDF:  A4 and Letter (111 KB | 28 pages)Get Adobe® Reader®

Activity:  55479 views
Comments:  

Implementing the controller

This section provides a step-by-step guide of the controller and its functions. The controller handles all the business logic of the application and responds to events fired from the user interface. Currently, the sample application includes add, update and delete events for both the employees and the departments.

Defining a controller

To create a controller, the class org.zkoss.zk.ui.util.GenericForwardComposer should be extended. An example controller is shown in Listing 13.


Listing 13. Example controller

public class MainController extends GenericForwardComposer {
	private static final long serialVersionUID = -3135206455666969851L;	
}

The composer then needs to be associated with a relevant view. Previously, the use of apply was touched upon in Nesting ZK components. In the following section the relationship is outlined in more detail.

Associating the controller with the view

To implement the interaction between the view and controller, data binding is used in this example. To implement data binding the apply attribute of a component has to be set. Most components support the apply attribute.

Listing 14 demonstrates the use of the apply attribute. The MainController is responsible for handling the user flow. In this example it was decided that a tabbox would be used, and the user would change between the department and employee tab. The code of MainController is demonstrated in Listing 15.


Listing 14. Main.zul

<?page title="Welcome to the employee demo!" contentType="text/html;charset=UTF-8"?>
<window id="win"  title="Welcome to the employee demo!" border="normal" 
apply="org.zkforge.controllers.MainController">
	<tabbox hflex="true" id="tbTabs">
        <tabs>
            <tab label="Employees" />
            <tab label="Departments" />
        </tabs>
        <tabpanels>
        	<tabpanel>
        		<include mode="defer" src="/module/employees.zul" />
        	</tabpanel>
        	<tabpanel>
        		<include mode="defer" src="/module/departments.zul" />
        	</tabpanel>
        </tabpanels>
    </tabbox>
</window>

Listing 15 introduces how to capture an event and invalidate a component.


Listing 15. MainController.java

public class MainController extends GenericForwardComposer {
	private static final long serialVersionUID = -3135206455666969851L;	
	Tabbox tbTabs;
	public void onSelect$tbTabs(ForwardEvent e) {
		Object o = e.getOrigin().getTarget();
		if (o instanceof Tab) {
			Tab t = (Tab)o;
			Tabpanel tp = t.getLinkedPanel();
			tp.invalidate();
		}
	}
}

Capturing events

Event capturing in ZK is easy to implement and provides developers with enormous power. Listing 16 shows a function signature to capture the onSelect event from the tabbox tbTabs. The onSelect event is fired when a user changes tabs.

The method signature can be broken down into three parts. Firstly, the return type is void and method is public. The method name consists of the event name, followed by a dollar sign ($) and the name of the component who’s event you want to trap. Then lastly in this case the event type is a ForwardEvent. Using this technique it is possible to trap any event from any ZK component in a composer which is properly wired to the view.


Listing 16. Function signature for event capturing

	public void onSelect$tbTabs(ForwardEvent e)

Why invalidate a component (reloading an include)?

The topic of why to invalidate is relevant in the scope of the application. However the question is based on a more significant question: How do you share the database information among different controls and make sure that they are all updated?

One of the best ways of doing this is to implement a shared list of database items among all concurrent clients accessing the resources. This implementation should be thread safe and is easily achievable in ZK. However, for the purposes of this tutorial it would introduce unnecessary complication that may cause confusion.

Therefore the decision was made to keep the departments and employees separated and to reload each tab's contents when switching. Thus, any information will be reloaded by the database.

Consequently, you need to bear this in mind when reviewing the decisions made in this section.


Listing 17. Switching tabs

	public void onSelect$tbTabs(ForwardEvent e) {
			Object o = e.getOrigin().getTarget();
			
			if (o instanceof Tab) {
				Tab t = (Tab)o;
				Tabpanel tp = t.getLinkedPanel();
				tp.invalidate();
			}
		}

Listing 17 shows the relevant code from the MainController. The first line of the method retrieves the original event and then retrieves the target of the event. In this case it is a Tab of the tabbox.

The Tabpanel of the Tab is then retrieved. A Tabpanel is the area where components are rendered in the tabbox, and each Tab has an associated Tabpanel. In this case the Tabpanel is then invalidated.

You should remember that the contents of the Tabpanel was in fact the include component which includes departments.zul and employee.zul respectively. In addition, as the include mode of each was set to defer, the zul is requested again through the servlet, and the data of each is reloaded.

Using databinding to load data from Informix

To fully explain data binding, only one of the two zul files, either departments.zul or employee.zul, are of relevance. For this tutorial employee.zul will be discussed because it is the more complex of the two.

The view is tied to the controller using the apply attribute as discussed in Associating the Controller with the view. Now the data binding mechanism of ZK needs to be activated for this page. Remember, due to the include mode being deferred, each zul is considered a separate entity. This means that they can each have their own data binding instance. To initialize the Annotated data binder, use the line shown in Listing 18.


Listing 18. Initialize the databinder

<?init class="org.zkoss.zkplus.databind.AnnotateDataBinderInit" root="./departmentdiv"?>

Employee.zul and EmployeeController.java functionality, step by step

To make it easier to explain how data binding works, Listing 19 contains the complete source of employees.zul. This tutorial will now step through each relevant part and include, where necessary, the relevant parts of the applied controller.


Listing 19. employees.zul complete code

<?init class="org.zkoss.zkplus.databind.AnnotateDataBinderInit" root="./employeediv"?>
<div id="employeediv" apply="org.zkforge.controllers.EmployeeController"
	hflex="true">
	<listbox id="lstEmployee" multiple="false" rows="5"
		model="@{employeediv$composer.getAllEmployees, 
        load-after='btnAddEmployee.onClick, 
        btnDeleteEmployee.onClick, btnUpdateEmployee.onClick'}"
		selectedItem="@{employeediv$composer.currentEmployee}">
		<auxhead>
			<auxheader label="Employees" colspan="4" />
		</auxhead>
		<listhead>
			<listheader label="ID" width="150px" />
			<listheader label="First Name" width="300px" />
			<listheader label="Last Name" width="300px" />
			<listheader label="Age" width="150px" />
		</listhead>
		<listitem self="@{each='employee'}" value="@{employee}">
			<listcell label="@{employee.id}" />
			<listcell label="@{employee.firstName}" />
			<listcell label="@{employee.lastName}" />
			<listcell label="@{employee.age}" />
		</listitem>
	</listbox>
	<groupbox>
		<caption label="Employee" />
		First Name:
		<textbox id="txtFirstName" cols="25"
			value="@{employeediv$composer.currentEmployee.firstName}" />
		Last Name:
		<textbox id="txtLastName" cols="25"
			value="@{employeediv$composer.currentEmployee.lastName}" />
		Age:
		<intbox id="intAge" cols="1"
			value="@{employeediv$composer.currentEmployee.age}" />
		Department:
		<listbox id="lstDepartment" mold="select"
			model="@{employeediv$composer.getAllDepartments}"
			selectedItem="@{employeediv$composer.currentEmployee.department}">
			<listitem self="@{each='department'}"
				label="@{department.name}" />
		</listbox>
		<button id="btnAddEmployee" label="Add" width="36px"
			height="24px" />
		<button id="btnUpdateEmployee" label="Update" width="46px"
			height="24px" />
		<button id="btnDeleteEmployee" label="Delete" width="46px"
			height="24px" />
	</groupbox>
</div>

Data binding initialization in employees

Initialization of data binding is the first line that is needed. However, there is a difference between the line demonstrated in Listing 18 and the one outlined in Listing 19. Notice the addition of an extra attribute named root. This root attribute takes a component name and states that the data binder is only initialized for that component and its children. Thus in this situation the annotated data binder’s root component is the div component with id of departmentdiv. Listing 20 demonstrates the relevant line.


Listing 20. Initialize the databinder

<?init class="org.zkoss.zkplus.databind.AnnotateDataBinderInit" root="./departmentdiv"?>

Loading the data from the controller

It is time to start populating data. This is done by binding t controller functions for retrieving the model’s data with our listbox. The complete listbox zul is outlined in Listing 21.


Listing 21. The listbox with databinding

<listbox id="lstEmployee" multiple="false" rows="5"
model="@{employeediv$composer.getAllEmployees, load-after='btnAddEmployee.onClick, 
    btnDeleteEmployee.onClick, btnUpdateEmployee.onClick'}"
		selectedItem="@{employeediv$composer.currentEmployee}">
		<auxhead>
			<auxheader label="Employees" colspan="4" />
		</auxhead>
		<listhead>
			<listheader label="ID" width="150px" />
			<listheader label="First Name" width="300px" />
			<listheader label="Last Name" width="300px" />
			<listheader label="Age" width="150px" />
		</listhead>
		<listitem self="@{each='employee'}" value="@{employee}">
			<listcell label="@{employee.id}" />
			<listcell label="@{employee.firstName}" />
			<listcell label="@{employee.lastName}" />
			<listcell label="@{employee.age}" />
		</listitem>
	</listbox>

The controller source code in model="@{employeediv$composer.getAllEmployees}" and selectedItem="@{employeediv$composer.currentEmployee}" have returned a list of type Employee, and a bean of type Employee respectively. The code snippet for this is shown in Listing 22.


Listing 22. EmployeeController source snippet - getAllEmployees and CurrentEmployee

public List<Employee> getAllEmployees() {
		try {
			return _empDAO.getAll();
		} catch (SQLException e) {
			UiUtils.showMessage(e.getMessage());
			log.error(e);
		}
		
		return null;
	}

public Employee getCurrentEmployee() {
		return _currentEmployee;
	}

public void setCurrentEmployee(Employee e) {
		this._currentEmployee = e;
	}

The controller’s method that is responsible for retrieving all employee data is named getAllEmployees(). This method can be accessed in the view by setting the listbox model attribute to e mployeediv$composer.getAllEmployees, as outlined in Listing 23.


Listing 23. Binding for getAllEmployees

model="@{employeediv$composer.getAllEmployees}”

The data binding expression can be broken down. Note that the expression beginning with employeediv, which is the name of the root component, also contains the apply attribute. It is then followed by a dollar sign and composer.

When ZK evaluates this, it means it is looking for the component with id employeediv and retrieving its composer.

A period (.) is then appended and followed by the function name that is to be accessed. This will assign the model to the result of the getAllEmployees function in the controller.

Secondly, the line shown in Listing 24 uses the same mechanism to retrieve the reference for employeediv’s composer. It is then followed by currentEmployee.


Listing 24. Databinding selected item

	selectedItem="@{employeediv$composer.currentEmployee}"

You should also note that Listing 24 outlines a function and a bean named currentEmployee. This demonstrates the data that binds the syntax to access beans and functions differs. This is outlined in Table 3.


Table 3. Data binder access to the controller
Access identifierDescription
fullFunctionNameTo access a function in the controller through data binding, it is necessary to use the full function name
beanNameWhen accessing a bean from the controller, it is only required to use the bean name. There is no need to include get or set. However, the bean in question must have both.

The attribute selectedItem is set to keep track of which bean is selected from the listbox. When the selection is changed, ZK will automatically update the bean accordingly.

Displaying the data

To display the data within a listbox, you will need a template. By creating a template, such as the one outlined in Listing 25, the listbox can effectively represent the data.


Listing 25. Listbox display template

<listhead>
	<listheader label="ID" width="150px" />
	<listheader label="First Name" width="300px" />
	<listheader label="Last Name" width="300px" />
	<listheader label="Age" width="150px" />
</listhead>
<listitem self="@{each='employee'}" value="@{employee}">
	<listcell label="@{employee.id}" />
	<listcell label="@{employee.firstName}" />
	<listcell label="@{employee.lastName}" />
	<listcell label="@{employee.age}" />
</listitem>

The data is bound to and rendered within the listbox. This is achieved by utilizing the self attribute of the listitem to assign variables which would each represent an employee. The data binder will then loop through each employee and output the template code shown in Listing 25. Each listcell will therefore be bound to the respective bean and its mutators.

A similar methodology is applied to the components in the group box which represent the selected item. Each one of them is bound to specific data of the currentEmployee bean using techniques discussed throughout this section. Therefore, as the currentEmployee changes when selecting a different employee in the listbox, the relevant textboxes are also updated. Also note that there is a listbox in the select mold that follows the same conventions we have discussed in Employee.zul. These techniques apply throughout ZK.

The relevant extract is shown in Listing 26.


Listing 26. Extract showing currentEmployee information

First Name: <textbox id="txtFirstName" cols="25"
		value="@{employeediv$composer.currentEmployee.firstName}" />
Last Name: <textbox id="txtLastName" cols="25"
			value="@{employeediv$composer.currentEmployee.lastName}" />
Age: <intbox id="intAge" cols="1"
			value="@{employeediv$composer.currentEmployee.age}" />
Department: <listbox id="lstDepartment" mold="select"
			model="@{employeediv$composer.getAllDepartments}" 
            selectedItem="@{employeediv$composer.currentEmployee.department}">

You have loaded and output the data, so it is time to start manipulating it.

CRUD operations on the UI

So far the data has been loaded and displayed, but the whole point of web applications is to manipulate data. Hence add, create, update and delete methods need to be created. This is achieved by using the three buttons shown in Listing 27.


Listing 27. CRUD buttons

<button id="btnAddEmployee" label="Add" width="36px"
			height="24px" />
		<button id="btnUpdateEmployee" label="Update" width="46px"
			height="24px" />
		<button id="btnDeleteEmployee" label="Delete" width="46px"
			height="24px" />

These buttons are tied to functions in the controller that capture the events. The functions are outlined in Listing 28.


Listing 28. Controller click events

//click events
	public void onClick$btnAddEmployee() {
		if(lstDepartment.getSelectedItem() != null) {
			String firstName = txtFirstName.getText();
			String lastName = txtLastName.getText();
			Department dep = null;
			int iAge = Integer.parseInt(intAge.getText());
			
			Selectable selectable = (Selectable)lstDepartment.getModel();
			Set<?> selectedSet = selectable.getSelection();
			
			if (selectedSet.size() == 1) {
				dep = (Department)selectedSet.toArray()[0];
			}
			
			Employee employee = new Employee(firstName + lastName + 
            UUID.randomUUID(), //id
									  firstName,
									  lastName,
									  iAge,
									  dep);
			
			try {
				_empDAO.insert(employee);
			} catch (SQLException e) {
				UiUtils.showMessage(e.getMessage());
				log.error(e);
			}
		}
		else {
			UiUtils.showMessage("Please select a department!");
		}
			 
	}
	
	public void onClick$btnUpdateEmployee() {
		if((lstDepartment.getSelectedItem() != null)
			&& (lstEmployee.getSelectedItem() != null)) {
			
			Employee employee = 
              (Employee)(lstEmployee.getSelectedItem().getValue());
			
			try {
				_empDAO.update(employee);
			} catch (SQLException e) {
				UiUtils.showMessage(e.getMessage());
				log.error(e);
			}
		}
		else {
			UiUtils.showMessage("Please select an employee and department!");
		} 
	}
	
	public void onClick$btnDeleteEmployee() {
		
		if(lstEmployee.getSelectedItem() != null) {
			Employee employee = 
              (Employee)(lstEmployee.getSelectedItem().getValue());
			
			try {
				_empDAO.delete(employee);
			} catch (SQLException e) {
				UiUtils.showMessage(e.getMessage());
				log.error(e);
			}
		}
		else {
			UiUtils.showMessage("Please select an employee!");
		}
			 
	}

Listing 28 highlights the business logic behind the CRUD operations. Most of these are self explanatory and are basic Java calls. One item you may notice is that each component is referenced directly from the code.

To enable this function, you only needs to specify the component type and its id in the controller and ZK will do the rest through automatic wiring. For example, Listing 29 shows that declarations are enough to make access to components possible from Listing 28.


Listing 29. Component declarations

Listbox lstEmployee;
	Listbox lstDepartment;
	
	//text boxes
	Textbox txtFirstName;
	Textbox txtLastName;
	
	//int boxes
	Intbox intAge;

The last talking point is how ZK would know to update the listbox model after updating, adding, or deleting an item. This is simply a matter of assigning load-after in the model attribute on the listbox to the relevant button events that update the model. When one of these events are fired, the model will be reloaded. Listing 30 demonstrates the code necessary for this. Breaking it down, it is as simple as specifying the component id followed by a period (.), and the event name.


Listing 30. Load-after

model="@{employeediv$composer.getAllEmployees, 
load-after='btnAddEmployee.onClick, btnDeleteEmployee.onClick, 
btnUpdateEmployee.onClick'}"

4 of 9 | Previous | Next

Comments



static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Information Management, Open source, Web development, Java technology
ArticleID=752700
TutorialTitle=Integrate the rich Internet application framework ZK with Informix to build real-world applications
publish-date=08182011
author1-email=timothyclare@zkoss.org
author1-email-cc=
author2-email=sachin.mahajan@in.ibm.com
author2-email-cc=