ZK With Spring JPA And A Model-View-Controller Pattern

Simon Massey, AVP, Marsh, The world's leading insurance broker and strategic risk advisor
November 3, 2008

Version

Applicable to ZK 3.5.0 and later.

Background

In this article we will introduce a refactored version of the ZK ToDo sample application using a Spring JPA database backend. The sample application "ZkToDo2" demonstrates the MVC approach documented by the MVC Patterns smalltalk. The MVC approach allows you to centralize application logic in one or more classes resulting in code which is easier to maintain over time.  

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. 

Why Spring & JPA? 

Data access within J2EE has had a long and colourful evolution. Seasoned programmers will have used a number of different persistence frameworks and techniques over the years. JPA has lately become a popular standard for Object Relational Mapping supported by a broad range of both opensource and commercial vendors. The Spring Frameworks support for JPA provides easy control over how different JPA vendor offerings can be configured and used within your application.

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 aims to be self installing to make it easy to run, 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 a 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 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 Controller

The user interface of ZkToDo2 is defined in a single file zktodo_a.zul file that is very similar to the original:

 
<?xml version="1.0" encoding="UTF-8"?>
<zk xmlns="http://www.zkoss.org/2005/zul">
<?variable-resolver class="org.zkoss.zkplus.spring.DelegatingVariableResolver"?>
<window title="To do list" width="640px" border="normal" apply="${toDoControllerV1}">
<listbox id="list" multiple="true" rows="4">
<listhead>
<listheader label="Item" />
<listheader label="Priority" width="80px" />
<listheader label="Opened" width="90px" />
</listhead>
</listbox>
<vbox>
<hbox>
Item:<textbox id="name" cols="40" constraint="no empty"/>
Priority:<intbox id="priority" cols="1" constraint="no empty"/>
Date:<datebox id="date" cols="14" constraint="no empty"/>
</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 rendering behaviours and event handlers of the original ToDo application have been removed. The screen file defines an inert page with no application state or behaviours. These are to be provided by our controller class. What is new is that the window tag has an "apply" attribute set to "". Spring is named as a variable resolver near the top of the page. The introduction of the spring variable resolver gives complete integration with the spring framework. All we need to do is define beans within Spring's configuration and we can reference this beans by name within our ZUL file.  The toDoControllerV1 bean is defined by this entry within the file spring-config.xml:  

	<bean id="toDoControllerV1" class="org.zkforge.zktodo2.ZkToDoControllerV1" 
p:reminderService-ref="reminderService" scope="prototype"
/>

The class of the toDoControllerV1 bean is ZKToDoControllerV1. The scope of the bean is "prototype". This means that Spring will instantiate a new bean each time ZK asks for a bean of that name. This occurs each time the zul page is loaded. The controller configuration specifies that it requires a "reminderService". The reminderService bean is defined elsewhere within the configuration file. Here is an extract of the controller class: 

public class ZkToDoControllerV1 extends GenericForwardComposer implements
ListitemRenderer {

public void doAfterCompose(Component comp) throws Exception {
super.doAfterCompose(comp);
// more initialization logic
}


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) {
// ...
}


public void render(Listitem listItem, Object data) throws Exception {
// ...
}
}

ZkToDoControllerV1 subclasses GenericForwardComposer and overrides it's doAfterCompose method. ZK passes the Window component of the user interface into the doAfterCompose method. It does this as the toDoControllerV1 bean was named in the "apply" attribute of the Window object within the zul file. The method first calls super.doAfterCompose to automatically wire our controller to the user interface inside the window object. The autowiring is done via ZK matching the names and types within our Java file to the XML elements and IDs defined within our ZUL file. 

If we compare the Java and ZUL 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.   

Our controller class implements the ListitemRenderer interface. Within the doAfterCompose method the controller sets itself as the listItemRenderer of the Listbox defined within the ZUL page. In this way our controller can define the logic of how to transfer state from our database bound objects into UI state.  

