Wednesday, March 25, 2009

Wicket Patterns and Pitfalls #3

This is the third 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. See also Wicket Pitfalls and Patterns #2.


OpenSessionInView-LoadableDetachableModel-Pattern and its Pitfalls



Environment: Wicket, Spring, Hibernate, OpenSessionInView

This article targets some pitfalls when using the OpenSessionInView (OSIV) pattern in combination with LoadableDetachableModels (LDM) and Hibernate. This combination is a very commonly used pattern, because it greatly simplifies handling of Hibernate entities (no more detached entities), and it relieves us from the pain of dealing with LazyInitializationExceptions (how many hours did we spend fixing these?). But although this pattern is very useful and it's highly recommended, there might be some tricky side effects, which have to be considered. These are described in this article.

The OSIV-LDM-Pattern
In order to explain the benefits of the OSIV-LDM-Pattern, let's take a look at a simple example. Assume we have a Hibernate entity Person with three properties firstName, lastName and username:

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

A simple page to edit a person could be implemented like this:

public PersonEditPage(final Long personId) {

super(new PersonModel(personId));

Form form = new Form("form",
new CompoundPropertyModel(getModel()));
add(form);
form.add(new TextField("firstName"));
form.add(new TextField("lastName"));
form.add(new TextField("username"));

form.add(new Button("saveButton",
new Model("Save")) {

public void onSubmit() {
Person person = (Person) PersonEditPage
.this.getModelObject();
// save person
}

});
}

The page simply consists of three text fields for the person's properties and a button to submit the changes. In this example, PersonModel is a LoadableDetachableModel for Person entities. This can be implemented easily, for example by inheriting from GenericLoadableDetachableModel introduced in the previous article:

public class PersonModel
extends GenericLoadableDetachableModel {
public PersonModel(Long id) {
super(Person.class, id);
}
}

