HST Addon Module Support
Overview
An HST Addon Module is a child Spring component bean manager that can be packaged, deployed, and loaded from a separate classpath resource, such as a JAR file. Each addon module has its own component bean manager with a unique namespace, which manages component beans intended for sharing across applications.
For example, you can bundle shared component beans into a JAR file and deploy this JAR to your HST site application. HST components can then access these shared beans using the HST ComponentManager API.
Suppose you have implemented a matrix operation API component (bean name: matrixOperator) in the JAR file linear-algebra-1.01.00.jar, and the namespace for your addon module is org.example.myproject.addonmodules.linearalgebra. You can retrieve the MatrixOperator bean instance as follows:
org.hippoecm.hst.core.container.ComponentManager#getComponent("matrixOperator", "org.example.myproject.addonmodules.linearalgebra")
The first argument, matrixOperator, is the bean name in the internal Spring ApplicationContext. The second argument is the context namespace for the bean.
The HST ComponentManager loads all defined addon module packages from classpath resources and initializes module instances for each namespace. This allows HST components to access shared beans from addon modules in your site application.
Each addon module instance contains its own Spring ApplicationContext to manage its beans. When you call org.hippoecm.hst.core.container.ComponentManager#getComponent(...), the HST ComponentManager locates the correct module instance by namespace and retrieves the bean by name from that module.
Defining an HST Addon Module
To create and use an HST Addon Module:
- Create a JAR module project and define the module descriptor at
classpath:META-INF/hst-assembly/addon/module.xml. - Add one or more Spring bean definition XML files.
- Add the packaged JAR as a dependency in your site application.
In your JAR module project, define the addon module descriptor as shown below:
<?xml version="1.0" encoding="UTF-8"?> <module xmlns="http://www.onehippo.org/schema/hst/hst-addon-module_1_0.xsd"> <name>org.example.myproject.addonmodules.linearalgebra</name> <config-locations> <config-location> classpath*:META-INF/hst-assembly/addon/org/example/myproject/addonmodules/linearalgebra/*.xml </config-location> </config-locations> </module>
The root element is module with the specified namespace. The name element defines the namespace for all beans shared by this addon module. The config-locations element contains one or more config-location entries, each specifying a Spring XML file pattern for loading beans. The XSD file for validation is available in hst-core-x.y.z.jar at META-INF/schema/hst-addon-module_1_0.xsd.
In the example above, the module named org.example.myproject.addonmodules.linearalgebra loads all beans from XML files matching:
classpath*:META-INF/hst-assembly/addon/org/example/myproject/addonmodules/linearalgebra/*.xml
If your JAR file is linear-algebra-1.01.00.jar and includes an XML file at META-INF/hst-assembly/addon/org/example/myproject/addonmodules/linearalgebra/base.xml, all beans defined in this file are loaded automatically by the addon module when the HST Container starts.
For example, the following bean definition enables access to the bean as shown earlier:
<bean id="matrixOperator" class="org.example.myproject.addonmodules.linearalgebra.MatrixOperatorImpl"> </bean>
Add the module JAR as a dependency in your site application’s Maven project:
<dependency> <groupId>org.example.myproject.addonmodules</groupId> <artifactId>linear-algebra</artifactId> <version>1.01.00</version> </dependency>
If the addon module JAR includes a valid module descriptor (classpath:META-INF/hst-assembly/addon/module.xml), the HST Container loads the addon module automatically at startup.
HST Modules with Descendant Modules
A module descriptor can define child modules within a parent module. For example, the following configuration defines a parent module (org.example.analytics) with two child modules (reports and statistics):
<module xmlns="http://www.onehippo.org/schema/hst/hst-addon-module_1_0.xsd"> <name>org.example.analytics</name> <config-locations> <config-location>classpath*:META-INF/hst-assembly/addon/org/example/analytics/*.xml</config-location> </config-locations> <modules> <module> <name>reports</name> <config-locations> <config-location>classpath*:META-INF/hst-assembly/addon/org/example/analytics/reports/*.xml</config-location> </config-locations> </module> <module> <name>statistics</name> <config-locations> <config-location>classpath*:META-INF/hst-assembly/addon/org/example/analytics/statistics/*.xml</config-location> </config-locations> </module> </modules> </module>
This configuration creates a module instance named org.example.analytics with its own Spring ApplicationContext. It also creates two child module instances, each with a separate child ApplicationContext.
To access a bean defined in a child module, use the ComponentManager and specify the appropriate module context names. For example, if you have a bean named analyticsStatisticsGreeting in the statistics child module, retrieve it as follows:
componentManager.getComponent("analyticsStatisticsGreeting", "org.example.analytics", "statistics");
Bean Visibility in Module Hierarchies
The Spring ApplicationContext of the default HST ComponentManager is the top ancestor for all module instances.
If an addon module contains descendant modules (such as child modules or deeper descendants), beans defined in descendant modules can reference beans from ancestor modules or from the HST ComponentManager.
However, beans defined in ancestor modules cannot reference beans from their descendants.
Similarly, beans defined in the HST Container (for example, in META-INF/hst-assembly/overrides/*.xml) cannot reference beans defined in any addon module.
Configuring an Explicit Parent Module
If the Spring beans in an addon module depend on beans from another HST Addon Module, you must explicitly specify the parent module. By default, beans from other addon modules are not accessible, except for beans in the default HST ComponentManager (the top ancestor ApplicationContext).
Descendant modules defined within the same <module> configuration can access beans from their parent module. For cases where a downstream Maven project needs access to beans from an upstream project, set the parent module explicitly in the module descriptor:
<?xml version="1.0" encoding="UTF-8"?> <module xmlns="http://www.onehippo.org/schema/hst/hst-addon-module_1_0.xsd"> <name>org.example.myproject.addonmodules.linearalgebra</name> <parent>org.example.addonmodules</parent> <config-locations> <config-location> classpath*:META-INF/hst-assembly/addon/org/example/myproject/addonmodules/linearalgebra/*.xml </config-location> </config-locations> </module>
With this configuration, all Spring beans from the parent module org.example.addonmodules are accessible in the linearalgebra addon. Beans from the default HST ComponentManager remain available as well.
Example: Addon Modules in TestSuite
The TestSuite repository contains examples of HST Addon Modules.
The "linear-algebra" module is a JAR sub-project that includes a module descriptor, a Spring bean assembly XML file, and component beans.
The bean defined in the Spring XML file implements the shared interface MatrixOperator. An HST Component accesses this shared interface as follows:
public class Algebra extends BaseHstComponent { public static final String RANDOM_NUMBERS_MODULE_NAME = "org.hippoecm.hst.demo.addonmodules.randomnumbers"; public static final String LINEAR_ALGEBRA_MODULE_NAME = "org.hippoecm.hst.demo.addonmodules.linearalgebra"; @Override public void doBeforeRender(final HstRequest request, final HstResponse response) throws HstComponentException { RandomGenerator randomGenerator = HstServices.getComponentManager().getComponent("randomGenerator", RANDOM_NUMBERS_MODULE_NAME); MatrixOperator matrixOperator = HstServices.getComponentManager().getComponent("matrixOperator", LINEAR_ALGEBRA_MODULE_NAME); double [][] matrixData = new double[2][2]; for (int i = 0; i < 2; i++) { double [] randomNums = randomGenerator.generate(2); for (int j = 0; j < 2; j++) { matrixData[i][j] = randomNums[j]; } } double [][] inverseMatrixData = matrixOperator.inverse(matrixData); request.setAttribute("matrix", ArrayUtils.toString(matrixData)); request.setAttribute("inverse", ArrayUtils.toString(inverseMatrixData)); double [][] multiplied = matrixOperator.multiply(matrixData, inverseMatrixData); request.setAttribute("multiplied", ArrayUtils.toString(multiplied)); } }
In this example, the bean implementing MatrixOperator is accessed using ComponentManager#getComponent(String, String ... contextNames). The Algebra HST Component generates matrix data and performs basic matrix operations using the component bean.
This example demonstrates how to use HST Addon Modules to share and access Spring beans in your HST site applications.
References
- [1] https://github.com/bloomreach/brxm/tree/brxm-14.7.3/testsuite
- [2] https://github.com/bloomreach/brxm/tree/brxm-14.7.3/testsuite/linear-algebra
- [3] https://github.com/bloomreach/brxm/blob/brxm-14.7.3/testsuite/linear-algebra/src/main/resources/META-INF/hst-assembly/addon/module.xml
- [4] https://github.com/bloomreach/brxm/blob/brxm-14.7.3/testsuite/linear-algebra/src/main/resources/META-INF/hst-assembly/addon/org/hippoecm/hst/demo/addonmodules/linearalgebra/base.xml
- [5] https://github.com/bloomreach/brxm/blob/brxm-14.7.3/testsuite/linear-algebra/src/main/java/org/hippoecm/hst/demo/addonmodules/linearalgebra/MatrixOperatorImpl.java
- [6] https://github.com/bloomreach/brxm/blob/brxm-14.7.3/testsuite/api/src/main/java/org/hippoecm/hst/demo/addonmodules/api/MatrixOperator.java
- [7] https://github.com/bloomreach/brxm/blob/brxm-14.7.3/testsuite/components/src/main/java/org/hippoecm/hst/demo/components/Algebra.java