Bart Vreeken

Mar 31, 2015

Updating resource bundles in Hippo using Groovy script

 

Often, when deploying a new release through the DTAP environment, resource labels need to be updated as well. For example you added a new label for a button. Or you defined some configuration in a resource label, like a date pattern, which is used into your JSP file (although not considered a best practice, but we – developers - do it anyway). In most cases resource labels are tightly coupled to your release and you can’t afford to miss a label on production.

Oops! A label is missing on production...

Updating the configuration is quite easy: The Hippo CMS uses a XML bootstrap mechanism to add (or change) the HST configuration. However, updating content in the CMS like resource bundles can be quite cumbersome. The process of editing the resource bundle XML is error prone and there is no proper mechanism to add new labels to an existing bundle. So every time you add a new resource label you need to do it manually. For every DTAP environment.

This article describes a solution using Groovy to update your existing resource bundle automatically when deploying a new release.  This strategy aims to ease the process of adding (or delete) labels for developers.

Solution
In brief, our solution consists of three parts. The first part is the data. The data contains all necessary instructions to add one or more labels to an existing bundle. It is stored in well-known property files and located in the any hippo plugin (jar files). Second, we use a utility Java class to read the property files from the classpath. The last part is the Groovy script which makes a call to the utility class, retrieves the data from the property files and eventually updates the resource bundle node with the new label(s).

The property files
The property files contain the instructions to load new resource labels into an existing resource bundle, or to delete an existing one. We came up with a very simple and readable syntax to express these instructions. Basically, the property file holds instructions for one single resource bundle only. Also, the instructions apply to adding or deleting labels. Not both. A typical property file should look like this:

#the ID of the resourcebundle
bundle.id=nl.company.cms.plugins.featurexyz.MyProfileBundle

#the instruction (ADD | DELETE)
bundle.action=ADD

#new message 1
profiel.mijn-gegevens.page.description.message=my profile
profiel.mijn-gegevens.page.description.message_nl=mijn gegevens
profiel.mijn-gegevens.page.description.description=mijn gegevens

#new message 2
...

Although it looks like overkill to have a property file for every single resource bundle, this mechanism works really well when developing new features for the Hippo CMS. The Hippo CMS has a pluggable architecture which makes new features available through plugins. So usually you have only one resource bundle per plugin and one property file to add new labels.

Note: The utility class in the sample download assumes that all property files (used for resource bundle instructions) are located in src/main/resources/labels. The resulting JAR artifact has a /labels package which holds all property files. The files can have any name you like and you can store as many files you need.

 

The Java utility class
The Java utility class is the glue between the property instruction files and the Groovy script. It scans the WebApp classpath for any property files. For every file it parses and processes the properties, creates a Java model structure and returns this model to the Groovy script.

Although this ‘utility glue’ can (probably) be developed in Groovy as well, I believe it’s a good idea to have a separate Java helper for this. Now, this relatively complicated process can be debugged easily and keeps your Groovy script small and clean: It does what it is designed for (separation of concerns): updating your JCR nodes.

Note: As mentioned in Using the updater editor, Groovy scripts are executed using a class loader in the CMS app context. Therefore make sure you put the utility class into the CMS web project or any dependency within the WEB-INF/lib of the CMS.war.


The Groovy script
Groovy scripts allow developers to run scripts against the Hippo (JCR) repository and change existing content. The attached sample script iterates through all existing resource bundle nodes using the following query path: /jcr:root/content/*//element(*,resourcebundle:resourcebundle)

For every bundle node it checks for ‘pending tasks’ by calling the Java utility class. After the bundleList has been received, it starts processing the instructions.

String bundleId = node.getProperty("resourcebundle:id").getString();

List bundleList = ResourceBundleBootstrapUtilities.findResourceBundleConfig(bundleId);

for (item in bundleList) {

  log.debug "Possible candidate key: '${item.getKey()}'"

  boolean exists = doesKeyAlreadyExist(node, item.getKey());

  if (!exists && item.getAction().toString() == "ADD") {

    log.debug "Found non-existing key: '${item.getKey()}'. Will be ADDED";

    addItem(node, item);

  } else if (exists && item.getAction().toString() == "DELETE") {

    log.debug "Found existing key: '${item.getKey()}'. Will be REMOVED";

    removeItem(node, item);

  }

}

Although you can choose to execute the script manually using the Updater Editor, it’s probably a better idea to automate the execution. The Hippo CMS offers a perfect mechanism to automate script execution on startup by adding the script to the /hippo:configuration/hippo:update/hippo:queue in your bootstrap module.

Benefits

  • Easy to use. This strategy makes adding (or deleting) resource labels no longer a painful process for developers. Using property files to add new labels is straightforward and there’s no need to edit XML bootstrap files.

  • Easy to deploy. Developers don’t need to make release instructions for new or deleted labels (they always forget somehow!). Naturally, during deployment there’s no need to create these new labels manually, for every environment.

  • Integrated with your release. Your bundles updates are tightly coupled to your release because you simply put the property files in the software package you want to release.

Drawbacks

  • Local startup can take a bit longer. Depending on the number of resource bundles and property files starting your local environment can take a bit longer than normal.


Conclusion

Updating an existing resource bundle through a DTAP environment  takes some effort. Hippo CMS provides a powerful bootstrap mechanism to add or change (HST) configurations, but the mechanism is not capable of adding or deleting labels.

Fortunately, this problem can be solved easily by using the proposed solution in this article, using property files. New labels can be added in a simple and clean way by developers. Also, it doesn’t require additional effort to release these labels in the next DTAP environment.