Lets take a more detailed look at two of the controller class methods:

 protected Reminder selectedReminder = null;

public void doAfterCompose(Component comp) throws Exception {
super.doAfterCompose(comp);
listModelList = new ListModelList();
List<Reminder> reminders = reminderService.findAll();
listModelList.addAll(reminders);
list.setModel(listModelList);
list.setItemRenderer(this);
list.addEventListener("onSelect", new EventListener(){
public void onEvent(Event e) throws Exception {
int index = list.getSelectedIndex();
selectedReminder = (Reminder) listModelList.get(index);
date.setValue(selectedReminder.getDate());
priority.setValue(selectedReminder.getPriority());
name.setValue(selectedReminder.getName());
return;
}});
}

public void render(Listitem listItem, Object data) throws Exception {
Reminder reminder = (Reminder) data;
new Listcell(reminder.getName()).setParent(listItem);
new Listcell(reminder.getPriority()+"").setParent(listItem);
new Listcell(dateFormat.format(reminder.getDate())).setParent(listItem);
}
Within the doAfterCompose method the controller configures the initial state of our page. If there are objects within the database they must be rendered into the listbox. To load objects from the database our controller invokes findAll on the rendererService bean. It then adds the objects loaded from the database into a ListModelList. The ListModelList is then set on the Listbox. This binds our database data to the user interface control.

Our controller class implements the ListitemRenderer interface. Within the doAfterCompose method the controller sets itself as the listItemRenderer of the Listbox defined within the ZUL page. In this way our controller can define the logic of how to transfer state from our database bound objects into UI state. For each item within the ListModelList ZK calls our render method passing both the model object and the Listitem instantiated for the current model object. Our controller code then creates Listcell components that are rendered into the current Listitem using the setParent method of the abstract Component class.

The last act of the controller initialization logic is to bind an onSelect EventListener onto the Listbox. This event handler resolves the corresponding database object within the ListModelList using the selectedIndex value of the Listbox. This object is set as the selectedReminder member variable. The update and delete event handlers make use of selectedReminder. The onSelect event handler also sets the textbox, intbox and databox values to match the state of the selected database object.

The Service & Data Layers

The layering of the UI controller 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="toDoControllerV1" class="org.zkforge.zktodo2.ZkToDoControllerV1"
p:reminderService-ref="reminderService" scope="prototype"
/>

The controller is provided with a service bean. The service bean is provided with a data access bean. The service bean has default scope so it will be a singleton object that will be injected into each controller object instantiated for each loaded ZUL page. The controller class makes use of the service to list database objects as outlined above. It also uses the service object within each of the EventListeners bound onto the buttons defined within the ZUL page. The EventListeners bound to the buttons provide logic to create, update or delete database objects.

Here is an extract of the ReminderService class:
 
