Skip to content
OpenCms documentation
OpenCms documentation

The module system

The basic functionality of OpenCms is the core system. All additional features are packaged in modules. This provides the flexibility to adjust each OpenCms installation according to your needs and to easily move functionality or whole websites from one installation to another. In this background topic you learn about the typical structure of modules and get some guidelines on what to package as a module. The user interface for module management is discussed here.

A module is basically the collection of resources from the VFS attached with some configuration. Typically, resources that are required to make up some functionality are grouped as a module. The group can either be very fine-granular, e.g., contain only a new resource type and provide schema, formatter, maybe some Java library and configuration of it, or, it can be very coarse, containing all the resources you need to build up a website, i.e., template JSP, resource types (with schemas and formatters), images, JavaScript, CSS, jars, classes, .... What's the correct choice for you depends on your use case and is discussed later on.

Grouping resources into modules has several advantages, because the modules are more than the simple collections of resources. You can:

  • import and export modules
  • define dependencies between modules
  • use version numbers
  • add module parameters to adjust a module's behavior for varying systems, e.g., configure data-base connections
  • group related modules
  • configure actions triggered when a module is imported, updated or removed.

To avoid naming conflicts, modules are named like Java packages, e.g., com.mydomain.mymodule. This name is also called the module's package name.Your module may additionally also have a more human readable name, as well as a description etc.

Modules can be structured very fine-grained or very coarse. The structure of choice depends on your use case and personal preferences. So, it's only possible to provide guidelines on how to structure modules and on what to encapsulate in separate modules. Regarding the guidelines, there's not much difference from good code design. Some rules of thumb are:

  • Capture things you want to reuse as separate modules.
  • Encapsulate functionality, such that each module has strong dependencies in internally, but few (clear defined) dependencies to other modules.
  • Let your module add real functionality to your system. So let it contain all it needs to add this functionality.
  • Factor out common functionality used by several other modules.
  • Never mix website content into a module containing resources to build up the website (such es templates, content type definitions, ...). You may have modules for a website's content - but separated from the modules exposing template JSPs, content types, scripts etc.

When you encapsulate resources used to build up your website, there are mainly three different approaches, all with pros and cons.

A very common approach is to package each functionality in a separate module. That means:

  • One module containing the template JSP, and resources common for all pages (like some images and JavaScripts, maybe also some Java library). The module does typically not expose content types.
  • One module for each content type (or dynamic function). Each such module contains the schema, the formatters and the formatter configurations as well as resources such as Java libraries, CSS, JavaScripts and message bundles, specific for the content type.

The big advantage of this approach is that you can exchange (in particular update) and reuse each of the small modules independently. You can also easily add new functionality or remove existing functionality by adding or removing modules (given that all dependencies are still fulfilled).

The main idea of the approach is to separate structure and layout. Basically, for a website, you build:

  • One module containing the content type definitions, in particular providing all schemas and resource/explorer type configuration.
  • One module providing formatters and formatter configurations, as well as the template JSP and all the things concerned with layout.

Taking this approach, you can reuse the schema module and just exchange the layouts to build up new websites. This may also nicely interplay with module cloning and is for example the way the modules of the demo websites of OpenCms 9.0 and 9.5 are structured. But the approach is (not yet) as wide spread as the "one-module-one-functionality" approach.

An, at the first glance, very simple approach is to place all the resources that are needed to build up your website in one single module. This is sufficient as long as you do not want to reuse parts of your resources and you can assure that things will not change frequently. Typically, at least for bigger projects, it's not the best choice. Why? In software developement the only constant is change.

Besides the modules specific for your website, there are modules that are intended for widely reuse. You may want to share your own modules, or use modules available by the community. These modules typically:

  • Add a new feature to OpenCms commonly required for various websites
  • Are adjustable easily, in particular concerning layout and server configuration
  • Contain all the resources needed (or build on another "broad audience" module containing common resources).

A collection of freely available modules that extend your OpenCms functionality and available for the "broad audience" are for example the OAMP modules provided by Alkacon. Check them out to get a feeling for that sort of modules.

Common modules could also be used to include frameworks. For example the demo website of OpenCms 9.0 and 9.5 encapsulates the bootstrap basics in a separate module. So this module can be used for each website styled based on the bootstrap framework.

In general, there is no restriction on what resources belong to a module and where in the VFS these resources are located. But there is a best practice that you should apply to avoid confusion or unintended side-effects.

It is strongly recommended to stick to the best practice explained below.

Basically, a module's resources are located in a special module folder. It is named after the modules package name and located under /system/modules/ in the root site of the VFS. For example, the module com.mydomain.mymodule will have the module folder /system/modules/com.mydomain.mymodule/ in the VFS.

Dependent on the actual resources located in the module, the following subfolders are added to the module folder.

Contains the containerpage template JSP(s), usually a single file main.jsp.

Contains elements (JSPs) included by the template (main.jsp), for example a file navigation.jsp.

Contains formatters (JSPs) for content and the formatter configuration files, e.g., an article-formatter.jsp and an article-formatter-configuration.xml

Contains static resources referenced by the template or by formatters, e.g. CSS files, JavaScript-files, images, etc. Typically the different kinds of resources are placed in several different subfolders, e.g., styles/, scripts/, images/, ....

Contains content type definitions (XSDs) that describe the structure of content types, e.g., an article.xsd that describes the structure of an article.

