Extend CommonComponent with DoBeforeRenderExtension
Introduction
Goal
Plug additional code into CommonComponent so that all components extending CommonComponent execute this code before they are rendered.
Background
All standard components provided by Hippo's setup application are descendants of the abstract class org.onehippo.cms7.essentials.components.CommonComponent. This CommonComponent class provides an extension point where additional code can be plugged into its doBeforeRender method. Consequently all standard components (and any custom component extending CommonComponent) will execute this additional code before it is rendered.
The extension point is provided as the interface org.onehippo.cms7.essentials.components.ext.DoBeforeRenderExtension. By default a no-op implementation (org.onehippo.cms7.essentials.components.ext.NoopDoBeforeRenderExtension) is configured.
Example
Use Case
The use case demonstrated by the example on this page is based on a Hippo project created from the Maven Archetype with the Blog feature added.
The Blog feature includes a "blog categories" key-value list. Such a key-value list is managed as a document in the CMS and can be accessed from within the delivery tier through a ValueListManager configured as Spring bean. The setup application provides a UI to create such configuration. The generated configuration can be found in your project's site module at:
site/src/main/resources/META-INF/hst-assembly/overrides/valueListManager.xml
<bean id="org.onehippo.forge.selection.hst.manager.ValueListManager" class="org.onehippo.forge.selection.hst.manager.DefaultValueListManager"> <constructor-arg> <map> <!--<entry key="name" value="/absolute/repository/path"/>--> <entry key="categories" value="/content/documents/myhippoproject/blog/blog-categories"/> </map> </constructor-arg> </bean>
You want the categories key-value list to be readily available as request attribute to any rendering template. One way to achieve this is through a DoBeforeRenderExtension: a custom piece of code that is executed by every component before it is rendered.
What about performance?
Since a DoBeforeRenderExtension is executed by every component extending CommonComponent there is a potential for performance degradation. In this use case the key-value list is actually already being cached in memory. In other use cases it may be beneficial to cache retrieved data locally in the HstRequestContext object.
Implement DoBeforeRenderExtension Interface
Create a new class org.example.extensions.CategoriesDoBeforeRenderExtension which implements DoBeforeRenderExtension.
Implement the execute method so that it retrieves the ValueListManager bean, gets the categories value list and stores it in a request attribute categories.
site/src/main/java/org/example/extensions/CategoriesDoBeforeRenderExtension.java
package org.example.extensions; import org.hippoecm.hst.content.beans.standard.HippoBean; import org.hippoecm.hst.core.component.HstRequest; import org.hippoecm.hst.core.component.HstResponse; import org.hippoecm.hst.site.HstServices; import org.onehippo.cms7.essentials.components.CommonComponent; import org.onehippo.cms7.essentials.components.ext.DoBeforeRenderExtension; import org.onehippo.forge.selection.hst.contentbean.ValueList; import org.onehippo.forge.selection.hst.manager.ValueListManager; import org.onehippo.forge.selection.hst.util.SelectionUtil; public class CategoriesDoBeforeRenderExtension implements DoBeforeRenderExtension { @Override public void execute(final CommonComponent component, final HstRequest request, final HstResponse response) { ValueListManager valueListManager = HstServices.getComponentManager().getComponent(ValueListManager.class.getName()); HippoBean siteContentBaseBean = request.getRequestContext().getSiteContentBaseBean(); ValueList categoriesValueList = valueListManager.getValueList(siteContentBaseBean, "categories"); if (categoriesValueList != null) { request.setAttribute("categories", SelectionUtil.valueListAsMap(categoriesValueList)); } } }
Configure DoBeforeRenderExtension Spring Bean
In the Spring configuration replace the default configured NoopDoBeforeRenderExtension by org.example.extensions.CategoriesDoBeforeRenderExtension .
site/src/main/resources/META-INF/hst-assembly/overrides/hippo-essentials-spring.xml
<bean id="org.onehippo.cms7.essentials.components.ext.DoBeforeRenderExtension" class="org.example.extensions.CategoriesDoBeforeRenderExtension"/>
Use the Key-Value List in a Template
Now any component that uses a component class extending CommonComponent has a request attribute categories (containing the key-value list as java.util.Map) available to its rendering template.
For example to render a blog post's categories on the blog overview page you could add the following to the blog-list-.ftl template:
bootstrap/webfiles/src/main/resources/site/freemarker/hstdefault/blog/blog-list.ftl
<ul> <#list item.categories as category> <li>${categories[category]}</li> </#list> </ul>