public class ReminderService {

@Transactional(readOnly=true)
public List<Reminder> findAll(){
List<?> events = this.basicDao.findAll(Reminder.class);
return(List<Reminder>) 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 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. Our BasicDao bean uses persistence annotations:

@Repository
public class BasicDao {

private EntityManager entityManager;

@PersistenceContext
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}

...
The @PersistanceContext annotation will cause Spring to inject an EntiyManager taken from the EntityManagerFactory into 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 class and surrounding packages which provide richer behaviour than was needed to implement zktodo2. The methods of the BasicDao that perform the list, add, update and delete operations are shown below. They delegate straight through to the EntityManager class obtained from the EntityManagerFactory configured above:

	// Called to list a objects of a given type within the database
public <T> List<T> findAll(Class<T> clazz) {
return (List<T>)find("from " + clazz.getName());
}
// Called from findAll above
public <T> T find(Class<T> clazz, Serializable id) throws EntityNotFoundException {
T result = entityManager.find(clazz, id);
if (result == null) {
throw new EntityNotFoundException(clazz, id);
}
return result;
}
// Called to delete an object from the database
public <T> T remove(Class<T> clazz, Serializable id) throws EntityNotFoundException {
T instance = find(clazz, id);
entityManager.remove(instance);
return instance;
}
// Called to add an object to the database
public void persist(Object entity) {
entityManager.persist(entity);
}
// Called to update an object within the database
public <T> T merge(T entity) {
return entityManager.merge(entity);
}

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 beans, a singleton service bean and a singleton data access bean were to provide 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.

References

  • Four articles on MVC patterns and ZK are reflectionApi, mvc3, mvc2 and mvc.
  • Henri Chen introduces ZK+Hibernate in a smalltalk that builds upon a Hibernate "Event tutorial" 
  • Andrew Ho and Henri Chen introduced the Spring JDBC DAO and ZK zscript Spring support to create an "Events list" application. 
  • The ZK ToDo sample application on ZK Forge from which the screen for this article was taken
  • High Level MVC & POJOs with Swing using the TikeSwing framework are presented here. TikeSwing provides interesting insight into MVC desktop programming patterns that may be used by ZK programmers

The ZK DevGuide states "ZK doesn't enforce developers to use MVC or other design patterns. Whether to use them is the developer's choice"

Simon Massey  is Technical Design Authority of a pan-european risk trading platform for Marsh (London, UK) that is built on top of ZK and other leading opensource technologies. He was previously Technical Lead on three production systems at Marsh that use ZK since Q3 2006. Not having enough of ZK in his day job he is also a developer of the ZKFoodToGo, zlora and zktodo2 projects for ZK.forge which is okay as his girlfriend is preparing to debug his public sample apps.
Copyright c Simon Massey. This article is licensed under GNU Free Documentation License.
Comments
 
Bill Moore
2008-11-04

Great article. Thanks.

Hayward
2008-11-06

Excellent Article!

Where is the download though?

simon
2008-11-10

Hayward,

There is now a release file on sourceforge at https://sourceforge.net/project/showfiles.php?group_id=156140&package_id=298393&release_id=639540

Simon

Marcos de Sousa
2008-11-11

Congratulation,

It is really well explained and showed how to really accomplish MVC pattern with ZK and Spring.

simon
2008-11-11

All,

Henri gave me a tip on how to expose objects held by the controller bean to the AnnotateDataBinderInit class. This allows you to use ZK databindings syntax to tell ZK how to render the POJOs. You can browse the updated code here: https://zkforge.svn.sourceforge.net/svnroot/zkforge/trunk/zktodo2/ and the build instructions work as per the links in the article.

Under source control there is now a zktodo_b.zul that binds the list box to an object called 'model' that the controller exposes and the zul screen uses to render components from:

<?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="@{model.reminders}" selectedItem="@{model.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>

In that code the @{x.y} is the ZK databindings syntax. See the DevGuide, smalltalks and javadocs for details of this advanded "POJO to UI" bindings syntax. It does for screen rendering what JPA does for persistance.

The "model" object is exposed from within the ZkToDoControllerV2.doAfterCompose(...) method:

@Override
public void doAfterCompose(Component comp) throws Exception {
super.doAfterCompose(comp);
//expose the model to Data Binder, so we can access data defined in this controller
//via data binding @{model.xxx.yyy}
comp.setVariable("model", this.getToDoModel(), true);
}

The actual model is a spring bean that is injected into the controller class:

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

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

Both beans are prototypes so they can be stateful. The model class ZkToDoModel encapsulates the users view of the state of the system. It has list operations that it delegate through to the service class but also holds the users current selected reminder and any state that might is not yet flushed into the DB. The idea being that the model bean can be re-used between screens in a more complex application.

If you go through the new code you will see that it reduces the total amount of Java code. The controller no longer has to be a listItemRenderer and no longer needs to know how to do the intial rendering of the listbox. The only logic that is left in the controller is the add, update and delete logic. All the rendering logic is moved into the zul file.

Very neat. Thanks very much Henri!

robertpic
2008-11-13

First, great work.

It becomes perfect with annotations (for me).

I'll try some improvements for controller - there is no need to handle with the GUI-Elements with annotations.

/Robert

davidem
2008-11-17

Very good job Simon :)
Have you ever tried to use Groovy as the programming language for ZK applications ? I'm thinking about using ZK for the UI&Controller layers and Groovy+Grails(GORM) for the business&dao layers.. what do you think about it ?

simon
2008-11-18

Davidem,

Programming by convention (known as "autowiring" which is something mentioned in the article) is a good thing. Rails and Grails are all about that.

I am very pleased to see that there is a groovy zk plugin at http://grails.org/ZK+Plugin. It is often said that Grails is groovy+hibernate+spring. My article shows how to work with zk+hibernate+spring. ZK supports Groovy. So there are options depending on where you currently are and where you want to go.

I really do like the GORM approach. Last time I looked at using GORM outside of Grails it appeared to require an understanding of the internal workings of Grails. I would suggest that it is more useful to know Grails+ZK or ZK+Spring+Hibernate individually. So I would suggest using ZK as the presentation page to a Grails application rather than try to plug-in GORM as a persistence framework to your ZK+Spring app. Please do contact me via soureforge if I am wrong or out of date on this matter...

Personally I am more interested in introducing springmvc and spring webflow frameworks into the picture rather than moving over to Grails. That may say more about where I started out from than where I will ultimately end up...

davidem
2008-11-19

Hi simon :)
I'm not excited about the Zk plugin.. for what it seems to me after a few hours of 'gameplay', ther's a lot of work to do on Eclpse (my IDE of choice) in order to properly support the Groovy language (code completion and class lookups are completely missing!);
Btw, My idea is precisely to take advantage of GORM and Grails together; my intent is (I completely agree with you ) to see if it's possible to easily build applications using ZK in the UI and controller layers + Grails for the service and ORM layers.. this is the general idea.. But, as I already told you, I'm not particularly happy about the Groovy ZK plugin..
I'll take some time to experiment a bit; I like the conciseness and power of a dynamic language such as Groovy (I love the power of closures in particular!) but, when coding, I find invaluable the help of code completion and code lookups that my IDE usually offers to me.
As of springmvc and webflow I have to admit my complete ignorance, so maybe I'm definitely wrong, but I can't get the picture.. Aren't they controller-related technologies ? Aren't you bringing into play a potential conflict between controller layers (ZK and springmvc or webflow ) ?

