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:
@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:
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:
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 }
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:
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.
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:
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.
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.
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:
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:
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.
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:
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
<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>
> 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.
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.
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.
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?
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:
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