Now, in this situation, the combination of the LDM with an OSIV-Filter (i.e. the OSIV-LDM-Pattern) is very elegant for serveral reasons.

  • The LDM keeps session size small, as the entities are not put into the HTTP session but are always fetched from the database on demand instead (if the haven't been fetched already).

  • As a result, entities are not detached (Hibernate detached) between requests.

  • The OSIV pattern opens a Hibernate session at the beginning of a request and keeps it open until all components have been rendered. So within a request, entities are not detached, as well.

  • Consequently, when OSIV is used with LDMs, entities will never be in detached state (neither within a request, nor between request).


In the example above, the PersonModel is attached to the page at page construction. During the render phase, the first time the model object is accessed it is fetched from the database. Until the end of the render phase, the OSIV keeps the Hibernate session open, so the entity is not detached. During event processing, as in Button.onSubmit(), Wicket first loads the model object, so it is fetched from the database (it is in persistent state), and then applies any changes to it. So, in Button.onSubmit() above, the person object is still attached to the Hibernate session and changes have been applied. Consequently, we never have to deal with detached entities or LazyInitializationExceptions at any point in a request cycle.

OSIV-LDM-Pitfall 1
But there are some things to be aware of. In the example above, when Button.onSubmit() is called, Wicket has pulled the entity from the model (from the database) before and has applied the converted and possibly validated input to it, for example the user could have changed the username of the person. At this moment, the entity is still attached to the Hibernate session. So, there is nothing more to do to save the changes to the database, because at the end of the request, the session will be closed by the OSIV-Filter and the changes will be flushed to the database ... But if we run the example above, we'll eventually recognize that the changes are not persisted to the database. So, let's try a bit harder and call session.saveOrUpdate(person):

public void onSubmit() {
Person person = (Person) PersonEditPage
.this.getModelObject();
sessionFactory.getCurrentSession()
.saveOrUpdate(person);
}

Nothing. The changes are still not persisted to the database.

The reason is, that the OSIV-Filter will by default set the flush mode of the session to FlushMode.MANUAL, which means that the session will not get flushed (synchronized to the db) on close or in between. To solve the problem we have to flush the session manually by calling session.flush():

public void onSubmit() {
Person person = (Person) PersonEditPage
.this.getModelObject();
sessionFactory.getCurrentSession()
.saveOrUpdate(person);
sessionFactory.getCurrentSession().flush();
}

Okay, this was an easy one. Let's tackle the next pitfall.

OSIV-LDM-Pitfall 2
The example above uses kind of a bad practice. Instead of handling persistent state in a Wicket component, it's recommended to move this code into the service layer, which takes care of transaction handling. [The OSIV-Filter does not do any transaction handling, everything you do in Wicket components is out of any transactional scope.] Let's improve our code by checking if the user changed the username of the person to a username that already exists in the database. If so, the application should reject the change. For this purpose the submit method calls a transactional person service:

public void onSubmit() {
Person person = (Person) PersonEditPage
.this.getModelObject();
try {
personService.updatePersonDetails(person);
// show success message
} catch (DuplicateUsernameException e) {
error("Username " + e.getUsername()
+ " already exists");
// show error message
}
}

The service method PersonService.updatePersonDetails(person) is called to update the person details. This method first queries all persons with the same username as the person provided as the argument from the databse. If there is no other person with this username, the person is updated with the new username by calling session.saveOrUpdate(). Otherwise, if there is a person with the same username, a DuplicateUsernameException is thrown:

@Service @Transactional
public class PersonService implements IPersonService {

@Autowired
private IPersonDao personDao;

public void updatePersonDetails(Person person)
throws DuplicateUsernameException {

// Check for duplicate username
Person checkPerson = personDao
.getPersonByUsername(person.getUsername());

if (checkPerson == null || checkPerson == person) {
personDao.saveOrUpdate(person);
} else {
throw new DuplicateUsernameException(
person.getUsername());
}
}
}

If we give it a try, and change the username of one person to the username of another person, a DuplicateUsernameException is thrown and it looks like everything works fine. But somehow the person's new username is persisted to the database, although this username already exists! (Assume for this example that there is no database unique constraint on username). The DuplicateUsernameException was thrown, so obviously personDao.saveOrUpdate(person) has never been called, so how did the changes get persisted?

The key is, that the Spring transaction manager has changed the session's flush mode from FlushMode.MANUAL (set by the OSIV-Filter) to FlushMode.AUTO at the beginning of the transaction. In this mode, Hibernate sometimes flushes the session before queries to ensure that the query does not return stale data. In the example, Hibernate flushes the session before the query executed by personDao.getPersonByUsername(person.getUsername()). The result of this flushing is, that person, which includes the new username, is also flushed to the database, unexpectedly. This is, because of the OSIV-LDM-Pattern the person has been attached to the Hibernate session from the beginning of the request. If it had been detached, it would not have been flushed.

Note: The same would also happen, if a query is called from onSubmit() and then a service is called.

The best advice, I can give, is to always be aware of this side effect of the OSIV-LDM-Pattern. When you have identified a problematic case, there are some ways to get around these problems. One is to validate the input before it gets applied to the model object. In the case above, we could implement a Wicket validator, that checks for duplicate usernames. Wicket validators are executed before the changes are applied to the model object, so if the username already exists, the username of the person would not be changed. Another, but not quite elegant way, is to use some kind of DTO like helper objects, which are used as model objects instead of the entities themselves. The changes have to be transferred from the DTO to the entity manually then.

Conclusion
The OSIV-LDM-Pattern is a very elegant way to handle Hibernate entities. Sometimes the problems above are quite hard to identify, but in real world situations they are quite rare and in most cases they can be tackled easily.

Finally, I'd like to mention, that the OSIV pattern has some further consequences, e.g. related to session handling after exceptions/transaction rollbacks, and because only one session is used for each request. But these topics are out of the scope of this article.


Comments are welcome.

Tuesday, March 17, 2009

Wicket Patterns and Pitfalls #2

This is the second episode in a series of articles (see
here for the first article) 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. This article illustrates how Wicket's SpringBean-Annotation can lead to subtle problems.

Be Aware of Spring Bean Proxies


This article shows a Hibernate example where Wicket's SpringBean-Dependency-Injection can have subtle side effects, but it can also have side effects in many other scenarios.

Environment: Wicket, Spring
Example Environment: Wicket, Spring, Hibernate, OpenSessionInView


The Example
When using Wicket in a Spring container the most common way to use Spring's dependency injection is to annotate fields to be injected with the @SpringBean annotation. As a simple example let's take a Hibernate entity Person ...

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

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

public class PersonPage extends WebPage {
public PersonPage(Long personId) {
Person person = getPerson(personId);
add(new Label("firstName",
new PropertyModel(person, "firstName")));
add(new Label("lastName",
new PropertyModel(person, "lastName")));
}
...
}

For the moment let's don't mind using an inappropriate Model for the person entity (we could use a LoadableDetachableModel instead). Now assume that we have configured an OpenSessionInViewFilter that cares about opening a Hibernate session at the beginning of a request and closing it after rendering the response on our behalf. In this case, one way to implement getPerson(personId) would be to use the recommended way of calling SessionFactoryUtils.getSession(sessionFactory, allowCreate) to get a Hibernate session and call get(personId) on it. We'll let Wicket inject a SessionFactory by @SpringBean for that purpose:

@SpringBean
private SessionFactory sessionFactory;

private Person getPerson(Long personId) {
return (Person) SessionFactoryUtils
.getSession(sessionFactory, true)
.get(Person.class, personId);
}

The Problem
As we know that the OpenSessionInViewFilter opened a session on our behalf, we can be sure that the call to SessionFactoryUtils.getSession() returns that session. But this is not the case and we won't recognize it immediately! The code works well at first look and the person will be displayed. So what's wrong with this code then?

In order to open a Hibernate session the OpenSessionInViewFilter pulls the session factory out of the Spring application context, then opens a session on it and basically puts it into a Map of registered open sessions which is held in a ThreadLocal. The session factory instance is used as the key for that map. The other way round, SessionFactoryUtils.getSession(sessionFactory, allowCreate) looks up a session in the same map with the sessionFactory provided to getSession(sessionFactory, allowCreate) as the key. So in this map the session, which was opened by the OpenSessionInView before, should obviously be found, because the OSIF has put it there under the same key, see the following figure.



What breaks this in the case above is that the sessionFactory object, that was injected into the page, is really a proxy of the sessionFactory.* The OSIF on the other hand pulled the sessionFactory directly from the application context, which is not a proxy. So consequently we tried to lookup the session opened by the OSIF in the map with an instance of a proxy of the sessionFactory as the key instead of the real sessionFactory. As these objects are not equal, the session opened by the OSIF is not found, see figure.


* Wicket injects proxies of Spring Beans instead of the beans themselves, because these would get serialized as parts of Wicket components and along with these beans the whole application context might get serialized.


The Consequences
Primarily this article is just aimed at showing that one should be aware of Wicket's @SpringBean injection. But just out of curiosity, let's have a deeper look at the consequences in this particular Hibernate scenario.

At first look the code just works fine. But what really happens in this example is that a new Hibernate session is created, because we called getSession(sessionFactory, allowCreate) with true as second argument. We could just don't care that a new session is opened, but actually this session is not closed after the request. The OSIF only closes sessions it opened itself, so our manually opened session just stays open (forever). We could turn on Hibernate statistics to see that each request adds one more open session, which is something you really wouldn't want.

What happens if we call SessionFactoryUtils.getSession(sessionFactory, false) (false as second argument) telling SessionFactoryUtils not to open a new session if none exists already? In this case an exception is thrown, telling us that no open session is available, which is quite healthier than silently opening more and more new sessions, which aren't closed afterwards. And after reading this article you even won't have to scratch your head why the session opened by the OSIF is not found and an exception is thrown.

The Solution
Actually, I think the example above is not quite common, as in most cases one would probably not call SessionFactoryUtils from a Wicket component directly. Instead I'd suggest to call a DAO method or another Spring Bean to load the person. These objects could be injected using @SpringBean. The fact, that these are really proxies of the Spring Beans as well does not matter in this case. It's just important, that these will have access to the session factory directly instead of through a proxy.

To close this article, I'd like to mention a kind of funny side effect of the example above. The nice (not really) thing about it is, that one wouldn't even get LazyInitializationExceptions accessing the person on post backs, because the session that loaded the person is not closed, so the person instance is not detached. And that even without using a LoadableDetachableModel ;-).


