Plugin Installation
Introduction
Essentials plugins of type feature require installation. During installation, the feature represented by the Essentials plugin is installed into your project, resulting in some change to your project sources. These changes can be a result of direct interaction between Essentials and your project (i.e. a Java class, configuration file or resource is copied to your project or modified), or changes find their way into the project when Essentials imports nodes and properties into a running repository, and the auto-export mechanism exports them as YAML files into your project sources.
For most changes to your project sources, a rebuild (packaging the changed resources into new WARs) and restart (deploying the new WARs locally) is required. If an Essentials plugin does not require a restart, it can tell the Essentials web application so through its Plugin Descriptor. The plugin installation logic of the Essentials web application keeps track of the plugin's installation state by means of a plugin file stored in the essentials module's resources, per plugin. You can find them at essentials/src/main/resources/<pluginId>.xml, by default.
Inter-Plugin Dependencies
Your Essentials plugin can declare a dependency on one or more other Essentials plugins (which themselves can also depend on other plugins). A plugin can depend on another plugin, because its installation may require the presence of certain project sources or repository nodes or node types. Essentials' plugin installation mechanism then makes sure that the depended-on plugins get installed first.
In its simplest form, an inter-plugin dependency only declares the plugin ID of the plugin(s) it depends on, in the Plugin Descriptor, for example
{ "id": "pluginA", [...] "pluginDependencies": [ { "pluginId": "pluginB" } ] }
Above dependency means that "pluginA" can only be installed once "pluginB" has been installed. If "pluginB" requires a rebuild and restart after the execution of the installation instructions (see below), above plugin dependency implicitly expresses that "pluginA" can be installed before the rebuild and restart. If your "pluginA" requires a rebuild and restart after the installation of "pluginB", for example because "pluginB" adds a dependency which, upon bootstrapping, creates a new JCR namespace "pluginA" depends on, you need a slightly more advanced form of the plugin dependency:
{ "id": "pluginA", [...] "pluginDependencies": [ { "pluginId": "pluginB", "minInstallStateForInstalling": "installed" } ] }
Adding the minInstallStateForInstalling expresses that, for "pluginA" to be installed, the installation of "pluginB" must have reached the installation state installed, which is only reached after the final rebuild and restart required by "pluginB". The installation state before the rebuild and restart (which is the default value of the minInstallStateForInstalling field) is installing.
Installation Instructions
During the installation of a plugin, the Essentials web application attempts to execute sets of installation instructions. The plugin tells the Essentials web application which instructions to execute by means of the packageFile, referred to by the Plugin Descriptor. A package file adheres to the XML schema defined in the Plugin SDK API, and groups multiple instructions into multiple instruction sets. Each instruction set can define a comma-separated list of group names (by means of the group attribute), which controls whether or not the instructions in that set get executed during the installation.
Installation Parameters
Installation parameters control which instruction sets of a plugin are executed during the installation of a plugin. The Essentials web application has 4 built-in installation parameters, more (custom) installation parameters can be used by more sophisticated Essentials plugins. The built-in installation parameters are bound to these global flags of the Essentials web application, found in the Essentials project settings and stored in essentials/src/main/resources/project-settings.xml:
- freemarker: is typically used to indicate that Freemarker templates are used throughout the project.
- jsp: is typically used to indicate that JSP templates are used throughout the project.
- extraTemplates: indicates that extra HST component template variants should be installed. This is only supported in combination with Freemarker templates.
- sampleData: indicates that sample data should be installed into the project.
You can use any of these flags as values of the group attribute of your package file's instruction set tags. If you specify multiple flags (comma-separated), the instructions in that set are executed if at least one of the specified flags is true during installation. If you specify no flag (i.e. leave out the group attribute), the instructions of this set are installed unconditionally.
Built-in Instructions
Essentials provides a few instructions out-ot-the-box. Here's a short description of their intent, more detail can be extracted from the Plugin SDK API's XML schema definition.
Element Name | Description |
---|---|
file | Copy a file from a source location (classloader resource path) to a target location (project sources), or delete a file at a target location. Placeholder-substitution is applied to text-based (non-binary) files. |
freemarker |
Identical to <file> |
directory | Create a directory at a target location (project sources), or copy an entire directory from a source location (classloader resource path) to a target location. |
xml | Import nodes and properties from a source location (node:sv XML classloader resource path) to a target location (JCR path), or delete a node at a target location. |
cnd | Register a JCR content type, given an existing namespace and optionally a list of existing supertypes. |
translation | Import a set of translations (JSON formatted localized labels) from a source location (classloader resource path) into the JCR repository. |
mavenDependency | Register a Maven dependency with the specified Maven module. |
hstBeanClasses | Register a scanning pattern for the site module to detect HST beans. |
execute | Execute a custom Instruction, typically defined in the scope of the plugin. |
Essentials implements a wide range of placeholders, which it substitutes in imported resources (text-based files or node:sv XML files) as well as target locations. The full set of supported placeholders is defined in the Plugin SDK API's PlaceholderService interface. To make use of these placeholders, embed them with double curly braces in your instructions.xml file or your resources. You can find such a placeholder in the example package file below.
Custom Instructions
Your Essentials plugin might require installation actions that are not catered for by the built-in instructions described above. In that case, your Essentials plugin can implement one or more custom instructions. To do so, create a Java class which implements the sdk.api.install.Instruction SPI. Inside that instruction, you implement the custom logic in the #execute method, making use of the services provided by the Plugin SDK API, and you implement the #populateChangeMessages method in order to provide a preview of your custom instruction's effect(s) to the Dashboard user. In order to trigger the execution of your custom instruction during the installation of the plugin, add an <execute> instruction to the appropriate instruction set in your plugin's package file, and refer to your custom instruction class.
Example Package File
To illustrate how a package file might look, here's an example:
<?xml version="1.0" encoding="UTF-8"?> <instructions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.onehippo.org/essentials/instructions /instructions.xsd" xmlns="http://www.onehippo.org/essentials/instructions"> <instructionSet> <hstBeanClasses pattern="classpath*:org/onehippo/forge/**/*.class" /> <mavenDependency targetPom="cms" groupId="org.example" artifactId="some-dependency"/> <execute class="org.example.essentials.plugin.CustomInstruction" /> <file action="copy" source="java/HstBean.txt" target="{{beansFolder}}/HstBean.java"/> </instructionSet> <instructionSet group="sampleData"> <xml action="copy" source="instructions/xml/sample-data.xml" target="/content/documents"/> </instructionSet> </instructions>