Best regards
Davide

Marcos de Sousa
2008-11-27

Hi Simon,

Since you are using

<tx:annotation-driven />
, you don't need to use inject service to controller:
<bean id="toDoControllerV1" class="org.zkforge.zktodo2.ZkToDoControllerV1" 
	p:reminderService-ref="reminderService" scope="prototype"
	/>

because it is autowired (you don't need get and setter for RemimberService). For example:
public class ZkToDoControllerV1 extends GenericForwardComposer implements
	ListitemRenderer {

	.public ZkToDoControllerV1() {
    	}
    
        @Autowired
    	protected ReminderService reminderService;
        
        ...

}

I was expecting it (injecting spring controller to the view) to be available with use="mypackage.myclass", but there is not support in this way.

Cary
2008-12-11

Hi Simon. Nice article and very helpful. I've tied several pieces of the MVC together with other Spring stuff I've done. I have a question though regarding 2 way databinding.

I have a list page and a detail window for getting to the details of an employee. In the list page, I have a <listbox> that I've bound to a collection of Employees and it shows a few attributes. I've hooked the double click event to display a detail window to show all attributes.

With 2 way binding, if the user types in the input fields and changes data but then has an "oops" moment realizing they double clicked the wrong employee (or some other "never mind" situation), the model data has been changed and the list page could well/should reflect the changed data.

What is your advice on a best practice for rolling back the changes in the "never mind" scenario?

FWIW, I have a controller hooked to the UI with the apply attribute. It has services injected into it via Spring and those use Hibernate DAO's.

Thanks,
Cary

Cary
2008-12-12

I looked through the website and found the ZK CRUD Demo app that was extremely close to what I want to do...I've applied its techniques to my MVC based stuff and have gotten it to work.

Cary

angel figueroa
2008-12-13

Hi Simon, When i try the ZKTodo2, the spring report to me that there is no a persistance unit found reminder. Any Subjection ?

angel figueroa
2008-12-13

Hi,

When execute the application, in tomcat, the indicate the following errors

1. WARNING: Unable to find file (ignored): jndi:/localhost/ZkTodo2/
java.io.FileNotFoundException

When i try to execute : entityManager.persist(entity);
2.java.lang.IllegalArgumentException: Unknown entity: org.zkforge.zktodo2.Reminder

include the spring configuration.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
">

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

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

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

<bean id="ZkToDoModel" class="org.zkforge.zktodo2.ZkToDoModelImpl" p:reminderService-ref="reminder" scope="session">
<!--
// scoped proxy is commented out as only referenced by a prototype bean
// if you wanted to pass this bean to a singleton you need to include
// the following configurration.
<aop:scoped-proxy proxy-target-class="false"/>
-->
</bean>

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

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


<!--
JPA config
-->
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" p:persistence-xml-location="/META-INF/persistence.xml">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true"></property>
<property name="generateDdl" value="true"></property>
<property name="database" value="MYSQL"></property>
</bean>
</property>
</bean>

<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driver}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>