Stay tuned. More posts are coming soon. Leave a comment!

Wednesday, March 11, 2009

Wicket Patterns and Pitfalls #1

This is the first 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 some might be very specific, but others apply for more general cases.


Hibernate IDataProvider and LoadableDetachableModel



Environment: Wicket, Hibernate, Spring, (OpenSessionInView)

Wicket and the HttpSession
When Wicket processes a request to a page, the page including the hierarchy of components and models that make up the page is constructed. Then the page including all its components and models is put into the PageMap, which in turn is put into the Wicket session, which is put into the HttpSession (it is actually put into a SessionStore, but basically it's put into the HttpSession by default). As the HttpSession is a critical resource, care has to be taken of the size of the page. Especially the size of the models, that are used by the components, can be of critical size (imagine huge amounts of table data). For this case, Wicket provides a LoadableDetachableModel - a model that holds a reference to the model object in a transient field, which is set to null after the request, so the model object is not put into the session. When the model object is needed/attached again later, LoadableDetachableModel updates the reference to its model object.

The following sections show a way to implement LoadableDetachableModel in a Spring/Hibernate environment. Along with this, an implementation of IDataProvider is presented.

The Example
Lets take, for instance, a table that displays a list of Person objects. Here's the Person class as a Hibernate entity. DomainObject is an interface for all the domain classes, which provides a method getId(), which returns the Hibernate id of the entity.

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

The page that displays the persons uses a DataTable:

public PersonListPage() {
IDataProvider personDataProvider = ...
List<IColumn> columns = new ArrayList<IColumn>();
list.add(new PersonNameColumn());
... // more columns
add(new DataTable("table", columns.toArray(
new IColumn[0]), personDataProvider, 20));
}

DataTable requires an IDataProvider, which delivers the data. Lets first have a look at how to implement this in a reusable way.

A generic IDataProvider implementation
The following implementation of an IDataProvider assumes the existence of a generic DAO IGenericDao, which provides methods for retrieving lists of different classes of entities from the database (the implementation of this generic DAO is out of the scope of this article).

public class GenericDataProvider<T extends DomainObject>
implements IDataProvider {

@SpringBean
private IGenericDao dao;
private Class<T> entityClass;

public GenericDataProvider(Class<T> entityClass) {
this.entityClass = entityClass;
InjectorHolder.getInjector().inject(this);
}

public Iterator iterator(int first, int count) {
return dao.findAll(entityClass, first, count).iterator();
}

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

public int size() {
return dao.count(entityClass);
}

public void detach() {}
}

The type T of GenericDataProvider specifies the type of domain objects this data provider retrieves. In the example, this would be Person. GenericDataProvider gets access to the generic DAO by dependency injection (@SpringBean). By default, Spring Beans can only be injected into Wicket components (IDataProvider is not a component), but we can inject Spring Beans exactly the same way that Wicket uses for components by calling InjectorHolder.getInjector().inject(this) from the constructor.

There's not much more to say about this IDataProvider implementation, but that it uses a generic LoadableDetachableModel, which is described in the next section. This basic version of a generic LoadableDetachableModel works for all of the domain objects. A more elaborate version could provide ways to restrict the result set by applying additional criteria, but I'll leave this up to you.

A generic LoadableDetachableModel implementation
For the implementation of a Hibernate LoadableDetachableModel we again make use of the generic DAO as well as of the interface DomainObject mentioned above.

public class GenericLoadableDetachableModel<T extends
DomainObject> extends LoadableDetachableModel {

@SpringBean
private IGenericDao dao;
private Class<T> entityClass;
private Long entityId;

public GenericLoadableDetachableModel(T entity) {
super(entity);
entityId = entity.getId();
entityClass = (Class<T>) entity.getClass();
InjectorHolder.getInjector().inject(this);
}

public GenericLoadableDetachableModel(Class<T> entityClass,
Long entityId) {
super();
this.entityClass = entityClass;
this.entityId = entityId;
InjectorHolder.getInjector().inject(this);
}

protected T load() {
return dao.get(clazz, entityId);
}

}

There's nothing special about this code, but this is a LoadableDetachableModel which is applicable to any domain object. It uses the same way to inject Spring Beans as the GenericDataProvider above.

There's one thing, though, to be aware of when the first constructor is used. The entity passed as an argument might be an instance of a Hibernate proxy in some cases. For example, suppose you've retrieved the entity by calling session.load(id) before. In this case Hibernate really returns a proxy instead of the entity itself. When this proxy is passed to the constructor, entity.getClass() will return the proxy class instead of the entity class. But there's a way around this. Lets change the constructor to make it aware of Hibernate proxies:

public GenericLoadableDetachableModel(T entity) {
super(entity);
entityId = entity.getId();

if (entity instanceof HibernateProxy) {
HibernateProxy proxy = (HibernateProxy) entity;
clazz = (Class<T>) proxy.getHibernateLazyInitializer()
.getPersistentClass();
} else {
clazz = (Class<T>) entity.getClass();
}

InjectorHolder.getInjector().inject(this);
}

This code checks for a HibernateProxy and eventually determines the persistentClass, which is what we want. This way the GenericLoadableDetachableModel can even be used with Hibernate proxies.

OpenSessionInView and GenericLoadableDetachableModel
The nice thing about the GenericLoadableDetachableModel is that it is applicable to all of our domain objects in a generic way, and in general LoadableDetachableModels keep the session size small. But in addition, there's another nice side effect when using GenericLoadableDetachableModel in combination with the OpenSessionInView pattern.

To show this, suppose we use GenericLoadableDetachableModel without an OpenSessionInViewFilter/Interceptor. When a component that uses a GenericLoadableDetachableModel is attached along with its model, the load() method of the GenericLoadableDetachableModel is called, which calls the generic DAO. The DAO opens a Hibernate session, retrieves the entity from the database and then closes the session. After that, the entity is detached (in a Hibernate sense) because the session is closed and LazyInitializationExceptions might eventually be thrown when we try to navigate an uninitialized association. Additionally, if we did not use a LoadableDetachableModel (with or without OSIV), but a non-detachable model, the model object would also be detached (Hibernate detached) on postbacks, because the model was put into the session including its model object (the entity).

This changes when we use an OpenSessionInViewFilter, which opens a session at the beginning of a request and closes it at the end of a request (details about the OSIV pattern is out of the scope of this article). This in combination with a LoadableDetachableModel leads to model objects, which are actually never detached (in a Hibernate sense). On the one hand, this is a consequence of the fact that the session is kept open after the call to load(), so that the entity is not detached. On the other hand, this is a consequence of the fact, that model objects are detached in a Wicket sense by the LoadableDetachableModel after the request, so that they will not be put into the Wicket session. So on postbacks the model object is not pulled from the session, but it is retrieved freshly from the database instead, because model.getObject() calls load() on LoadableDetachableModel. So, as a client you will actually never see any detached model objects and, as a result, no more LazyInitializationExceptions.

Note: The OpenSessionInView pattern needs special attention regarding transactions. This will be topic of a subsequent article in this series.


That's it for now. The next article will be about a pitfall using the @SpringBean annotation, so stay tuned.