Adding JPA based persistence to the Address Book Demo

Apr 09
2010

Every Vaadin developer has probably at some point looked at the Address Book Demo. It is a simple application written as an example of how to develop applications with Vaadin. The example is nice, but it is lacking one key feature, the ability to actually store the addresses in a database.

The Vaadin wiki contains an article written by Petter, which shows how to apply JPA based persistence to the address book demo. The article is great and I recommend you to read it, however, I was thinking that I probably could achieve the same task with a more simple approach.

I’ve written a small framework called Application Foundation. Its goal is to provide a simple and lightweight foundation for Vaadin application. With the application foundation framework you get commonly used features such as JPA based persistence, view handling, i18n, authentication and permission management. For this article, I’ll be using the persistence module to provide the JPA based persistence.

Setting up and configuring the project
I’ll start by checkout out the source code of the address book demo and set up my Vaadin project in Eclipse. Next, I’ll download the newest version of Application Foundation (at the time of writing this, the newest version is 1.2). I’ll add the appfoundation.jar to the WEB-INF/lib folder. The application foundation is a server-side only add-on, so you won’t need to recompile your widgetset.

Once I’ve added the appfoundation.jar to my application, I will need to configure the persistence module. The configuration details are explained in the documentation of the persistence
module
. Once the persistence module is configured, I will create a context listener which starts up the persistence module when the server is started.

Identifying and applying the needed changes
I’ll start by identifying the entities needed in the application. The application only needs one entity and that is the Person class. The required changes are really simple, all I need to do is to annotate the Person class as an entity and make it extend AbstractPojo.

@Entity
public class Person extends AbstractPojo {
   ...
}

The next modifications I’m going to do is to move the creation of the example data away from the PersonContainer into a class which is executed only once when the server is started. In other words, when the server starts, I want to create a set of test data, persist it and then use the same data in all application instances. I’ll create a class called InitialData which has a static method called init(). I’ll copy the implementation of createWithTestData() method from the PersonContainer and use the exact same implementation in the init() method. Only modifications I’ll make is that I remove the container references and replace the addItem() method with a method which stores the person object into the database.

FacadeFactory.getFacade().store(p);

I previously created a context listener for starting up the persistence module, I’ll add a method call to InitialData.init() in that same context listener. This way my test data is created only when the server is started.

I’ll also have to make small modifications to the PersonContainer. Since the test data has already been created in the context listener, I’ll be wanting to use that data instead of the data created by the container. What I’ll do is fetch all the person objects from the database and populate the container with those objects. The method for populating the container looks like this:

public static void populatedContainer(PersonContainer c) {
   if (c == null) {
      return;
   }
 
   c.removeAllItems();
 
   List<Person> persons = FacadeFactory.getFacade().list(Person.class);
 
   if (persons != null) {
      for (Person p : persons) {
         c.addItem(p);
      }
   }
}

I renamed and refactored the createWithTestData() method, the new implementation looks like this:

public static PersonContainer createAndPopulatedContainer() {
   PersonContainer c = null;
   try {
      c = new PersonContainer();
      populatedContainer(c);
   } catch (InstantiationException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
   } catch (IllegalAccessException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
   }
   return c;
}

Next thing I will tackle is the saving of contacts. This means that I want to store to the database any changes made to existing contacts and to store any new contacts created. This is really easy to implement, just two lines of code in the PersonForm’s buttonClick() method. The method contains an if clause for checking if the save button was clicked. At the end of the clause I’ll add the following two lines of code:

Person person = ((BeanItem<Person>) getItemDataSource()).getBean();
FacadeFactory.getFacade().store(person);

The first line fetches the actual Person object from BeanItem which is set as the form’s data source. The second line tells the persistence module to store any changes made to the person object. That’s all, now creating and modifying contacts will work and everything is persisted in the database.

There’s one thing left to do before the example is complete – that task is to handle concurrent modifications. Since every application instance uses the same data, conflicts in editing data may occur. When such a situation occurs, an OptimisticLockingException is thrown. I’ll handle this situation by refreshing the PersonContainer so that all its data is again up-to-date and by notifying the user of what happened. This can be achieved by wrapping the store() method call in a try catch and handling the possible exception.