<tx:annotation-driven />

<!--
Injected properties
-->
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>/WEB-INF/jdbc.properties</value>
</list>
</property>
</bean>

</beans>

Simon
2009-01-14

Cary,

> What is your advice on a best practice for rolling back the changes in the "never mind" scenario?

This is very much a good question. Users are used to having to push the 'submit' button to put the data on the server. Html forms also have a helpful 'reset' feature to reset the text on the screen. With AJAX databindings the data is already on the server. We always engineer our user interface to have a "Save" button that means "commit the data to the database" which is delegated through to the model/controller. If the user chooses to hit the "Cancel" button instead as a 'never mind' we reload the data from the database.

Simon

Simon
2009-01-18

angel,

I tested things out on Tomcat and it runs okay. On windows vista using sun jdk 1.6.0_10 I simply unzipped the apache-tomcat-6.0.18.zip and dropped in the zktodo2.war file and started tomcat. The app deployed and ran. Are you trying to run it under Eclipse WTP?

Simon

Simon
2009-01-18

Marcos,

Thanks for pointing that out. For the clarity of the article and for those people that are new to spring I will leave the explicit xml configuration in. The persistence context is being annotation wired which is also documented in the article so I will leave things 'as-is'. With hindsight I should have stuck with one approach or another.

Simon

robertpic71
2009-01-20

Cary wrote:
> What is your advice on a best practice for rolling back the changes in the "never mind" scenario?

simon wrote:
>> This is very much a good question. Users are used to having to push the 'submit' button to put the data on the server. Html forms also have a helpful 'reset' feature to reset the text on the screen. With AJAX databindings the data is already on the server. We always engineer our user interface to have a "Save" button that means "commit the data to the database" which is delegated through to the model/controller. If the user chooses to hit the "Cancel" button instead as a 'never mind' we reload the data from the database.

Yes, this problem remains: The bean/model is is always up-to-date (with databinding). Sometimes this creates bad effects, i.e. select a listitem change a value and select another listitem
--> the first item is changed in the list

So there is the choice between:
1. do not bind all data to the bean (and move from UI to bean by code)
2. code refresh and repair logik for uncommited data
3. create clones for edit-areas (i.e. with apaches beanutils) and sync back when the validation is ok

henrichen
2009-01-20

There might be 4th choice:

In ZK databinding, you can configure the databinding to "happen" on an specified event rather than the default one.

e.g. <textbox > is default to do 'save'(UI -> bean) when textbox onChange event is fired but you can tell data binder to do 'save' when other component and event is fired.

