Monday, April 27, 2009

Wicket Patterns and Pitfalls #5

This is the fifth article in a series of articles about common patterns and pitfalls when using Wicket (http://wicket.apache.org). Most of these patterns apply only when using Wicket in conjunction with Spring and Hibernate and these might be very specific, but others are more general. The last article was about the pitfalls related to Wickets HTTP session usage. This time a pattern for dataproviders for lists of associated entities is shown.

Data Providers for Indexed Lists



Environment: Wicket

Example Environment: Wicket, Spring, Hibernate


IDataProviders in Wicket are used to provide data to data views, such as DataTables for instance. The data provider interface has three methods:

public interface IDataProvider extends IDetachable {

Iterator iterator(int first, int count);

int size();

IModel model(Object object);

}

The iterator(first, count) method returns an iterator, that iterates over the actual data. The range is is used to get a subset of that data, e.g. for paging. The size() method returns the total number of possible result values. The objects returned by the iterator are then passed to the model() method to wrap the entity into a model, generally this should be a LoadableDetachableModel.

There are many ways to implement a data provider depending on the situation. This article sets the focus on the special case of implementing a data provider for a list of objects that are associated by another object, for example the orders of a person.

The Example
As an example, let's take an entity Person that references some Orders:


@Entity
public class Person {

@Id @GeneratedValue(strategy = GenerationType.AUTO)
private Long id;

private String lastName;
private String firstName;
private String username;

@OneToMany(mappedBy = "person")
private List<Order> orders = new ArrayList<Order>();
...
}


... and a panel that displays the orders of a person:


public class PersonOrdersPanel extends Panel {

public PersonOrdersPanel(String id,
final IModel personModel) {
super(id, personModel);

Person person = (Person) personModel.getObject();
IDataProvider dataprovider =
new PersonOrdersDataProvider(person.getId());

IColumn[] columns = ...

add(new DataTable("table", columns, dataprovider, 10));
}
}

The panel is provided a person model and it uses a Wicket DataTable to display the details of the person's orders. DataTable requires an IDataProvider that delivers the orders. Let's have a look at different implementations of such a data provider, that retrieves the orders of a person.

A DAO data provider
The first thing, that comes to my mind when thinking about how to implement the order data provider, is using a DAO that fetches the person's orders from the database.

public class PersonOrdersDataProvider implements
IDataProvider {

@SpringBean
private IOrderDao orderDao;

private final Long personId;

public PersonOrdersDataProvider(Long personId) {
this.personId = personId;
InjectorHolder.getInjector().inject(this);
}

public Iterator iterator(int first, int count) {
return orderDao.findByPerson(personId,
first, count).iterator();
}

public IModel model(Object object) {
return new GenericLoadableDetachableModel<Order>(
(Order) object);
}

public int size() {
return orderDao
.findByPersonCount(personId);
}

public void detach() {
}
}

This data provider implementation uses a @SpringBean annotated OrderDao, which is injected by the constructor. The constructor takes the person's database ID as an argument. The iterator() method uses the order DAO to find the orders of the person with this ID. size() calls the DAO to get the total number of the person's orders. The model() method returns a GenericLoadableDetachableModel for an order, which loads the order by its ID (see the previous article for a description of GenericLoadableDetachableModel).

While this implementation works well, it's quite an effort, to implement it. We need an order DAO and we have to implement the findByPerson(first, count) and findByPersonCount(personId) methods. We have to write some injection code, and we need a suitable model for the orders (this is no effort, if you have a GenericLoadableDetachableModel, though). Another issue is, that it only works for entities, not for value objects (e.g. Hibernate @Embeddables), as these don't have an ID, so it's hard to implement a LoadableDetachableModel for these. Also, this implementation results in a separate database query for the orders, although the person already might be referencing them.

A model based data provider
Another implementation could depend only on the person model, or in general, on the model for the entity that associates the list of objects we need a data provider for. Let's take a look:

public class PersonOrdersDataProvider implements
IDataProvider {

private final IModel personModel;

public PersonOrdersDataProvider(
IModel personModel) {
this.personModel = personModel;
}

public Iterator iterator(int first, int count) {
return getPerson().getOrders().subList(
first, first + count).iterator();
}

public IModel model(Object object) {
int index = getPerson().getOrders()
.indexOf(object);
return new PropertyModel(personModel,
"orders." + index);
}

public int size() {
return getPerson().getOrders().size();
}

public void detach() {
// personModel gets detached somewhere else
}

// helper
private Person getPerson() {
Person person = (Person) personModel
.getObject();
return person;
}
}

This shows a data provider that does not use a DAO, but instead completely relies on the person model. This is passed as an argument to the constructor and assigned to an instance variable. The iterator() method pulls the person out of this model and creates a sublist of the list of orders referenced by the person. Also, size() just returns the size of the orders list of the person. The model() method returns a PropertyModel based on the person model, indexing into the orders property (PropertyModel expressions support indexing). The index is the index of the order in the list of orders.

With this implementation there's no need for a DAO or a separate database query. There is no special model needed for the orders and it also works for value objects.

Alternative model based data provider
There is a variant of the previous data provider implementation, that I even like a little bit more, as it is kind of more explicit. The only difference is in the iterator() and model() methods:

public class PersonOrdersDataProvider implements
IDataProvider {

...

public Iterator iterator(int first, int count) {
return new RangeIterator(first, count);
}

public IModel model(Object object) {
Integer index = (Integer) object;
return new PropertyModel(personModel,
"orders." + index);
}

...

}

This time iterator() really just returns an iterator that iterates over the indexes of orders in the list of orders of the person. It returns a RangeIterator that iterates over the integers in the range [first, first + count] (this is not difficult to implement). In consequence this index is passed to the model method, which again returns a PropertyModel indexing into the orders property of the person model.

Conclusion
I think, this article shows a way to implement a data provider that's a bit more elegant than the conventional way. An additional benefit is, that it can also be used for lists of value objects. Also, it allows for a generic implementation, that can be reused for different entities.

A drawback is, that it performs worse than the DAO data provider when it comes to huge datasets, because it loads all elements of the collection, which might not be necessary if you use an OR-Mapper that supports lazy loading. The DAO data provider can restrict the number of results that are fetched from the database, if you want to implement some kind of paging. On the other hand if you really want to display all elements of the collections, you could fetch the person including the orders within a single query with the model based dataprovider.




Thursday, April 9, 2009

Wicket on Google App Engine

Google App Engine now supports Java. Let's get Wicket running on it, quickly.

Note: This post covers the basics of setting up Wicket on GAE. This subsequent post takes the next steps of setting up Spring and persistence with JDO and provides the source code of a sample application.

1. Use the Eclipse plugin to create a project
The Eclipse plugin can be installed via Eclipse Update Manager and it includes a Google App Engine SDK, so you don't need to install that separately. With the plugin, create a "New Web Application Project".


Uncheck "Use Google Web Toolkit" and leave "Use Google App Engine" activated. The project will contain a src folder and war folder. It contains a simple "Hello, World" example and you can run it immediately. But let's get Wicket running, quickly.



2. Add Wicket jars
Add the following jars to the war/WEB-INF/lib directory and add them as external jars to the eclipse project:

- wicket-1.3.5.jar
- slf4j-api-1.5.2.jar
- slf4j-log4j12-1.4.2.jar
- log4j-1.2.13.jar



3. Turn on logging
Turn on logging, so that you can see any strange things, that may occur. App Engine won't tell you much by default.

- log4j.properties: log4j.logger.org.apache.wicket=DEBUG, A1
- java6 logging.properties: .level = INFO

4. Create a Wicket Application and a Page
Add WicketApplication.java

package wicket;

public class WicketApplication extends WebApplication {
public Class getHomePage() {
return HomePage.class;
}
}

and a simple HomePage.java and HomePage.html:

public class HomePage extends WebPage {
public HomePage() {
add(new Label("label", new Model("Hello, World")));
}
}



5. Set up WicketFilter
Add the Wicket servlet filter to web.xml. Alternatively use WicketServlet:


WicketFilter
org.apache.wicket.protocol.http.WicketFilter

applicationClassName
wicket.WicketApplication




WicketFilter
/wicket/*




6. Add HTTP session support
Enable HTTP session support (by default it's disabled) by adding the following line to appengine-web.xml:

true


Now the app is ready to run, but there are still some issues.

7. Disable resource modification watching
When Wicket is started in development mode now, exceptions are raised because Wicket spawns threads to check resource files such as HTML files for modifications. Let's just disable resource modification checking by setting the resource poll frequency in our WicketApplication's init() method to null.

protected void init() {
getResourceSettings().setResourcePollFrequency(null);
}

8. Disable SecondLevelCacheSessionStore
We cannot use the SecondLevelCacheSessionStore in the app engine, which is the default. At least not with a DiskPageStore, because this serializes the pages to the disk. But writing to the disk is not allowed in the app engine. You can use the simple HttpSessionStore implementation instead (this increases HTTP session size), by overriding newSessionStore() in our WicketApplication:

protected ISessionStore newSessionStore() {
//return new SecondLevelCacheSessionStore(this, new DiskPageStore());
return new HttpSessionStore(this);
}


9. Run
From the context menu of the project, call Run As -> Web Application. Open http://localhost:8080/wicket/ in your browser and see the app running.


Download the demo as an eclipse poject.




Tuesday, April 7, 2009

Wicket Patterns and Pitfalls #4

This is the fourth article in a series of articles about common patterns and pitfalls when using Wicket (http://wicket.apache.org). Most of these patterns apply only when using Wicket in conjunction with Spring and Hibernate and these might be very specific, but others are more general. The last article was about the OSIV-LDM-Pattern and its pitfalls. This time it's about HTTP session pitfalls.

Wicket Session Pitfalls



Environment: Wicket, Spring

Example Environment: Wicket, Spring, Hibernate, OpenSessionInView


When Wicket processes a request, the component hierarchy including the models is constructed, then events are processed, the response is rendered, and finally the components and models are put into the PageMap. This is Wicket's way of storing state. The PageMap in turn is put into the Wicket session, which is put into a SessionStore, which is put into the HttpSession (by default). And as the HttpSession is a critical resource, one has to take care of the size of the components. Especially, the size of the models, that are attached to the components, can be of critical size - imagine huge amounts of table data or large object graphs. For this reason, Wicket provides models, which get detached at the end of the request, so that their model objects will not be put into the session (this generally means nulling out transient fields). But there are still some cases, where model objects are accidently put into the session. This article sheds some light on these cases.

The Example
As an example to demonstrate these cases, let's take an entity Person ...

@Entity
public class Person {
@Id @GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String lastName;
private String firstName;
...
}

... and a very simple page that displays the details of a person:

public class PersonPage extends WebPage {

public PersonPage(final Person person) {
super(new Model(person));

add(new Label("firstName",
new PropertyModel(person, "firstName")));
add(new Label("lastName",
new PropertyModel(person, "lastName")));
add(new Label("username",
new PropertyModel(person, "username")));

Link link = new Link("editLink") {
public void onClick() {
setResponsePage(
new PersonEditPage(person));
}
};
add(link);

}
}

The person entity is provided as an argument to the constructor. We call super() with a new Model(person) to associate the person model with the page, so we can get a handle to the person later on. Then we add some labels to display the details of a person. We provide PropertyModels to the labels, which are used to access a property of the person using a property expression. Finally, we add a Link, which directs the user to the PersonEditPage, where the user details can be edited. We do so by setting the response page to a new PersonEditPage(person). We pass the person instance, that was provided to the constructor of PersonPage, to the edit page.

So, this is a really, really simple page. And in fact, it has some flaws, so that the person entity is put into the session. This is something we wouldn't want, because the person may be connected to a larger object graph (e.g. person references some orders, which reference some line items, which references items, ...), which would all be put into the session as well.

The person entity in this example is put into the session for different reasons. The following sections describe these reasons and give some rules to prevent model objects from getting put into the session.

Rule #1: Use detachable models for entities
The first one is a very basic one. In the example above, the person is passed as an argument to the constructor and then it's put into a newly created Model instance. Now, Model is the basic implementation of an IModel (the base model interface in Wicket) and it does no more than keeping a reference to the entity, which is returned by getObject() - no detaching at all. In fact, the constructor of the Model class gives a hint that the model object is put into to the session: it just accepts model objects as an argument that implement Serializable.

Model is not the only implementation of IModel that does not detach entities. For example, PropertyModels and CompoundPropertyModels don't detach entites either. These models do some other kind of detaching, though, which is shown in the next section. But first, let's see, what we can do about the problem here. We are looking for an IModel implementation that implements detach() (inherited from IDetachable) in a suitable way, i.e. detaching the entity from the model after the request. And in this case, we could use a LoadableDetachableModel. LoadableDetachableModel requires you to implement the abstract method load(), which is meant to return the entity (e.g. fetch it from the database). When getObject() of LoadableDetachableModel is called, it calls load() to fetch the entity and assigns it to a transient field. At the end of a request, detach() is called, which nulls out this transient field, so the entity is not put into the session.

Rule #2: Rely on models, not on entities
The second reason, for which the person entity gets into the session in the example above, is the way the PropertyModels for the Labels are used. When new PropertyModel(person, "firstName") is called, the PropertyModel assigns the person instance to an internal, non-transient, never nulled-out instance variable. In this sense, PropertyModel is no better than an ordinary Model.

But we can still leverage the benefits of a PropertyModel as it implements IChainingModel in a proper way. That means, we can pass another person model to it as an argument instead of the entity itself, and it will chain through the calls to getObject(), detach() and so on. So, if we pass a LoadableDetachableModel for the person to the PropertyModel, we are fine: new PropertyModel(loadableDetachablePersonModel, "firstName"). So, whenever it is possible, we should build models that rely on other models instead of the entities directly.

Rule #3: Do not assign entities to instance variables
The example above does not violate this rule, so here is a variation of the PersonPage that does:

public class PersonPage extends WebPage {

private Person person;

public PersonPage(final Person person) {
this.person = person;
...
}
}

In this case, the person instance gets put into the session, simply because the page is put into the session, as all components are. It's easy to follow this rule. Just follow rule #1 and rule #2.

Rule #4: Do not circumvent @SpringBean proxies
This rule is kind of the same as rule #3 but related to @SpringBean annotated fields (when using Wicket in Spring container). When a field of a component is injected with the use of @SpringBean, what really is assigned to the field is a proxy of that spring bean.

public class PersonPage extends WebPage {

@SpringBean
private PersonDao personDao;

public PersonPage(final Person person) {
...
}
}

As this is a lightweight proxy of the PersonDao, rule #3 is not violated. In fact, the @SpringBean-proxy-mechanism is a good example of following rule #3. Anyway, while it's okay to keep a reference to this proxy, it's not okay, to pull other spring beans out of the proxy and assign them to instance variables. Example:

public class PersonPage extends WebPage {

@SpringBean
private PersonDao personDao;

public PersonPage(final Person person) {
super(new PersonModel(
personDao.getSessionFactory(),
person.getId());
...
}
}

public class PersonModel
extends LoadableDetachableModel {

private SessionFactory sessionFactory;
private Long personId;

public PersonModel(SessionFactory sessionFactory,
personId) {
this.sessionFactory = sessionFactory;
this.personId = personId;
}

public Object load() {
return sessionFactory.get(personId);
}
}

When personDao.getSessionFactory() is called, the real sessionFactory is returned, of coures. No proxy. Then it's passed to the PersonModel which holds a reference to it, and the sessionFactory will be put into the session along with this model. We can prevent this by injecting the session factory by using @SpringBean as well.

Rule #5: Implement anonymous inner classes carefully
The PersonPage in the example uses a Wicket Link to redirect the user to the person edit page. The Link is implemented as an anonymous inner class in order to implement its abstract method onClick(). Many Wicket components are implemented this way, and as a result, anonymous inner classes are very common in Wicket.

public PersonPage(final Person person) {
super(new PersonModel(person));
...

Link link = new Link("editLink") {
public void onClick() {
setResponsePage(new PersonEditPage(person));
}
};
add(link);
}

The onClick() method is implemented in the most straightforward way. The person instance, which was passed as an argument to the constructor of PersonPage, is passed to the constructor of PersonEditPage, which is set as the response page. It's not easy to see immediately, how the person is getting into the session now, but in fact it's put there. And it can happen as easily in many other cases using anonymous inner classes.

This is because in Java, when an inner class, declared in a method (or constructor), accesses a variable of its declaring method, such as an argument or a local variable, this variable effectively becomes a member of this inner class. This is because these variables have to be declared final to be able to access them from inner classes. In the example above, the person parameter becomes an instance variable of the anonymous Link class, and as rule #3 has shown, instance variables are put into the session along with the components they belong to.

Rule #6: Always attach models to components
This rule also relates to rule #3. This time it's about models as instance variables. Let's add an instance variable of type IModel to the person edit page.

public class PersonPage extends WebPage {

private IModel accountModel;

public PersonPage(final Person person) {

super(new PersonModel(person);

this.accountModel = new AccountModel(
person.getAccount());
}
}

Let PersonModel and AccountModel be properly implemented LoadableDetachableModels. So what's wrong with assigning a LoadableDetachableModel to an instance variable? After all, it's a lightweight model and the PersonModel is assigned to an instance variable somewhere in the page hierarchy, too.

Actually, the PersonModel is assigned to a component, which takes care of detaching the model. A LoadableDetachableModel has to be detached by some component that knows about this model. And this is not the case with the accountModel. No component ever calls its detach() method, as it's not attached to a component as a model. We could implement some detachment logic for this model in the person page, though.

Conclusion
The conclusion of this article is simple: If you use objects of some serious weight in components, don't use them directly. Instead use an IModel implementation, that implements a proper detachment logic, or use some kind of other leightweight representation of that object like an ID or a @SpringBean proxy.