Contains Java libraries (jar files) that are contained in the module. The folder must be exported to WEB-INF/lib/ folder of the RFS. The lib's package name is typically chosen identically to the module's package name.

Contains resources that must be exported to the WEB-INF/classes/ folder of the RFS, e.g., Java classes or Java property files.

A module consists basically of resources in the VFS plus some configuration. Modules are managed via the module management in the administration view and there you can, besides other options, import, export or delete a module. So what happens if you choose one of those options?

The configuration of an installed module is stored in the file opencms-modules.xml in the folder {webapp home}/WEB-INF/config/. For each of the installed modules, the file has a node <module> with subnodes containing all the configuration for the module. Here's an example (you do not need to get the details):

Module config

<module>
    <name>com.alkacon.opencms.documentation.editortools</name>
    <nicename>OpenCms Documenation Administration</nicename>
    <group>OpenCms Documentation</group>
    <class/>
    <description>Provides tools and extra contents to be used by editors</description>
    <version>9.5.3</version>
    <authorname>Alkacon Software GmbH</authorname>
    <authoremail>sales@alkacon.com</authoremail>
    <datecreated/>
    <userinstalled/>
    <dateinstalled/>
    <dependencies>
        <dependency name="com.alkacon.opencms.documentation" version="9.5.3"/>
        <dependency name="org.opencms.jsp.search" version="0"/>
    </dependencies>
    <exportpoints>
        <exportpoint uri="/system/modules/com.alkacon.opencms.documentation.editortools/lib/" destination="WEB-INF/lib/"/>
    </exportpoints>
    <resources>
        <resource uri="/system/modules/com.alkacon.opencms.documentation.editortools/"/>
        <resource uri="/system/workplace/resources/filetypes/auto-correct-xml.png"/>
        <resource uri="/system/workplace/resources/filetypes/auto-correct-xml_big.png"/>
    </resources>
    <parameters/>
    <resourcetypes>
         <type class="org.opencms.file.types.CmsResourceTypeXmlContent" name="auto-correct-xml" id="20297">
             <param name="schema">
                 /system/modules/com.alkacon.opencms.documentation.editortools/schemas/auto-correct-xml.xsd
             </param>
         </type>
     </resourcetypes>
     <explorertypes>
         <explorertype name="auto-correct-xml" key="fileicon.auto-correct-xml" 
                       icon="auto-correct-xml.png" bigicon="auto-correct-xml_big.png" reference="xmlcontent">
             <newresource page="structurecontent" uri="newresource_xmlcontent.jsp?newresourcetype=auto-correct-xml"
                          order="10" autosetnavigation="false" autosettitle="false" info="desc.auto-correct-xml"
                          key="title.auto-correct-xml"/>
         </explorertype>
     </explorertypes>
</module>

If you export the module, the configuration is looked up and all the resources from the VFS that are in a folder specified under the <resources> node are exported, i.e., written to the RFS. The folder structure is kept and the exported resources are zipped. Additionally a manifest.xml file is created and added in the zip at the root folder. This manifest.xml records all the information on the module from the opencms-modules.xml and additionally all the meta-data from the exported resources, e.g., the properties, modification dates, etc. that are attached to files or folders.

Exporting a module means to export the online version of the module resources. So never forget to publish changes before you export a module.

Importing a module to the system means to take the module's zip file that was generated by the export and extract it into the VFS. Using the information from the manifest.xml the meta information (e.g., properties) are set at the resources and a configuration entry for the module is added to the opencms-modules.xml. Note that, when you import a module that is already present in the system, the currently installed module is first deleted and then the new version is imported. If you import an older version of a module, the newer version is also replaced. So, there is no difference in up- or downgrading.

The import procedure also checks if all specified module dependencies are met.

Exporting a module is different than deleting it. Export does not remove the module from the system, it just builds the zip file (created in {webapp home}/WEB-INF/packages/modules/). Deleting a module will remove all resources specified in the <resources> node in opencms-modules.xml and also remove the configuration of that module in that config file. Furthermore, before deleting a module, dependencies are checked. Thus, only modules where no other modules depend on can be deleted.

Be aware that deleting a module can not be undone.

When you import or export modules there are some common pitfalls that you should be aware of:

  1. Importing modules from the wrong site: Typically modules are imported and exported from the root site. In some rare cases, modules can also be im- or exported from another site, e.g., /sites/default/. Since the folder structure in the module's zip file that is build on export is relative to the site you exported the module from, modules exported from the root site should always be imported in the root site again. Also modules exported from other sites, e.g., /sites/default/ should be added in another site again. This is in particular of interest, when the module  contains resources that are not in the /system/ or /shared/ folder - otherwise the site is not that interesting because folders /system/ and /shared/ are always assumed relative to the root site.
  2. Modules with overlapping resources: If module resources are specified via folders, all resources in the folder belong to the module. Thus, if module A has specified all resources in folder a/ as module resources and then a module B is added, with resources in folder a/b/, the folder a/b/ will also belong to the resources of module a/. Thus, deleting module a/ will also delete folder a/b/ and an export of module A will also contain folder a/b/. Hence there are usually unwanted interaction between the modules when overlapping resources exist.
  3. Forgetting to publish before export: Only published versions of resources are exported when a module is exported. So, if you export a module unpublished changes will not be contained.