DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones AWS Cloud
by AWS Developer Relations
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones
AWS Cloud
by AWS Developer Relations
  1. DZone
  2. Coding
  3. Languages
  4. Using Desktop MVC Patterns with ZK, Spring & JPA

Using Desktop MVC Patterns with ZK, Spring & JPA

Simon Massey user avatar by
Simon Massey
·
Mar. 12, 09 · Interview
Like (0)
Save
Tweet
Share
54.04K Views

Join the DZone community and get the full member experience.

Join For Free

In this article I will discuss the "ZkToDo2" sample application that demonstrates desktop MVC patterns using the ZK RIA AJAX framework, Spring and JPA. The Spring and JPA configuration used in this article are adapted from the persistence add-on of the Loom framework. My thanks go to Ignacio Coloma and his collaborators on Loom for their well documented and discussed JPA code.

ZK is a mature, opensource, pure Java Rich Internet Application (RAI/AJAX) framework hosted on SourceForge. The unique feature of ZK is that you use XML (ZUL/XHTML) to describe a Java desktop that is translated into browser specific AJAX enabled DHTML. All UI events triggered in the web browser DOM are sent via AJAX to the server where Java event handlers are executed. Within the AJAX event handers any changes that you make to the Java desktop are sent back to the browser where the DOM is updated. As the user interface logic is programmed as Java event handlers the developer is free from the distractions of cross browser DHTML JavaScript programming. Instead the ZK framework provides the cross browser DHTML and JavaScript. The developer is free from having to write code to bridge the browser-to-server divide and can focus on what is unique to their application rather than having to write a large amount of "boiler plate" code. A pure Java approach also means that you can debug your user interface code within your favourite IDE.

Obtaining & Building The Sample Code

Typically setting up an environment to try out J2EE sample code can be an in-depth and time consuming experience. The ZkToDo2 sample code hosted on SourceForge under the ZKForge project aims to be self installing to make it easy to debug and explore the running code. All you need is the Maven build system (a powerful successor to Ant) or a Maven plug-in for your chosen IDE. Maven will download all of the dependant jars, compile the code, test the code and will run an embedded Servlet container with an embedded database with a single command. The steps to checkout, build, run and debug the application using Eclipse with the m2eclipse Maven plug-in are here. Alternatively if you would like to build and run the application on the command-line using only a stock Maven distribution and attached a remote debugger then follow the instructions here.

Domain Object & Database Bindings

