Prerequisites: Readers are expected to be familiar with AppFoundation (especially its persistence module) and Vaadin containers and its Sortable and Filterable interfaces.
Since the opening of the Vaadin directory, a bunch of really interesting add-ons have emerged there. One interesting add-on is the LazyQueryContainer – it’s a container implementation which fetches data lazily, in other words, data is fetched only when it is needed. It’s by no means the only container which allows lazy fetching of data, but what made this specific container implementation interesting, was that it is licensed under Apache 2.0 license and it won the Vaadin Add-on competition in September.
In this blog post I want to show you how you can combine AppFoundation and LazyQueryContainer to enable lazy data loading in your JPA based application. Be aware, this blog post will be very technical. I will discuss how to combine the LazyQueryContainer with AppFoundation, step by step explaining all the details and providing you with the necessary code examples. At the end of this blog post, I have created a generic LazyQueryContainer which works for any entity type supported by AppFoundation’s persistence module. The container I’m going to write will implement both the sortable and filterable container interfaces. If you are not interested in the implementation details, but rather just want to know how to integrate LazyQueryContainer and AppFoundation to your project, then please wait for my next blog post
After downloading the LazyQueryContainer add-on (abbr. LQC) version 1.1.8, I started by taking a look at it and try to figure out what I need to do to be able to integrate it with AppFoundation. Obviously, I’m going to use AppFoundation’s persistence module to implement the actual database connection, so the actual first step is then to try to figure out how to combine LQC and AppFoundation.
By looking at the LQC’s wiki page, I saw that I need to make my own implementations of the Query and QueryFactory interfaces.
The Query interface defines a set of methods for handling data, for example, fetching a subset of entities, getting the size of the container or saving changes made to a set of entities. Implementing this interface was quite straight forward, it is basically just a wrapper for AppFoundation’s facade calls. My implementation is called AFQuery and it’s a generic implementation that works for all entities which extends AppFoundation’s AbstractPojo. At this point I noticed that I will need to make my own implementation of the QueryDefinition interface. A QueryDefinition is an object which describes how the query should be constructed, for example, in which order should the elements be sorted. The LazyQueryContainer contains a default implementation called DefaultQueryDefinition, but that won’t fit my needs. I will later in this blog describe why I wanted to create my own implementation of the QueryDefinition interface, but for now I will satisfy on creating a class called AFQueryDefinition which simply extends the DefaultQueryDefinition. Note that in version 1.2.0 of LQC the DefaultQueryDefinition class was marked as final, so you will need to copy its implementation to your class, the code example uses the old 1.1.8 version of LQC which allows extending of the DefaultQueryDefinition.
Click here to view first version of AFQuery
After implementing the Query interface, I took upon myself the task of implementing the QueryFactory. QueryFactory’s purpose is to instantiates new query objects whenever the container’s state changes or refresh is requested. You see, the Query object is stateful and it only handles one state at a time. This means that it contains information about which entities it should fetch and in which order should the entities be sorted. So, for example, if you want to sort your items in another order, then the query’s state has changed and a new Query object will be needed.
Click to view source code of AFQueryFactory
The implementation of this interface was really easy, it only contains two methods, constructQuery and setQueryDefinition. The latter method takes a new instance of QueryDefinition as input, which in my case will be the AFQueryDefinition I created earlier. In the implementation I check that the given parameter in fact is a AFQueryDefinition and then I store the instance in a class variable for later use. The constructQuery method’s purpose is quite simple, all it needs to do is to create a new Query instance and return it. The method takes two input parameters sortPropertyIds (Object) and ascendingStates (boolean). These two parameters are familiar from the container’s sort() method. Basically, these two parameters define in which order the items in the container should be sorted. In LazyQueryContainer’s default implementation, these two parameters are passed as arguments to the Query object’s constructor, but my implementation will do it a bit differently. Instead of forwarding the parameters to the Query object, I will instead add a sort() method to the AFQueryDefinition which takes as input the sortPropertyIds and ascendingStates parameters and stores them in class variables.
Click to view source of AFQueryDefinition
The next step is to actually support sorting in the Query object. Since the AFQueryDefinition contains information about the actual query, I think it’s logical that it will be responsible of creating a JPQL query for the AFQuery to use. For this, I will need to make small modifications to the AFQueryDefinition and the AFQuery classes. AFQueryDefinition will have a constructor that takes the entity class as an input parameter and then the toString method will be overridden to return a JPQL query. In AFQuery I will need to change the loadItems method slightly, instead of giving the entity class as a parameter to the JPAFacade’s list() method, I will give it a JPQL query string, one which I will get by calling toString on the query definition object.
Click to view changes in AFQueryDefinition
Click to view changes in AFQuery's loadItems() method
At this point I have created a LazyQueryContainer with AppFoundation binding for fetching any type of entities supported by AppFoundation (in other words, anything extending AbstractPojo). LazyQueryContainer implements Container.Indexed and Container.Sortable interfaces, but not Container.Filterable. I will now show you how to implement the Filterable interface, an interface which we will need in the address book demo application’s search functionality.
Obviously, to be able to implement the interface, I will need to extend the LazyQueryContainer class. By default, the LazyQueryContainer provides you with a different set of constructor methods to choose from. In my extended class (which I will call AFLazyQueryContainer), I will only implement one constructor, it takes as its arguments a QueryDefinition and a QueryFactory. As you probably guessed, these two objects will be instances of our AFQueryDefinition and AFQueryFactory respectively. Next up is implementing the Filterable interface, it has three methods, addContainerFilter, removeAllContainerFilters and removeContainerFilters. I don’t want the container itself to handle the filters, a more logical place to handle them are in the AFQueryDefinition, as it is responsible for creating the JQPL query. Hence, I will start by adding equivalent filter methods to the AFQueryDefinition.
I’ll start by implementing the addContainerFilter method in the query definition. To have a bit better control over the filters, I will create an inner class called Filter. This class will simply hold the information of one specific filter. It will only have four methods: a constructor which takes as its arguments the same parameters as the addContainerFilter method, an overridden toString method which creates a WHERE clause for the JPQL query, a getParam method which constructs the parameter value for the filter (applies wildcards on the filterString) and finally a getParamName which will return the placeholder’s name in the JPQL query. The filter interface’s methods in the query definition will be implemented by using a map between the property id and a list of filters applied to the property id. Basically, I just add and remove Filter objects from the map based on the container calls. The query definition class will also have a createWhereClause() method which creates, well, the where clause for the JPQL query based on the filters assigned. I’ve also created a getParameterMap() method which will return a map between the filter placeholder names and the actual filter strings (this is needed for AppFoundation’s facade calls). This is all I need to do in the AFQueryDefinition. The last thing I need to do is to change the AFQuery’s size() and loadItems() methods’ implementations so that they take into account the filters.
That’s it and I’m done. You can view the final version of each file by clicking on the links below. Please feel free to use the code in your own projects and play around with both AppFoundation and LazyQueryContainer.
Download the source code as a zip file