<textbox value="@{person.firstName,save-when='btn.onClick'}"/>
<textbox value="@{person.lastName,save-when='btn.onClick'}"/>
<button id="btn" onClick=""/>

The above example would not copy <textbox> value to 'person' bean until the <button> 'btn' is clicked.

If you would like to use Java code to move data, you can also "disable" the default 'save-when' events by giving 'none' keyword:

<textbox value="@{person.firstName,save-when=none}"/>
<textbox value="@{person.lastName,save-when=none}"/>

Then ZK data binder will not do the 'save' for you.

There were also 'load-when' options, if you don't want ZK data binder to do 'load'(bean -> UI) for you.

Details in http://www.zkoss.org/javadoc/3.5.2/zkplus/org/zkoss/zkplus/databind/AnnotateDataBinder.html

robertpic71
2009-01-20

Hi henri,

thanks, i forgot this option. I've done already some tests with this option. But it solves not all my problems.

- with "save-when=none" no contraints are fired after onblur/onchange (not really a problem for me)

- it's a little bit inconvenient to write "save-when=none" in all fields for big forms (also not really a problem - i know the zk.xml option, but for other cases i prefer the save-when=onChange)

- for complexer validations i need the bean(data) inside my controller. When i do (complex) contraints inside javacode the data is already syncronised to the listitem - after error/cancel/"select another listitem" the unchecked data remains in the listitem.

Maybe it looks like a little bit fussy, but i want a 100% working CRUD, before i create some basiclasses and/or templates (for out main application).

However, "save-when=none" and onClick=binder.saveXXX is really an option.

/Robert

Simon
2009-02-26

I have updated the wiki version of this article with two new sections. One introduces an explicit model class and the other introduces ZK databindings.

http://docs.zkoss.org/wiki/ZK_With_Spring_JPA_And_A_Model-View-Controller_Pattern

rgds

Simon

dseiler
2009-04-06

Hi Simon,
I have studied your zktodo2 example. It is a great help to see how everything fits together. Am I right that for the @Reporsitory annotation to work (translate the exceptions) you would need to add the following bean desc to the spring-context.xml?

<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />

rgds

Daniel

Brad Rhoads
2009-05-26

I just wanted to point out that it's not necessary to specify methods of an interface as abstract. All interface methods are implicitly abstract. I only mention it, because seeing that confused me until I looked it up.

simon
2009-06-26

Brad,

<off-topic>
Yes is not necessary to write abstract - but with certain java tools and IDEs it makes it easier to know that it is a method coming from an interface or abstract without looking at the source code of the type or at the java doc. Of course such a method it could also be from an abstract class but it does indicate polymorphism regardless of the strategy used to implement it. I have only recently started to add that qualifier to the code simply to help with understandability. Yes I too had to look it up when I first started to notice it on other peoples code and when eclipse started suggesting it to me when I started to trust it to do a lot of the typing for me. Another style thing around interfaces is that jdk1.6 allows you to put @Override when you implement the method of an interface. Code that did not have that does not need it as it works without on jdk1.4 and jdk1.5 but it helps to document what is going wrong and also gives you a compile warning if the method is dropped from the interface you are implementing without you spotting it. The best book that I have seen for years hard core java programmer that I actually learnt anything new from is 'Effective Java 2nd Edition' by Joshua Block who wrote the java collections framework and is chief java architect at google. It is well worth studying for those who want to learn the black art of java inside out.
</off-topic>

Simon

simon
2009-06-26

dseiler,

Sorry for the late reply. I published a later version of this article on javalobby.com so I have not come back to this wiki version for a while. Did you try out your suggestion and did it work? If so please feel free to submit a patch on sourceforge for the zkforge project where the source is located and I will take a look and commit the code if it tests well.

Recently I read Spring Recipes by Gary Mak which was a very excellent book that taught me a lot of new areas of the spring framework. I would highly recommend the book to anyone who is using spring.

