Openbravo Architecture

Openbravo 2.50: Using the Model in your Application Code

dinsdag 28 april 2009

As you may know Openbravo follows a Model-Driven-Development (MDD) approach. The main theme of MDD is generating an application from a model. An aspect which is often ignored by traditional MDD methods is the availability of the model at runtime. Openbravo specifically pays attention to the runtime model and makes it available through an easy-to-use api.

The main advantage of a runtime-model is that it is possible to develop very generic application functionality at model-level. Writing code at model-level is far more efficient than writing specific code for each table. Another advantage of model-level code is that it is often robust for model changes.

Here are some examples of generic application functionality which can make use of the runtime model:

  • security
  • import and export logic
  • archiving
  • tracking/tracing of changes
Some main concepts of the Openbravo runtime model:
  • The runtime model consists of a set of Entities.
  • An Entity is a domain concept like an Order or a Product. Currently in Openbravo an Entity is the same as a table (each table has an Entity representing it and vice versa).
  • An Entity has a list of Properties, for example an id, a name, a description. Some properties are primitives (string, number, etc.), some are single references (from an Order to a Currency), some are many references (from an Order to all its OrderLines).
To make use of the runtime model it is good to understand the Openbravo business object class model.


As you can see, each business object (order, product, etc.) inherits from the BaseOBObject class. The BaseOBObject class offers a number of important methods:
  • getEntity(): to get access to the domain concept (=table) represented by this java class
  • get(String propName): get the value of a certain property
  • set(String propName, Object value): set the value of a certain property
  • getIdentifier(): returns a readable name for the business object
So while the specific subclass has specific set and get methods for each property, the main super class has generic set and get methods to set/get the value of all properties of a business object.

In a runtime model-driven-development approach the code uses the runtime model and accesses objects as a generic BaseOBObject. In Openbravo 2.50 access to the runtime model is provided by the ModelProvider class.

I will illustrate the use of the ModelProvider class and the Openbravo runtime model in general with some example code. This sample code exports all data in an Openbravo instance in just a few lines of code, the code executes the following steps:
  1. get all Entities from the ModelProvider
  2. for each Entity get all records/instances from the databases
  3. for each instance iterate over its properties and read the property value
  4. create a string representation of that property value
// as we read all entities, be an administrator to prevent
// security exceptions
OBContext.getOBContext().setInAdministratorMode(true);

// iterate over all entities
for (Entity entity : ModelProvider.getInstance().getModel()) {

// query for all objects of the entity and iterate over them
final List businessObjects = OBDal.getInstance().createCriteria(
entity.getName()).list();
for (BaseOBObject businessObject : businessObjects) {

final StringBuilder line = new StringBuilder();

// place the entity name so for each line it is known what type is exported there
line.append(entity.getName());

// and iterate over all the properties of the entity
for (Property property : entity.getProperties()) {
// ignore these type of properties, as the children are exported separately
if (property.isOneToMany()) {
continue;
}

line.append(SEPARATOR);

// get the current value
final Object value = businessObject.get(property.getName());
// handle null
if (value == null) {
continue;
}
// export primitives in the same way as xml primitives
if (property.isPrimitive()) {
line.append(XMLTypeConverter.getInstance().toXML(value));
} else {
// export the id of a referenced business object
line.append(((BaseOBObject) value).getId());
}
}
writer.append(line + "\n");
}
}
The data is appended to the writer object (which can be a FileWriter), with the BigBazaar Openbravo sample data this results in a file of about 13mb. The XMLTypeConverter is an Openbravo class which correctly converts primitive types such as a Date, a number, etc. to a String.

You can copy the above code directly in a test case and run it (set the writer and SEPARATOR variables). For how-to create a test case in Openbravo see this how-to.

An additional nice feature of the Openbravo runtime model is that all tables added by modules are automatically made part of the runtime model. So for Openbravo in the runtime model, there is no difference between an Openbravo core Entity/table or a custom module table/Entity.

The runtime model is used extensively by the Data Access Layer and REST web services.

Well I hope that this blog gives some inspiration to try out coding at model level and to make use of the Openbravo runtime model. Thanks for reading, and feel free to ask any (detailed) questions on the Openbravo deverlopers forum!