Magnolia 5.3 reached end of life on June 30, 2017. This branch is no longer supported, see End-of-life policy.

Page tree
Skip to end of metadata
Go to start of metadata

Magnolia's module mechanism facilitates smoother version changes. The idea is that an upgrade or update should be as easy as replacing a module JAR. Magnolia uses the version handler to determine which tasks should be executed. On each startup of Magnolia the version handler provides a list of deltas.

The ModuleVersionHandler interface is a special class which contains a series of tasks (deltas) which are executed during installation or during specific updates. If your module needs to handle its own installation and updates you should provide an implementation of this interface.

Delta

A Delta is a list of Tasks to be executed during a version change. The sample module's version handler provides three example deltas.

Delta (from Version)

Task

3.5

  • Remove menu item for sample templates.
  • Add menu item for sample templates.
  • Remove menu item for sample components.
  • Add menu item for sample components.
  • Remove menu item for sample dialogs.
  • Add menu item for sample dialogs.
  • Install the CSS configuration.
  • Install the JS configuration.
  • Install the paragraph configuration.

3.5.4

  • Remove Kupu editor.

3.6

  • Replace if exists user "bob" with "david".
  • Replace if exists user "joe" with "eve".
  • Replace if exists user "melinda" with "patrick".

More precisely, a Delta can store and apply an additional set of Conditions to be executed only when a version update or revision is deployed. The Tasks of a Delta will only be executed if all specified Conditions are met. We examine Tasks and Conditions in more detail later.

Abstract version handler classes

To create your own version handler you do not have to start from scratch. There are some abstract classes for common cases which can be used. Good practice is to extend one these base classes and implement only the methods you need. There are two abstract version handler classes in the package info.magnolia.module which can be used to create a custom version handler.

Class

Description

AbstractModuleVersionHandler

Extend this class and register your deltas in the constructor using the register method. Add your own install tasks by overriding the getExtraInstallTasks() method. In most cases, modules won't need to override any other method.

DefaultModuleVersionHandler

Extends AbstractModuleVersionHandler and triggers the most common installation tasks (see table above):

  • register repositories, node types and workspaces as stated in the module definition.
  • bootstrap the module's mgnl-bootstrap files.
  • bootstrap the module's mgnl-bootstrap-samples files.
  • extract the module's mgnl-files files.
  • register the module's servlets.

If you do not specify a version handler in the module descriptor, DefaultModuleVersionHandler is used and performs basic install tasks:

Task

Description

SetupModuleRepositoriesTask

Bootstraps empty repositories defined in the module descriptor, grants them to the superuser and subscribes them so that activation can be used.

ModuleBootstrapTask

Bootstraps the necessary module repository content which is provided as multiple XML-export files under /mgnl-bootstrap/moduleName".

SamplesBootstrapTask

Bootstraps the module's sample repository content which is provided as multiple XML-export files under "/mgnl-bootstrap-samples/moduleName".

ModuleFilesExtraction

Copies all files under mgnl-files which includes the module name as a directory to the web application folder, preserving the path.

RegisterModuleServletsTask

Registers the necessary servlets for the module.

Task

A Task is a lightweight class with the minimal necessary code to augment configuration during module installation. The important method in the  Task interface is:

void execute(InstallContext installContext) throws TaskExecutionException;
  • A Task should execute responsibly and respond to issues appropriately.
  • To allow developers/users to fix issues at a later time, fixable or irrelevant issues should be logged and standard InstallContext methods used.
  • A Task should be in place to perform backups of nodes when extensive modifications are performed, meaning that a user can refer to a pre-alteration copy.
  • In the event of an unrecoverable issue, a Task should automatically perform a TaskExecutionException to interrupt and cancel the module installation, update and startup. If a TaskExecutionException is thrown, the exception message should be shown to the end user.
  • Exception messages should be simple and intuitive.

A set of predefined and abstract Tasks is available in the info.magnolia.module.delta package which can be used. Here are some of the most useful:

Abstract taskDescription
AbstractTask Abstract implementation of the Task interface which handles the mandatory properties, name and description.
AbstractRepositoryTask An abstract implementation of AbstractTask which wraps the execute call in a try/catch block. This avoids verbose and irrelevant code lines in actual tasks and leaves room for smarter and more interesting exception handling.
AbstractConditionalRepositoryTask An abstract implementation of a RepositoryTask that only needs to be executed when a specific node is not found in the repository. Can be used to easily create self-check tasks for mandatory configuration.
AllChildrenNodesOperation Executes the abstract method on every child node.
AllModulesNodeOperation Abstract that performs an operation on all modules node found in the configuration repository.

Also interesting are delegate Tasks:

Delegate taskDescription
ArrayDelegateTask A task that simply delegates to an array of other tasks.
ConditionalDelegateTask A task that delegates to another if a condition is true, or to an optional other if it is false.
PropertyExistsDelegateTask A task that delegates to another depending on whether a specified property exists or not.
PropertyValueDelegateTask A task which delegates to another if a property has a given value.

For the complete list of Tasks, see the  Task interface. 

It is customary for modules to expose some tasks that can be re-used by other modules when needed, such as  RegisterNodeTypeTask . The API is designed so that it should be easy for you to write your own specific Task implementations.

Condition

Conditions are checked prior to the installation or update of a module. They check for system configuration which can't be automatically updated, like configuration, dependencies, etc. Modules register their conditions like their tasks, for each successive version. Only if all conditions in delta evaluate positively will the tasks of the delta be executed. The most important method in the  Condition interface is:

boolean check(InstallContext installContext);

Node builder API

The NodeBuilder  API is commonly used in update tasks.

Here's a snippet from  STKModuleVersionHandler that demonstrates its use:

register(DeltaBuilder.update("2.0.1", "")
   .addTask(new NodeBuilderTask("Add editable property to stkSection page", "Adds and sets editable property to true for sectionHeader area on stkSection pages.", ErrorHandling.logging, RepositoryConstants.CONFIG, "/modules/standard-templating-kit/templates/pages/stkSection/areas",
       getNode("sectionHeader").then(
           addProperty("editable", Boolean.TRUE)
       )
   ))
   .addTask(new NodeBuilderTask("Add editable property to areas", "Adds and sets editable property to false on sectionHeader, footer and metaNavigation.", ErrorHandling.logging, RepositoryConstants.CONFIG, "/modules/standard-templating-kit/config/site/templates/prototype/areas",
       getNode("sectionHeader").then(
           addProperty("editable", Boolean.FALSE)
       ),
       getNode("footer").then(
           addProperty("editable", Boolean.FALSE)
       ),
       getNode("branding/areas/metaNavigation").then(
               addProperty("editable", Boolean.FALSE)
       )
   ))
 );

Properties

Properties in the module descriptor can be used to define values for install tasks. You can get the current module descriptor from the InstallContext:

installContext.getCurrentModuleDefinition().getProperty(PROPNAME);

The properties defined in the module descriptor will be included in the Magnolia system properties too, so you might want to use the SystemProperty class instead:

SystemProperty.getProperty(PROPNAME, "default");