Simon

simon
2009-06-26

I posted a version of this smalltalk article on javalobby.com here. As that site is not a ZK site I changed the detail a bit. <shameless>If you like the article dont forget to vote for it on that site so that it will bring zk to the attention of a wider audience!</shameless>

simon
2009-06-26

All,

I recently added some code to zktodo2 demo to show using an <?init?> statement to add the controller class to the page rather. This forum post explains how it works and why.

Simon

Celso
2009-09-10

Simon,
first of all, your article is great!

But I need some help from you. I will try to explain my problem.

I'm getting the follow Exception:
Cause: failed to lazily initialize a collection of role: com.xmobilesystems.yardsales.model.User.products, no session or session was closed

This exception becomes when I use "user.getProducts()" from my controller.
In my model I have this:

@OneToMany(fetch=FetchType.LAZY, cascade = { CascadeType.PERSIST })
@JoinTable(name = "user_product", joinColumns = @JoinColumn(name = "user_id"), inverseJoinColumns = @JoinColumn(name = "product_id"))
protected Set<Product> products = new HashSet<Product>();

You will see "FetchType.LAZY", yes I know that I can put it on EAGER, but I need it in Lazy, because I have a lot of products.

How can I change your the datasource-context.xml to solve this problem?
Thanks in advance.

Simon
2009-10-18

Celso,

Your question leads to an advanced topic: lazy loading in object relational mapping (ORM). This is covered well in this JPA blog:

http://blog.xebia.com/2009/04/27/jpa-implementation-patterns-lazy-loading/

It is a big topic with lots of design decisions involved so this comment is going to be long....

The issue is that the presentation code cannot access any lazy loaded data once the transaction has been committed when the JPA session is closed. The transaction is committed when the service methods which are marked as @Transactional finish. With the zktodo2 sample code that is when the ReminderService methods have returned.

There are two different strategies which you can take to resolve this:

* Keep the transaction and the JPA session open for the whole of the web request processing including any UI rendering. This is the Open Session In View pattern.
* Ensure that the method marked as @Transactional explicitly calls any lazy loading getters. This can be done using either a Service Facade class to host the methods, or by using Spring TransactionTemplate call-backs called within your Composer classes. Both may be used to scope all of the work necessary to force the lazy loaded entities to be loaded ahead of the UI rendering phase.

ZK has support classes for Open Session In View with Hibernate. I am sure these classes can be adapted to do the same with any JPA vendor other than Hibernate. I do not use them personally. This is because there is a price to pay for the convenience of Open Session In View. It means that a database connection is taken from the pool and reserved for the whole of any of the user input processing or page rendering.

If you have a high load application (dedicated database servers and many application servers) then holding the database connection whilst rendering could inhibit scaling the application. With high load applications you want to do any rendering work after having returned the database connection to the pool. That way the database connection can be put to work by a second request in parallel to the rendering phase of the first request . You can then process more concurrent requests than you have working database connections. To do this you need to make the scope of any transaction work as narrow as possible.

The alternative to Open Session In View is to ensure that you call any lazy getters within the @Transaction methods to force the entities to be loaded. For example you could just do a foreach over any collections of entities and call a non-ID property getter on each entity just to force the entity to be loaded from the database.

You could of course do such "force a lazy fetch" work within your regular application service classes. The downside being that work to force entities to be loaded for the UI is "presentation work". Typically if you complete checkout at a website the next page you get shown is something totally unrelated - it is a bad design to have your "CheckoutService" be coded to know that after completing the users purchase it must load data to render the users order history page under the same JPA session and database transaction.

In order to get around the design concerns about encoding knowledge of the UI into your generic application services you could introduce a set of service facade classes. These classes exist to intermediate between the screens and the generic services. The facades encapsulate the Use Case specific knowledge that "completing checkout places an order and then takes the user to her recent orders page". A service facade class which knows "call the CheckoutService to complete the pending order then call the OrdersService load the data needed to render the recent orders page" makes the perfect place to put the @Transaction method which scopes all of the database work. It would be acceptable to have a foreach at the bottom of the method which calls a getter on each item of the recent orders to force the lazy loading of each entity.

