Tuesday, August 9, 2011

Optimistic Locking - Play! Way

I would not go into the details of describing what locking or optimistic locking is. There is a great article on wikipedia for reference. I would stop at saying that here I am trying to describe my method of implementing the same in the context of a database within the boundaries of Play! Framework.

A common strategy to build optimistic locking is to add a version field to the model and update the version field on every update. In fact it is so common that JPA has a special annotation for it.

Here is the code for my model class followed by explanation.

@Entity
@Table(name = "REF_BRANCH")
public class Branch extends Model{
  @Version
  @CheckWith(value=OptimisticLockingCheck.class, message="optimisticLocking.modelHasChanged")
  public int version;
  ...
}
@Version is the JPA annotation that will add an auto-incremented column named version to my table (REF_BRANCH) in this case. As a result when I create a new Branch object and persist it, the version field will take a value of 0. Every subsequent update to the above created object will automatically change the value of the version field to 1, 2, 3 ... and so on. The version field above is also annotated with the @CheckWith annotation. More on that in a minute.

I decided to design my application in such a way that failure to acquire a (pseudo) lock before record is updated will be treated as a validation failure. In Play! Framework, custom validation is done by extending the class play.data.validation.Check. Thus I also mark my version field in the model class with the @CheckWith annotation.

public class OptimisticLockingCheck extends Check {
  public boolean isSatisfied(Object model, Object inputVersionObject) {
    try {
      Model modelObject = (Model) model;
      modelObject.refresh();
      Field versionField = modelObject.getClass().getField("version");
      int dbVersion = versionField.getInt(model);
      int inputVersion = ((Integer)inputVersionObject).intValue();
      return dbVersion == inputVersion;
    } catch (Exception e) {
      return false;
    }
  }
}

@CheckWith(value=OptimisticLockingCheck.class, message="some.message") ensures that the above class is used to validate the model instance. A quick reference to the controller's update method will be helpful.
public static void update(@Valid Branch entity) {
  if (validation.hasErrors()) {
    flash.error(Messages.get("scaffold.validation"));
    entity.refresh();
    render("@edit", entity);
  }               
  entity.auditLogs.add(AuditHelper.onUpdate(Security.connected()));
  entity = entity.merge();
  entity.save();
  flash.success(Messages.get("scaffold.updated", "Branch"));
  index();
}

Here update(@Valid Branch entity) ensures that all validations on the Branch object fires before the update method is executed.
One has to ensure that the version field is included in the edit form albeit hidden.

Friday, January 21, 2011

Whack a bit of EXT JS

Sometimes just using an Ext JS class inside of a simple javascript is all that is required as opposed to formally extending one. In this case I want to wrap a Ext.data.store object inside a simple javascript object so I can configure it to perform all my CRUD operations.
The object will be created using a simple method intuitively named init() which will be invoked like this...

dataStore = MyStoreObject.JsonStore.init({
enterpriseId: 'acompany', // send some parameters (config options in javascript speak through the init method
screenId: 'somescreenid', // send some more config options
userId: 'arindam', // and still some more ...
id: 'someId',
root: 'root_of_json',
fields: ['field1', 'field2', 'field3'],
autoLoad: true
});


Now the object itself

MyStoreObject.JsonStore = {
init: function(config){ // all those config opts are contained in config
// constants
... some constants go here for next processing

// url pattern
... some calculations based on the constants and config (see config.enterpriseId)
var urlPattern = P18N_CONTROLLER_NAME + PATH_SEPARATOR + config.enterpriseId 
+ PATH_SEPARATOR + config.screenId + PATH_SEPARATOR + config.userId;
// setup proxy
... some more value setting etc...
var proxy = new Ext.data.HttpProxy({
api: {
read    : urlPattern + PATH_SEPARATOR + READ_FUNCTION,
create  : urlPattern + PATH_SEPARATOR + CREATE_FUNCTION,
update  : urlPattern + PATH_SEPARATOR + UPDATE_FUNCTION,
destroy : urlPattern + PATH_SEPARATOR + DELETE_FUNCTION
}
});
// setup reader
... and some more 
var reader = new Ext.data.JsonReader({
root: config.root,
fields: config.fields
});
// setup writer
... still more 
var writer = new Ext.data.JsonWriter({
encode: false
});
// setup the store
... now we create the Ext object store
var store = new Ext.data.Store({
id: 'MyStoreObject.InternalStore_' + new Date().getTime(),
restful: true,
proxy: proxy,
reader: reader,
writer: writer,
autoLoad: config.autoLoad ? config.autoLoad : false
});
... now we insert a new attribute [viz. store] into our current object (this) and assign the Ext's store to it
this.store = store;
... and return the new object. this way the callers of the init method actually get a fully configured Ext.data.Store object which they are free to use in whatever way they see fit
return store;
}
}