Module mechanism
Magnolia CMS has a modular architecture. A module is a independent component that performs a particular task or is used to package content and functionality. For an introduction into the module mechanism, see Modules in the Technical Guide
- Configuration items
- Module descriptor elements
- Module version handling
- Dependencies
- Servlets
- Repositories
Configuration items
Magnolia provides standard components including controls, templates, paragraphs, and dialogs. If you create customized implementations of such components you should configure them in your module.
The configured items must be stored directly under the module node in order to be automatically registered by Magnolia. Because Magnolia monitors configured items, any changes in the configuration of registered items will immediately be active. The config node uses Content2Bean to populate all registered module classes as Java Beans with the content of the config node. That is why it is important to put specific configuration details in the config node.
This is a list of available configuration items.
| Configuration item | Function of Configuration Item | Details or Example |
|---|---|---|
| config | Module-specific configuration which will be available via the module class (see below). | Config contains parameters and data for your module |
| templates | Template definition. Templates define page composition. They can use FreeMarker, JSP or a custom templating language. | For example, stkNews is a template definition provided in the Magnolia Standard Templating Kit (STK). Its purpose is to render a news page. |
| paragraphs | Paragraph definition. Paragraphs can use FreeMarker, JSP or a custom templating language. | A paragraph is a content subelement of page. The paragraph definition defines the script which is used to render the content. It also defines the dialog used to edit the content. For example, one of the most used paragraphs is stkTextImage provided in STK. It's purpose is to render a subtitle, some text and an image. |
| dialogs | Define a configured dialog. | Dialog to edit the content of sample text & image of paragraph |
| controls | Define your own dialog control. | Allows editing of the control |
| trees | Define a tree to be used in AdminCentral and when browsing in dialogs | Defines where in the tree will be displayed in the Website view of AdminCentral. |
| commands | Define commands to use with the Magnolia command management. | Activates the command |
| pages | Define a page to be used in AdminCentral. | For instance, JCR Queries in the Tools menu. |
| virtualURIMapping | Makes the rendering depend on a URI pattern. | Default URI: defines which page should be rendered if no path is specified |
| template-renderers | Define a new template type. You can integrate logic before rendering a page or use your preferred rendering engine. | Magnolia ships with JSP and FreeMarker template renderers. You can also create a custom one for another templating language. |
| paragraph-renderers | Define a new paragraph type. You can integrate logic before rendering a paragraph or use your preferred render engine. | Magnolia ships with JSP and FreeMarker paragraph renderers. You can also create a custom one for another templating language. |
Module descriptor elements
| Element | Description |
|---|---|
name | The functional name of the module. You will see this name in the config workspace |
displayName | The display name of the module |
description | A full description of the module |
class | The name of a module class |
versionHandler | The name of the class handling version changes |
version | The module version |
properties | Properties which can be used with the version handler |
dependencies | Dependencies on other modules - the module will install only after the specified modules |
servlets | Servlets which will be included in the servlet filter |
repositories | The repositories which must exist or will be created for this module |
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);
SystemProperty class instead:
SystemProperty.getProperty(PROPNAME, "default");
Module version handling
The 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. Upon each startup of Magnolia the version handler provides a list of deltas.
Delta
A Delta is a list of Tasks to be executed during a version change. The sample module's version handler provides three Deltas which can be referred to as an example.
| Delta (from Version) | Task |
|---|---|
| 3.5 |
|
| 3.5.4 |
|
| 3.6 |
|
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 will examine Tasks and Conditions in more detail later in this chapter.
Abstract version handler classes
If you want to create your own version handler you will not have to start from scratch. There are some abstract classes for common cases which can be used. It is good practice 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 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 the AbstractModuleVersionHandler and triggers the most common installation tasks (see table above):
|
If you do not specify a version handler in the module descriptor, the DefaultModuleVersionHandler is used which performs some basic install tasks:
| Task | Description |
|---|---|
| SetupModuleRepositoriesTask | This task bootstraps empty repositories defined in the module descriptor, grants them to the superuser and subscribes them so that activation can be used. |
| ModuleBootstrapTask | This task bootstraps the necessary module repository content which is provided as multiple XML-export files under "/mgnl-bootstrap/moduleName". |
| SamplesBootstrapTask | This task bootstraps the module's sample repository content which is provided as multiple XML-export files under "/mgnl-bootstrap-samples/moduleName". |
| ModuleFilesExtraction | This task copies all files under "mgnl-files" which includes the module name as a directory to the web application folder, preserving the path. |
| RegisterModuleServletsTask | This task registers the necessary servlets for this module |
Task
A Task is a lightweight class with only minimal necessary code to augment configuration during module installation. The important method in the Task interface is:
void execute(InstallContext installContext) throws TaskExecutionException;
A good-citizen task should execute itself responsibly: it should know what to do in case of problems. For instance, fixable or irrelevant issues should usually just be logged and standard InstallContext methods should be used, allowing the developer/user to fix the logged issues at a later time. The task could also potentially perform backups of nodes when extensive modifications are performed so that the user can refer to a pre-alteration backup in case of problem. In the event of an unrecoverable issue, the Task could also automatically perform a TaskExecutionException, which will interrupt and cancel the module's installation, update and startup. If a TaskExecutionException must be thrown, keep in mind that the exception message will still be shown to the end user, so try to keep the exception messages simple and intuitive.
There is already a set of predefined and abstract Tasks available in the package info.magnolia.module.delta which can be used. Here are some of the most useful: AbstractTask, AbstractRepositoryTask, AbstractConditionalRepositoryTask, AllChildrenNodesOperation, AllModulesNodeOperation.
Also interesting are delegate Tasks:
ArrayDelegateTask, ConditionalDelegateTask, PropertyExistsDelegateTask, PropertyValueDelegateTask.
For the complete list of Tasks, please consult the javadoc.
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);
Dependencies
You can define runtime or install time dependencies (not build dependencies). If you define a dependency on a module, then this module will be installed and started before your module. A dependency can be optional which means that if an optional module is not present, installation will proceed, if the optional module is present, this module will be installed first. The dependencies could look like this:
<dependencies> <dependency> <name>core</name> <version>3.6.0/*</version> </dependency> <!-- in case cache module is present, make sure we install after so we can add a bypass --> <dependency> <name>cache</name> <version>3.6.0/*</version> <optional>true</optional> </dependency> </dependencies>
from version/to version where a version number consist of three parts: major version.minor version.patch level where the latter two parts are optional. For a strict version dependency just use one version string.
Taking * for the from version means "to version or lower"
Taking * for the to version means "from version or higher"
Some examples:
| Example | Description |
|---|---|
| 3 | Must have major version 3 |
| 3.6 | Must have major version 3 and minor version 6 |
| 3.6.3 | Must have major version 3 and minor version 6 and patch level 3 |
| 3/* | Must have major version 3 or higher |
| 3.6/* | Must have major version 3 and minor version 6 or higher |
| 3.6.3/* | Must have major version 3 and minor version 6 and patch level 3 or higher |
| */3 | Must have major version 3 or lower |
| */3.6 | Must have major version 3 and minor version 6 or lower |
| */3.6.3 | Must have major version 3 and minor version 6 and patch level 3 or lower |
| 3.5/3.6.2 | Version not lower than 3.5 and not higher than 3.6.2 |
Servlets
Instead of defining servlets in web.xml, servlets can be defined in the module descriptor using the same values as in web.xml. The DMS module for example registers a servlet to deliver the documents:
<servlets> <servlet> <name>DMSDownloadServlet</name> <class>info.magnolia.module.dms.DMSDownloadServlet</class> <comment>DMS download servlet</comment> <mappings> <mapping>/dms/*</mapping> <mapping>/dms-static/*</mapping> </mappings> </servlet> </servlets>
ModuleVersionHandler.
Servlet initialization parameters
You can specify initialization parameters for servlets in the module descriptor file. These parameters are the equivalent of servlet initialization parameters in a web.xml file. Use the following syntax in the descriptor:
<params> <param> <name>name</name> <value>value</value> </param> </params>
Examples:
Repositories
Repositories and/or workspaces can be defined in the module descriptor. If necessary Magnolia initializes these workspaces before the installation starts. As an example look at the data module:<repositories> <repository> <name>magnolia</name> <workspaces> <workspace>data</workspace> </workspaces> <nodeTypeFile>/mgnl-nodetypes/magnolia-module-data-nodetypes.xml</nodeTypeFile> </repository> </repositories>