With a very small application - such as the zktodo2 demo - putting in an explicit set of service facades to scope an @Transactional method can be overkill. In a very simple webapp I would configure a Spring TransactionTemplate and inject that into my Composer class. Then the composer can call execute on the template passing in a method which does all of the necessary database work. This would include the work to force the loading of lazy entities required for rendering recent orders. I would then do the work to cause the loaded entities to be rendered correctly outside of the transaction template call-back. In this manner the scope of the use of the database connection is kept as narrow as possible.

A book which covers all of the above in detail is Chris Richardson's book "POJOs In Action". Although it was written before JPA it is an excellent book about how to write web applications using ORM. It covers all of the patterns that I have mentioned here above with detailed examples. It is also a timeless classic about how to write websites using spring and junit. I would very highly recommend it to anyone that wants to write a website using the full power of the Spring framework.

Simon

thangaraj
2009-11-01

Hi there,
Can you tell any one how to show serial number in the grid/listbox using datagbinding with or without jsp tags dynamically?

I need like this-
sno fruits price
1 apple $3
2 banana $1
3 Gooseberry $2

Regards
Thangaraj

Eric
2010-01-22

Hi I believe there is an issue that many have overlooked! When creating a ZK-Spring (annotated) controller such as:

@Controller("myController")
public class MyController extends GenericForwardController {...}

there is the issue on how to access the current HttpSession for storing things! The GenericForwardControllers "session" attribute seems to point to null (ZK never handles this controller as it is set up as a annotated spring one! Or at least that is my guess).

ZK UI components such as a listbox could easily be bound to a method within the controller class using <listbox model="@{myController.allItems}. This requires a "getAllItems()" function in the controller class above.

But another typical binding used in ZK is "selectedItem" such as in <listbox model=".." selectedItem="@{myController.selectedItem}" />

However that requires a getSelectedItem() in the controller class which in turn would have to retrieve the current item from the HttpSession! Which doesn't seem to be possible. Neither can a setSelectedItem(Item item) store the currently chosen item (in the listbox) in the HTTP session associated with the current origin of the web request.

Autowiring a session-scoped bean (as a wrapper for HTTP session objects) doesn't work, Spring complains that there is no request bound to thread (and yes I have tried RequestListeners, filter etc).

The problem is that ZK and Spring doesn't seem to share threads for the incoming web request. And the syncronization as handled by the ThreadLocal Variables Synchronizer doesn't seem to deal with the RequestContextHolder (which otherwise could have been used to access the current session's attributes) as it should eventhough I've added the thread-local preference (to the threads-syncronizer config in zk.xml) that has the value of: org.springframework.web.context.request.RequestContextHolder=requestAttributesHolder,inheritableRequestAttributesHolder

So basically, if i'm not missing something important out here, in Spring-ZK apps there doesn't seem to be any support for accessing HTTP session in controllers (that are spring ones with autowired fields for accessing app services etc) nor having session scoped proxied beans injected and used into/in controllers. Which basically renders any serious application impossible.. Which sucks, cuz I really do like ZK and Spring and JPA as well as Spring annotations..

Anyone who's got this working? Then pls post a solution! I'd be more than happy I can assure u that..

wims.tijd
2010-02-08

you do not need a @controller annotation

@Service("aclform")@Scope("session")
public class AclForm extends GenericForwardComposer{

an instance is created for every new session so you can
safely store variables in your class members (T selected;)
(setSelected,getSelected) instead of using the session

<window apply="${aclform}"

 
 
Leave a Reply
 
Name (required)
Mail (will not be published) (required)
Website
(Case Insensitive)
Bold textItalic textUnderLine textSource CodeHorizontal rulerExternal Link
Post
Preview