try {
   Person person = ((BeanItem<Person>) getItemDataSource()).getBean();
   FacadeFactory.getFacade().store(person);
} catch (OptimisticLockException e) {
   getApplication().getMainWindow().showNotification(
         "Oops, someone else modified the data "
         + "simultaneously, refreshing data",
         Notification.TYPE_ERROR_MESSAGE);
   PersonContainer c = ((AddressBookApplication) getApplication()).getDataSource();
   PersonContainer.populatedContainer(c);
}

And I’m all done. Now the address book demo supports JPA based persistence and is able to handle conflicts in concurrent modifications of person contacts.

Summary

The following was done to apply JPA based persistence to the Address Book demo.

  • Application Foundation downloaded and configured
  • Made the Person class an entity
  • Creation of test data refactored to another class
  • PersonContainer popoulates itself with data from the database
  • Changes made to contacts stored in the database
  • Implementing handling of concurrent modifications

Resources:

10 Responses to “Adding JPA based persistence to the Address Book Demo”

  1. Oleg Mazurashu says:

    Good work. Thanks.

  2. ziezzo says:

    Hi,

    Thanks for the sample application to store data into database. Its good.

    Could you guide me on how to read, write and update tables in my database

    Thanks and Regards
    Ziezzo

  3. Vlademir says:

    Hello kim,

    Im pretty new in JPA and Vaadin.
    I tried to implements your solution using Mysql and rised the following
    error:

    Exception [EclipseLink-4002] (Eclipse Persistence Services – 1.1.4.v20100812-r7860): org.eclipse.persistence.exceptions.DatabaseException
    Internal Exception: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table ‘acesso.sequence’ doesn’t exist
    Error Code: 1146
    Call: UPDATE SEQUENCE SET SEQ_COUNT = SEQ_COUNT + ? WHERE SEQ_NAME = ?
    bind => [50, SEQ_GEN]
    Query: DataModifyQuery(sql=”UPDATE SEQUENCE SET SEQ_COUNT = SEQ_COUNT + ? WHERE SEQ_NAME = ?”)
    at org.eclipse.persistence.exceptions.DatabaseException.sqlException(DatabaseException.java:323)

    Can you give me any help?

  4. Kim says:

    This has been answered on the Vaadin forums, see http://vaadin.com/forum/-/message_boards/message/258818

  5. xinyu liu says:

    Petter’s approach takes the value object / DTO design pattern, which in general is undesired in JPA, but widely used in SOA web services.

    I would say Kim introduces a better solution for JPA and Vaadin integration. One question I have for Kim is that how to scope the JPA entitymanager (Hibernate session). It seems open-session-in-view doesn’t apply in Vaadin. If the persistence context is scoped to a database transaction, entities will be in detached state most of the time, how to cope with the LazyInitializationException when lazy fetching is triggered by a user action?

  6. Kim says:

    In my opinion, the persistence context should either be scoped to a database transaction or to one HTTP request, otherwise you will run into problems, eg memory leaks (at least that was the case in a PoC I created a few years back). Either way, the entities will be detached from the session and this is exactly the reason why I prefer EclipseLink over Hibernate in Vaadin applications. EclipseLink manages to handle these situations in a way, that the entity is reattached to the session without the developer having to worry about it, in other words, it’s all done in the background – AppFoundation’s persistence module actually depends on EclipseLink.

    With Hibernate you will get the LazyInitializationExceptions so the approach has to be a bit different. There are a couple of approaches, one is that you manually try to reattach entities to the session before using lazy data. Another, probably a better solution is to write a custom proxy class to handle the lazy loading – when the lazy data is being fetched, instead of relying the object being in a session, handle the lazy request as a separate request which uses another Hibernate session.

  7. haluk says:

    May you add source code as a eclipse-maven project?

  8. Kim says:

    I will try to do that in future posts. I haven’t used maven that much myself – hence the “traditional way”.

  9. Sylvanus says:

    hi kim,

    nice job. you are making our vaadin experience interesting. thanks

Leave a Reply

Visit Our Friends!

A few highly recommended friends...

Archives

All entries, chronologically...

Pages List

General info about this blog...