Serve a Dynamic Resource
Overview
This page describes how to implement business logic to serve a dynamic resource from a page component in Bloomreach Content.
When to Use
Serve a dynamic resource when you need a page component to provide content in an alternative format or expose data for client-side consumption. Typical scenarios include:
- Offering downloadable content such as PDF, CSV, images, or iCalendar files.
- Providing data (such as JSON) for AJAX requests in component templates.
This guide demonstrates how to add an iCalendar file download link to the Events feature available in the library.
Core Concepts
To serve a dynamic resource, implement the following elements:
-
In the component template, use the
hst:resourceURLtag to generate a resource URL. TheresourceIdattribute identifies the resource and is accessible in the component class.Freemarker:
<@hst.resourceURL resourceId='foo'/>JSP:
<hst:resourceURL resourceId="foo"/> -
In the component class, implement the
doBeforeServeResourcemethod. This method contains the logic to serve the resource.public void doBeforeServeResource(HstRequest request, HstResponse response) throws HstComponentException { ... } -
Create a resource template (separate from the main template) to render the resource. Configure this template using the
hst:resourcetemplateproperty on thehst:componentnode.
Implementation Example
This example extends the Events feature to allow users to download event details as an iCalendar (.ics) file. The doBeforeServeResource method generates the iCalendar file dynamically.
Prerequisites
- Create a project using the Maven archetype with default parameters.
- Build and run the project.
- Add the Events feature from the library.
- Rebuild and restart the project.
Navigate to http://localhost:8080/site/events and open an event detail page. This is where you will add the iCalendar download link.
Step 1: Add a Download Link in the Template
Locate the template used for rendering event details. Add a download link for the iCalendar file using the hst:resourceURL tag with resourceId set to "ics".
Freemarker
File: repository-data/webfiles/src/main/resources/site/freemarker/myproject/eventspage-main.ftl
<p> <a href="<@hst.resourceURL resourceId='ics'/>">Download iCalendar</a> </p>
JSP
File: site/webapp/src/main/webapp/WEB-INF/jsp/myproject/eventspage-main.jsp
<p> <hst:resourceURL var="resourceURL" resourceId="ics"/> <a href="${resourceURL}">Download iCalendar</a> </p>
Step 2: Extend EssentialsContentComponent and Implement doBeforeServeResource
Identify the configuration for the event page's main content component at /hst:myproject/hst:configurations/myproject/hst:workspace/hst:containers/eventspage/main/content. The default class is org.onehippo.cms7.essentials.components.EssentialsContentComponent.
Create a new class org.example.ICalendarEvent in your project's components module. Extend EssentialsContentComponent and override the doBeforeServeResource method.
In your implementation:
- Check if
resourceIDequals"ics". If not, set the response status to 404. - Retrieve the event content bean and verify it is not null and is an event document. If not, set the response status to 404.
- Construct a string in iCalendar format using the event's title, start date, and end date.
- Set the response content type to
text/calendar. - Store the iCalendar string in the request attribute
ics.
Example implementation:
package org.example; import java.text.DateFormat; import java.text.SimpleDateFormat; import org.example.beans.EventsDocument; import org.hippoecm.hst.content.beans.standard.HippoBean; import org.hippoecm.hst.core.component.HstComponentException; import org.hippoecm.hst.core.component.HstRequest; import org.hippoecm.hst.core.component.HstResponse; import org.onehippo.cms7.essentials.components.EssentialsContentComponent; public class ICalendarEvent extends EssentialsContentComponent { @Override public void doBeforeServeResource(HstRequest request, HstResponse response) throws HstComponentException { String resourceID = request.getResourceID(); if ("ics".equals(resourceID)) { HippoBean bean = request.getRequestContext().getContentBean(); if (bean != null && bean instanceof EventsDocument) { EventsDocument eventDocument = (EventsDocument) bean; DateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmss"); StringBuilder iCalString = new StringBuilder(); iCalString.append("BEGIN:VCALENDAR\n"); iCalString.append("BEGIN:VEVENT\n"); iCalString.append("DTSTAMP:").append(format.format(eventDocument.getDate().getTime())).append("\n"); iCalString.append("DTSTART:").append(format.format(eventDocument.getDate().getTime())).append("\n"); iCalString.append("DTEND:").append(format.format(eventDocument.getEndDate().getTime())).append("\n"); iCalString.append("SUMMARY:").append(eventDocument.getTitle()).append("\n"); iCalString.append("UID:").append(eventDocument.getIdentifier()).append("\n"); iCalString.append("END:VEVENT\n"); iCalString.append("END:VCALENDAR\n"); response.setContentType("text/calendar"); request.setAttribute("ics", iCalString.toString()); } else { response.setStatus(404); } } else { response.setStatus(404); } } }
Note: To generate iCalendar files, you can use a library such as iCal4j for more robust handling.
Step 3: Create a Resource Template
Create a template that reads the ics request attribute and outputs its content. If the ics attribute is missing, render a simple HTML error page. The response status code is already set to 404 in this case.
Freemarker
File: repository-data/webfiles/src/main/resources/site/freemarker/myproject/eventspage-main-download.ftl
<#if ics??>${ics}<#else><html><body><h1>404 Not Found</h1></body></html></#if>
JSP
File: site/webapp/src/main/webapp/WEB-INF/jsp/myproject/eventspage-main-download.jsp
<%@ include file="/WEB-INF/jsp/include/imports.jsp" %> <c:choose> <c:when test="${not empty requestScope.ics}"> <c:out value="${requestScope.ics}"/> </c:when> <c:otherwise> <html> <body> <h1>404 Not Found</h1> </body> </html> </c:otherwise> </c:choose>
Create a template configuration node at /hst:myproject/hst:configurations/myproject/hst:templates/eventspage-main-download and set the hst:renderpath property to the template location:
- Freemarker:
webfile:/freemarker/myproject/eventspage-main-download.ftl - JSP:
jsp/myproject/eventspage-main-download.jsp
Freemarker
/hst:myproject/hst:configurations/myproject/hst:templates: /eventspage-main-download: jcr:primaryType: hst:template hst:renderpath: webfile:/freemarker/myproject/eventspage-main-download.ftl
JSP
/hst:myproject/hst:configurations/myproject/hst:templates: /eventspage-main-download: jcr:primaryType: hst:template hst:renderpath: jsp/myproject/eventspage-main-download.jsp
Step 4: Configure the Component Class and Resource Template
Update the component configuration at /hst:myproject/hst:configurations/myproject/hst:workspace/hst:containers/eventspage/main/content:
- Set the
hst:componentclassnameproperty toorg.example.ICalendarEvent. - Add the
hst:resourcetemplateproperty and set it toeventspage-main-download.
/hst:myproject/hst:configurations/myproject/hst:workspace/hst:containers/eventspage/main/content: jcr:primaryType: hst:containeritemcomponent hst:componentclassname: org.example.ICalendarEvent hst:resourcetemplate: eventspage-main-download hst:template: eventspage-main
Verification
- Rebuild and restart your project.
- Open an event detail page.
- Click the "Download iCalendar" link to download the
.icsfile. - Import the file into a calendar application to verify the event details.