Here is an extract of the domain class and it's mapping into the database:

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "REMINDER")
public class Reminder {
@Id @GeneratedValue
@Column(name = "EVENT_ID")
private Long id;

@Column(name = "NAME")
private String name;

@Column(name = "PRIORITY")
private int priority;

@Column(name = "DATE")
private Date date;
...

The database binding annotations used within the class are from the javax.persistence package. This means that they will work with any JPA implementation such as EclipseLink, Hibernate, OpenJPA or TopLink to name just a few. The state held in each domain object will be persisted to the database by the BasicDao class detailed below. First we will look at the user interface and its controller class that displays and updates the reminder objects stored within the database.

The User Interface

The user interface of ZkToDo2 is defined in a single file zktodo_b.zul. Here is a screenshot of the fully AJAX enabled web page defined in this file:

The entire user interface is the following XML markup:

<?xml version="1.0" encoding="UTF-8"?>
<zk xmlns="http://www.zkoss.org/2005/zul">
<?init class="org.zkoss.zkplus.databind.AnnotateDataBinderInit" ?>
<?variable-resolver class="org.zkoss.zkplus.spring.DelegatingVariableResolver"?>
<window title="To do list" width="640px" border="normal" apply="${toDoControllerV2}">
<listbox id="list" multiple="true" rows="4" model="@{toDoModel.reminders}" selectedItem="@{toDoModel.selectedReminder}">
<listhead>
<listheader label="Item" />
<listheader label="Priority" width="80px" />
<listheader label="Opened" width="90px" />
</listhead>
<listitem self="@{each=reminder}">
<listcell label="@{reminder.name}"/>
<listcell label="@{reminder.priority}"/>
<listcell label="@{reminder.date, converter='org.zkforge.zktodo2.DateFormatConverter'}"/>
</listitem>
</listbox>
<vbox>
<hbox>
Item:<textbox id="name" cols="40" constraint="no empty" value="@{toDoModel.selectedReminder.name}"/>
Priority:<intbox id="priority" cols="1" constraint="no empty" value="@{toDoModel.selectedReminder.priority}"/>
Date:<datebox id="date" cols="14" constraint="no empty" value="@{toDoModel.selectedReminder.date}"/>
</hbox>
<hbox>
<button id="add" label="Add" width="36px" height="24px"/>
<button id="update" label="Update" width="46px" height="24px"/>
<button id="delete" label="Delete" width="46px" height="24px"/>
</hbox>
</vbox>
</window>
</zk>

The XML dialect is ZUML the ZK User Interface Markup Language. ZUML can be a mixture of XHTML, ZUL (the ZK XUL dialect) and arbitrary XML. The ZK framework supports 170+ off-the-shelf state-of-art XUL or HTML compliant Ajax components and numerous third party widgets: JFreeChart, JasperReports, Google Maps, FCKeditor, Timeline, Timeplot, ExtJS, Dojo to name a few. The screenshot above uses the default ZK look-and-feel but you can define your own CSS-based skin or HTML template-based look-and-feel. You can even just use your corporate XHTML web pages and simply add a few Java enabled XUL textboxes, dateboxes and intboxes that render as plain old HTML form elements. The ZK demo shows many of the components on offer. You can even edit the ZUML on the "View Source" tabs then click the "Try Me!" button below the source to render your changes.

Within the markup a special declarative databindings syntax ("@{binding}") is used to bind the UI to our Java code. Within the application the JPA Annotations provide a declarative binding between our POJOs and the database tables. The ZK databindings feature provides a similar capability to declaratively bind our POJOs to the UI Components. This feature will be discussed later on in this article.

The Application Layering

The layering of the UI controller bean, application model bean, service bean and data access bean is defined within the Spring configuration file as follows:

