Home > Entry > Versioning Your Wicket Models

Versioning Your Wicket Models

June 13th, 2007

Occasionally you’ll run into a use case where multiple users might edit the same object/data at the same time. If two people are editing the same information, generally the last one to submit the web form wins (last writer). ORM frameworks, like Hibernate, provide the ability to detect when the object’s version changed. If you’re using something like Wicket, with it’s detachable model support, integrating version support is very easy.

What’s a detachable model?
Unlike standard Wicket models, which serialize the wrapped object to the session store, detachable models only contain an identifier used to reload the object when needed. This way, less memory and disk (in Wicket 1.3) is used. Detachable models should generally be used throughout your Wicket applications.

Let’s create a simple detachable model by subclassing LoadableDetachableModel:

public class MyModel extends LoadableDetachableModel {

  private Integer id;
  private MyDao dao;

  public MyModel(Integer id, MyDao dao) {
    this.id = id;
    this.dao = dao;
  }

  /*
    This method is inherited from LoadableDetachableModel
    and must be implemented by concrete classes.
  */
  public Object load() {
    return dao.get(id);
  }
}

When Wicket’s request cycle starts, MyModel’s load() method is called, retrieving the object using the DAO. (You might be concerned about the model storing a reference to the DAO, but if you’re using something like Wicket’s Spring Annotation package, the DAO won’t be serialized with the model.) As you can see, the DAO has the object’s id, which is just enough information to retrieve the object.

Now, we need to add support for detecting the version change:

public class MyModel extends LoadableDetachableModel {

  private Integer id;
  private Integer version;
  private MyDao dao;

  public MyModel(Integer id, Integer version, MyDao dao) {
    this.id = id;
    this.dao = dao;
    this.version = version;
  }

  /*
    There are a few different ways to detect a version
    mismatch. I'm being intentionally illustrative here.
  */
  public Object load() {
    MyObject myobj = dao.get(id);
    if (version == null) {
      version = myobj.getVersion();
    }
    else  if (!myobject.getVersion().equals(version)) {
      throw new MyVersionMismatchException(MyObject.class, id, version);
    }

    return myobj;
  }
}

When the object is loaded, we first ensure the version isn’t null and set it to the object’s current version if it is. This might be the first time we’ve seen the object, so we may not know the version when the model was created. Setting it allows us to check for differences later.

If the version is not null, we do an equality check. If the versions aren’t equal, we throw a fictional runtime exception handled by the Wicket component using the model.

Let’s step through the scenario using our version-sensitive detachable model:

  • Sue clicks the “Edit MyObject” link on the web page. The edit page creates a new instance of MyModel which loads the relevant MyObject instance using the passed id. Since the version is null when load() is called, it’s set.
  • Lucy also clicks “Edit MyObject” for the same object Sue is editing. The same process with MyModel occurs.
    Sue clicks submit, saving her object.
  • Lucy clicks submit. When MyModel#load() is called, the version from the loaded object (the one Sue saved, thereby updating the version number) doesn’t match the version number in the model, so the exception is thrown.
  • The exception handling code should inform Lucy about the version mismatch and prompt her to reload the object for editing.

The combination of Hibernate and Wicket allows for easy handling of a feature traditionally difficult to implement.

nick Entry

  1. No comments yet.
  1. No trackbacks yet.