View source | Discuss this page | Page history | Printable version   
Toolbox
Main Page
Upload file
What links here
Recent changes
Help

PDF Books
Add page
Show collection (0 pages)
Collections help

Search

How to create build validations and module scripts

Contents

Objective

In this howto article, we will create both a Build Validation and a Module Script. They are both very similar concepts, and are also implemented in a very similar way, so we are going to describe them in the same document.

Build Validations

A build validation in Openbravo is a Java class which is executed at the beginning of the update.database task, and which returns a list of errors. If there is one or more errors, the build is stopped, and the errors are shown to the user.

Because of the fact that the Build Validation can stop the build process, it is very important that it follows these rules:


Validationerror.jpg

Please see this image as an example:

BuildValidation.jpg

The build validations main use is to stop the build because the instance is in such a state that rebuilding the system cannot be safely done. In modules, validations can be used to stop the build in case the module cannot be installed safely in the system for some reason.

So, for example, a validation could be used to check if the user has done a necessary manual setup step that cannot be automated. Or a validation could also be used to check if the user has filled some data which is needed for the module to be installed correctly.

Build validations are a different piece of code in Openbravo, in that they are distributed as binaries (compiled classes), which are executed directly without them being compiled on the run. The packaging task for modules will automatically include the binaries inside the .obx file, the developer should only make sure that the classes were compiled before packaging the module.

Bulbgraph.png   Note: Build validations shouldn't be a common case. Normally, they should only be needed when there was a mistake in a previous version of the module, or Core. The ultimate result for a validation is that, if it detects what it was meant to detect, the user will need to do manual actions to fix the problem, and this should be avoided if possible by all developers

Introduction to the implementation of build validations

The main steps to create a build validation are:

  1. Write it (you need to create a Java class for each validation you want to do).
  2. Compile it (Build validations are compiled separately from the rest of the Openbravo code, using a specific ant compile task).
  3. Test it (you should carefully test the validation before including it in your module, or in Core).
  4. Add it to the module, or Core (Don't forget to add the binary classes too, as they are needed, in addition to the Java source files. ant package.module will automatically add the files to the .obx file, but you need to manually add the binary files in addition to the source files to the Mercurial repository if you are using one for your module, or if you want to add the validation to Core).


To create a build validation, you need to create a class which extends the org.openbravo.buildvalidation.BuildValidation class. This is an abstract class which has one abstract method: List<String> execute()

This method needs to be implemented. The class will be loaded at the beginning of the update.database task, and this method will be called. As you can see, a List of Strings must be returned. If the list is empty, the build will continue. If the list contains at least one string, every string will be shown to the user, and the build will stop. Every string is supposed to be a meaningful error message, which shows the user what does he need to fix in his system for the validation to pass.

Writing the build validation

As was just explained, a build validation is nothing more than a class which extends the org.openbravo.buildvalidation.BuildValidation class, and implements the abstract execute method. Here you can see a small example:


 
 
public class ValidationExample extends BuildValidation {
 
  public List<String> execute() {
    try {
      ConnectionProvider cp = getConnectionProvider();
      PreparedStatement ps = cp
          .getPreparedStatement("SELECT COUNT(*) FROM C_Bpartner WHERE name IS NULL");
      ps.execute();
      ResultSet rs = ps.getResultSet();
      rs.next();
      ArrayList<String> errors = new ArrayList<String>();
      if (rs.getInt(1) > 0) {
        errors
            .add("There are business partners which don't have a defined name. Please fill the name of every business partner before installing the module MyModule.");
      }
      return errors;
    } catch (Exception e) {
      return handleError(e);
    }
  }
}

In this example, you can see the main points of any build validation:

You can also use SqlC if you want to do the database operations.

 
public class ValidationExample2 extends BuildValidation {
 
  public List<String> execute() {
    try {
      ConnectionProvider cp = getConnectionProvider();
      ArrayList<String> errors = new ArrayList<String>();
      int numBpartners=Integer.parseInt(ValidationExample2Data.queryBPartners(cp));
      if (numBpartners > 0) {
        errors.add("There are business partners which don't have a defined name. Please fill the name of every business partner before installing the module MyModule.");
      }
      return errors;
    } catch (Exception e) {
      return handleError(e);
    }
  }
}

This needs the following xsql file:

 
<?xml version="1.0" encoding="UTF-8" ?>
 
<SqlClass name="ValidationExample2Data" package="org.openbravo.buildvalidation">
  <SqlMethod name="queryBPartners" type="preparedStatement" return="string">
      <SqlMethodComment></SqlMethodComment>
      <Sql><![CDATA[
         SELECT COUNT(*) FROM C_Bpartner WHERE name IS NULL
          ]]>
      </Sql>
  </SqlMethod>
</SqlClass>

The class source files themselves should be inside the module folder, in the folder: src-util/buildvalidation/src

And they should follow the standard Java package rules. The folder will not exist if it's your first validation, so you will need to create it.

Compiling the build validation

Warn-icon.png   Build Validations should be (must be in case they are going to be included in Openbravo 3 distribution or in Retail pack) compiled using, at most, latest supported JDK version.

To compile the build validation, you use the following command:

 
ant compile.buildvalidation -Dmodule=javapackageofmodule

If you want to compile the validations of Openbravo Core, the module property needs to be set to "org.openbravo"

This task will compile the Java classes, and copy them to the correct "build" folder in the module, or in the src-util/buildvalidation of Core.

Executing the build validation

The build validations will be automatically executed in the update.database task, or in update.database.mod if the module is being applied. Validations will not be compiled in this task, they need to have been compiled previously to be executed.

Another important point to remark is that the build validations will be executed in every version of the module, or Core, in which they are present (this means, for example, that if a validation exists in Openbravo Core MP15 and later, it will be executed when updating to MP15 or later, and will be executed again when updating to a later version). The developer needs to take this into account (it is advisable not to design validations which are version-dependant, they should always be designed to be generic).

The package.module task will automatically include the compiled binaries in the .obx file, provided that you compiled the validations before packaging the module.

If you are adding a validation to Openbravo Core, remember that you need to include the binary classes (contained in src-util/buildvalidation/build/classes/) to the repository like you would add any source files. If you don't, they won't be executed (because the classes are not compiled by default in the build process, they are executed only if the binary files are there).

Module Scripts

A module script is a task that is executed when a module is being applied in the database. This task is supposed to do operations that need to be done in the database, and cannot be done in a different way.

Conceptually, they are extremely similar to Build Validations, and the main steps involved to create a Module Script are virtually the same, so it's advisable that you read the previous section before this one. The main points of module scripts are the following ones:

Introduction to the implementation of module scripts

As with build validations, a module script is a Java class which extends the abstract class org.openbravo.modulescript.ModuleScript, and implements the execute() method. This execute method will be called by the update.database task. This method will include the logic of the module script, here all the operations will be done.

Writing the module script

Here goes a very simple Module script, which just sets the value of some column to a default in case the column value is null:


 
 
public class ModuleScriptExample extends ModuleScript {
 
  public void execute() {
    try {
      ConnectionProvider cp = getConnectionProvider();
      PreparedStatement ps = cp
          .getPreparedStatement("UPDATE mytable SET mycolumn=0 WHERE mycolumn IS NULL");
      ps.executeUpdate();
    } catch (Exception e) {
      handleError(e);
    }
  }
}

The main two important points that you need to take into account when building the script are:


The class source files themselves should be inside the module folder, in the folder: src-util/modulescript/src

And they should follow the standard Java package rules. The folder will not exist if it's your first script, so you will need to create it.

Compiling the module script

Warn-icon.png   Module Scripts should be (must be in case they are going to be included in Openbravo 3 distribution or in Retail pack) compiled using, at most, latest supported JDK version.

To compile the module script, you use the following command:

 
ant compile.modulescript -Dmodule=javapackageofmodule

If you want to compile the scripts of Openbravo Core, the module property needs to be set to "org.openbravo"

This task will compile the Java classes, and copy them to the correct "build" folder in the module, or in the src-util/modulescript of Core.

Executing the module script

The module scripts will be automatically executed in the update.database task, or in update.database.mod if the module is being applied. Module scripts will not be compiled in this task, they need to have been compiled previously to be executed.

Another important point to remark is that the module scripts work as build validations in regards to execution criteria; that is, they will be executed in every version of the module, or Core, in which they are present (this means, for example, that if a script exists in Openbravo Core MP15 and later, it will be executed when updating to MP15 or later, and will be executed again when updating to a later version). The developer needs to take this into account (it is advisable not to design scripts which are version-dependant, they should always be designed to be generic).

And, as it was explained above, scripts should also be designed to produce the same result if executed multiple times, because they will be executed every time the system is rebuilt, or the module is updated.

The package.module task will automatically include the compiled binaries in the .obx file, provided that you compiled the module scripts before packaging the module.

If you are adding a module script to Openbravo Core, remember that you need to include the binary classes (contained in src-util/modulescript/build/classes/) to the repository like you would add any source files. If you don't, they won't be executed (because the classes are not compiled by default in the build process, they are executed only if the binary files are there).

Defining the module script execution limits

Bulbgraph.png   This feature is supported since 3.0PR15Q4

The module scripts provide by default a couple of mechanisms that allow to control when they should be executed:

Module version limits

It is possible to define a dependency with two versions of a particular module to identify when the module script should be executed:

This way, the module script can be executed only when it is really needed (see image below), avoiding extra time calculations when updating database.


ModulescriptApplicationScheme.png

The dependent module and its limit versions can be set by overriding the getModuleScriptExecutionLimits() method in our ModuleScript subclass:

 
  @Override
  protected ModuleScriptExecutionLimits getModuleScriptExecutionLimits() {
    return new ModuleScriptExecutionLimits("0", new OpenbravoVersion(3,0,27029), 
        new OpenbravoVersion(3,0,27050));
  }
 

Following this code example, we are setting that our modulescript should only be executed when upgrading core module (id = "0") from a version between 3.0.27029 (first execution version) and 3.0.27050 (last execution version). This way, we are avoiding the execution of our modulescript in those cases which it does not apply.

Executing just once

One typical case of modulescripts usage, is to populate the values of a newly added column. So we need to execute the modulescript once. This can be covered by setting just the Last Execution Version.

For example, if we add a new column in version 1.5.0 of a module, we want to execute the modulescript when upgrading from versions previous this version. So we can define its limits as follows:

 
  @Override
  protected ModuleScriptExecutionLimits getModuleScriptExecutionLimits() {
    return new ModuleScriptExecutionLimits(ad_module_id, null, 
        new OpenbravoVersion(1,5,0));
  }
 

Where ad_module_id is the UUID of the module.

This way the modulescript will be executed when upgrading the module from any version prior to 1.5.0 and it will not be executed anymore.

Execute on install

It is also possible to configure whether the module script should be executed when installing the dependent module defined with the getModuleScriptExecutionLimits() method or during the install.source ant task. By default, the module script will be executed in the following cases:

But in case we do not want to execute it in these cases, the executeOnInstall() method should be overridden as follows:

 
  @Override
  protected boolean executeOnInstall() {
    return false;
  }

Executing just on install.source

In case we want to configure a modulescript to be executed just on every install.source, we do not override the executeOnInstall() method and we define the execution limits as follows:

 
  @Override
  protected ModuleScriptExecutionLimits getModuleScriptExecutionLimits() {
    return new ModuleScriptExecutionLimits(ad_module_id, null, 
        new OpenbravoVersion(0,0,0));
  }
 

Retrieved from "http://wiki.openbravo.com/wiki/How_to_create_build_validations_and_module_scripts"

This page has been accessed 6,323 times. This page was last modified on 18 November 2015, at 14:41. Content is available under Creative Commons Attribution-ShareAlike 2.5 Spain License.