    <bean id="basicDao" class="org.zkforge.zktodo2.BasicDao" />

<bean id="reminderService" class="org.zkforge.zktodo2.ReminderService"
p:basicDao-ref="basicDao"
/>

<bean id="toDoModel" class="org.zkforge.zktodo2.ZkToDoModelImpl"
p:reminderService-ref="reminderService" scope="session"/>

<bean id="toDoControllerV2" class="org.zkforge.zktodo2.ZkToDoControllerV2"
p:toDoModel-ref="toDoModel" scope="prototype"
/>

The controller is provided with a model bean. The model bean is provided with a service bean. The service bean is provided with a data access bean. The service bean and data access bean have default scope so they will be singleton objects. The model bean has session scope. This will cause Spring to keep one and only one instance of the bean associated with the users HTTP session. The controller bean has prototype scope. This causes a new bean to be instantiated for each page that is rendered. Setting the scopes in this manner allows the model bean and the controller beans to be stateful. The control beans state is related to the Java Desktop defined within the page. The model beans state is related to the users web session and may be shared across many screen controllers in a large application.

The ZkToDo2 sample application is very small with only one bean in each layer and a 1-to-1 relationship between each layer. Within a larger application there would be multiple beans in each layer across the width of a complex application. The layering then allows for 1-to-many, many-to-1 and many-to-many configurations to encourage maximum code re-use and a clear separation of responsibility between classes and layers of the application.

The Controller Class

The above ZUML screen file defines an inert page with no application behaviours. Behaviour is to be provided by our controller class. The window tag has an "apply" attribute set to "${toDoControllerV2}". This requests that the ZK framework pre-processes the Java Window object of the Java Desktop with the object referenced by the variable toDoControllerV2. The Spring variable resolver has been included near the top of the page. The introduction of the Spring variable resolver gives a complete integration with the spring framework. All we need to do is define beans within Spring's configuration and we can reference beans by name within our ZUML screen file. The toDoControllerV1 bean is defined by this entry within the file spring-config.xml:

<bean id="toDoControllerV2" class="org.zkforge.zktodo2.ZkToDoControllerV2" 
p:toDoModel-ref="toDoModel" scope="prototype"/>

The class of the toDoControllerV2 bean is ZKToDoControllerV2. The scope of the bean is "prototype". This means that Spring will instantiate a new bean each and every time ZK asks for a bean of that name. This occurs each time the ZUML page is loaded. The controller configuration specifies that it requires a bean named "toDoModel". The bean "toDoModel" is also referenced within the ZUML file. Here is an extract of the controller class:

public class ZkToDoControllerV2 extends GenericForwardComposer {

protected Textbox name;
protected Intbox priority;
protected Datebox date;
protected Listbox list;
protected ListModelList listModelList;

public void onClick$add(org.zkoss.zk.ui.event.Event e) {
// ...
}
public void onClick$update(org.zkoss.zk.ui.event.Event e) {
// ...
}

public void onClick$delete(org.zkoss.zk.ui.event.Event e) {
// ...
}
}

ZkToDoControllerV2 subclasses GenericForwardComposer. GenericForwardComposer is an optional ZK support class explicitly designed to support the MVC pattern. Code within the GenericForwardComposer class will automatically wire our ZkToDoControllerV2 controller object to the user interface components defined within the ZUML file. The autowiring is done via ZK matching the names and types within our Java class to the XML elements and IDs defined within our ZUL file.

If we compare the Java and ZUML listings above we find matches for "name", "priority", "data" and "list". In addition the types within the Java code match the Components defined within the ZUL file. ZK will inject references to the named screen Components into our controller class. The Java listing also defines three event handlers. The signatures of the event handlers are similar to the standard ZK "onClick" event handler. The method names start with "onClick" and end with the ID of a button defined within the ZUL file. ZK will bind the three controller methods as event handlers on the corresponding button components. Without any JavaScript AJAX programming when the user clicks on the buttons of our user interface our pure Java code will run on the server.

The Service & Data Layers

Here is an extract of the ReminderService class:

public class ReminderService {

@Transactional(readOnly=true)
public List findAll(){
List events = this.basicDao.findAll(Reminder.class);
return(List) events;
}

@Transactional(readOnly=false,propagation = Propagation.REQUIRED)
public void persistEvent(Reminder reminder){
this.basicDao.persist(reminder);
}

@Transactional(readOnly=false,propagation = Propagation.REQUIRED)
public void deleteEvent(Reminder reminder) throws EntityNotFoundException {
this.basicDao.remove(Reminder.class, reminder.getId());
}

@Transactional(readOnly=false,propagation = Propagation.REQUIRED)
public void mergeEvent(Reminder reminder) throws EntityNotFoundException {
this.basicDao.merge(reminder);
}
}

The reminderService has Spring transaction annotations to define the transactional semantics of the business logic. The sample application is very simple and does not define many database operations within each service method. In a larger system that must perform a set of data operations in an atomic manner the use of transactions would be of greater importance to ensure data integrity. The transaction annotations are activated by a single line in the spring-config.xml file:

<tx:annotation-driven />

This tx annotation tag does not name a specific transaction manager to use. So by convention Spring will use a bean called transactionManager to honour the transaction annotations of the service bean. We may wish to change the transaction manager and data source between running JUnit tests within an IDE and deployment to an application server. So these beans are separated out into a file called dataSourceContext.xml.

The final part of the spring configuration is the JPA EntityManagerFactory:

<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
p:persistence-xml-location="classpath:META-INF/persistence.xml"
p:data-source-ref="dataSource"
>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"
p:showSql="true"
p:generateDdl="true">
</bean>
</property>
<property name="jpaProperties">
<value>
hibernate.ejb.naming_strategy=org.hibernate.cfg.ImprovedNamingStrategy
hibernate.dialect=
hibernate.hbm2ddl.auto=
</value>
</property>
</bean>

<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />

The configuration defines a Hibernate JPA EntityManagerFactory that uses our dataSource bean defined within dataSourceContext.xml. The use of PersistenceAnnotationBeanPostProcessor provides the glue between our JPA entity manager and our BasicDao bean.

The BasicDao class has been taken from the Loom framework source code along with the Spring+JPA configuration outlined above. The pagination support of the class has been removed as it was not required for this sample application. It is recommended that readers study the original Loom class and surrounding packages which provide richer behaviour than was needed to implement zktodo2.

The Model Classes

The model class encapsulates the state and behaviour of the business layers of the system. The model class is stateful in nature and can be reused amongst multiple screen and multiple controllers within a larger application. The model class utilizes the service layer of the application to sync its state with the database.

An explicit model interface for the sample application is here with the implementation here. The interface is shown below:

package org.zkforge.zktodo2;

import java.util.List;

public interface ZkToDoModel {

public abstract void deleteEvent(Reminder reminder)
throws EntityNotFoundException;

public abstract List findAll();

public abstract void mergeEvent(Reminder reminder)
throws EntityNotFoundException;

public abstract void persistEvent(Reminder reminder);

//used by selectedItem="@{controller.selectedReminder}" and others
public abstract Reminder getSelectedReminder();

//used by selectedItem="@{controller.selectedReminder}" and others
public abstract void setSelectedReminder(Reminder reminder);

//used by model="@{controller.reminders}"
public abstract List getReminders();

}

Notice that the Model class holds the "selected reminder" which is the reminder that the current user is editing.

ZK Databindings

Databindings are declarative bindings. Within the application the JPA Annotations provide a declarative binding between our POJOs and the database tables. The ZK databindings feature provides declarative bindings between POJOs and UI Components. An extract highlighting the databindings within the ZUML screen file is shown here:

...
<?init class="org.zkoss.zkplus.databind.AnnotateDataBinderInit" ?>
<?variable-resolver class="org.zkoss.zkplus.spring.DelegatingVariableResolver"?>
...
<listbox id="list" multiple="true" rows="4" model="@{toDoModel.reminders}" selectedItem="@{toDoModel.selectedReminder}">
<listhead>
<listheader label="Item" />
<listheader label="Priority" width="80px" />
<listheader label="Opened" width="90px" />
</listhead>
<listitem self="@{each=reminder}">
<listcell label="@{reminder.name}"/>
<listcell label="@{reminder.priority}"/>
<listcell label="@{reminder.date, converter='org.zkforge.zktodo2.DateFormatConverter'}"/>
</listitem>
</listbox>
...
Item:<textbox id="name" cols="40" constraint="no empty" value="@{toDoModel.selectedReminder.name}"/>
Priority:<intbox id="priority" cols="1" constraint="no empty" value="@{toDoModel.selectedReminder.priority}"/>
Date:<datebox id="date" cols="14" constraint="no empty" value="@{toDoModel.selectedReminder.date}"/>

In the listing above the page has an "init" instruction referencing the AnnotateDataBinderInit class. Preprocessing the page with AnnotateDataBinderInit causes the zul properties containing "@{binding}" declarative bindings to be bound onto the application POJOs. Collectively the databindings show how to render the initial state of the screen and how to write UI input from the edit area into the selected POJO.

The databindings for the Listbox initially reads from "@{toDoModel.reminders}" and writes to "@{toDoModel.selectedReminder}" when an item is selected from the list by the user. The variables are resolved to our Spring bean via the Spring variable resolver. ZK reflects on the class of the model bean and maps the bindings onto the methods "toDoModel.getReminders()" and "toDoModel.setSelectedReminder(...)" methods.

Within the Listbox there are bindings which define how to render each Reminder object into a set of Listcells within a Listitem. The self="@{each=reminder}" binding sets up a loop variable "reminder" that is set for each reminder within the list loaded from the database. For each reminder object in the list a new Listitem is instantiated. The bindings such as "@{reminder.name}" applied to the Listcells map the getters of the reminder object onto the setters on the Listcell objects.

Below the Listbox the selected reminder is rendered into the edit area using bindings such as "@{toDoModel.selectedReminder.name}". ZK resolves this to the "getName()" method of the selected reminder object.

Putting It All Together

The effect of the databindings is that when you load the page ZK will call the model bean method to load the reminders from the database and will then render them into the list. When the user clicks on a reminder within the list its data appears within the edit area. No bespoke code is required to do this as ZK does it automatically as directed by the databindings. If you edit the name of the reminder in the edit area, then tab away, the name of the reminder shown within the list changes. This is because both the listcell and edit area is bound to the POJO so ZK keeps all three in synch. ZK knows that the POJO name has changed so it will automatically update the ListCell at the same time as it updates the POJO. Once again no bespoke code has been written to achieve this effect.

It is also important to know that the Java POJO on the server has been updated. There is no "web page post" when writing user interfaces with ZK. The ZK framework has fired AJAX events asynchronously to the server and has called the setters on our Java objects without having to write a single line of Javascript or Java. ZK gives us the illusion that our Java desktop and application Java objects are being rendered directly into the browser window without any Servlet or DHTML programming. In reality ZK is implemented as a set of pure Servlets and a JavaScript library. The ZK developers have done all of the Servlet and DHTML programming to give us a pure Java Desktop programming environment that is "painted" into a browser window without any browser plug-ins.

When you click the Update button ZK will run the Java method of the controller class that it has automatically bound to the event handler of the button. The POJO is already on the server and has already been updated by ZK via AJAX when the user has input data into the edit area. There is no need to write any boiler-plate code to copy the strings out of a web-request and call setters on our POJO. As the POJO is already fully up to date we simply have to add code into the Java event handler of the controller to flush the modified POJO to the database. Here is the controller event handler method that is called when we click the Update button:

	public void onClick$update(Event e) {
Reminder selectedReminder = this.toDoModel.getSelectedReminder();
if( selectedReminder != null ){
ListModelList listModelList = (ListModelList)this.list.getModel();
try {
this.toDoModel.mergeEvent(selectedReminder);
} catch (EntityNotFoundException exception){
int index = list.getSelectedIndex();
listModelList.remove(index);
alert("Reminder "+selectedReminder.getName()+" has been deleted by another user.");
if( listModelList.size() > 0 ){
selectedReminder = (Reminder)listModelList.get(0);
list.setSelectedIndex(0);
name.setValue(selectedReminder.getName());
date.setValue(selectedReminder.getDate());
priority.setValue(selectedReminder.getPriority());
} else {
selectedReminder = null;
}
}
List reminders = toDoModel.findAll();
listModelList.clear();
listModelList.addAll(reminders);
}
}

The majority of the code of that method is dealing with the exceptional case of discovering that the reminder has been deleted from the database by another user. The actual bespoke code to take the user input and call our back-end Java business logic to persist the input to the database can be simplified down to a single line of code:

this.toDoModel.mergeEvent(this.toDoModel.getSelectedReminder());

As all of the DHTML and Servlet programming has been handled by the ZK framework and our databindings mark-up we are free to focus on what is unique to our application. The source code of the project contains no bespoke Servlet or DHTML code only pure Java business logic. The Update logic above is within our prototype scoped controller bean which Spring instantiated and injected with a model bean. ZK injected references to the Java desktop Components defined within the ZUML page. ZK also bound the Java event handlers of the Components within the Java desktop to the event handlers defined within our controller bean. The model bean was given session scope so it is bound to the HTTPSession. Spring injected into the model bean a service bean. The service bean was given transactional annotations such that Spring will roll-back any database changes if an exception is thrown within the service call. Spring injected the data access bean into the service bean and configured the data access bean with a JPA entity manager.

Summary

In this article we introduced the ZkToDo2 sample application. The application makes use of the ZK support class GenericForwardComposer which provides explicit support for the Model-View-Controller pattern. The user interface defined in the ZUL file was wired to the controller class of the application automatically by matching elements and IDs within the ZUL file to member variable names and types within the controller class.

Integration with the Spring framework was demonstrated using the ZK support class DelegatingVariableResolver. Spring was used to create application layering through configuration using its support for the Inversion-Of-Control pattern. Logical layers for the UI controller bean, an application model bean, a singleton service bean and a singleton data access bean were configured via Spring. These layers provide a clear separation of concerns between the classes of the application. Spring support for transaction management was used to configure the database transaction boundaries of the service bean. Spring support for JPA was used to connect an EntityManager to the data access bean that was injected into the service bean.

The ZkToDo2 sample application uses an explicit Model class and ZK databindings. The introduction of an explicit model class provides for better encapsulation of the application business logic to facilitate code re-use between controllers. The introduction of ZK databindings removed much of the boiler-plate code required to initialize the UI and update application POJOs with user input.

Spring Framework Database application Desktop (word processor) Java (programming language) Data access Web Service Object (computer science)

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • Best CI/CD Tools for DevOps: A Review of the Top 10
  • Public Key and Private Key Pairs: Know the Technical Difference
  • How To Best Use Java Records as DTOs in Spring Boot 3
  • Testing Repository Adapters With Hexagonal Architecture

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: