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:resourceURL tag to generate a resource URL. The resourceId attribute 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 doBeforeServeResource method. 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:resourcetemplate property on the hst:component node.

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

Navigate to http://localhost:8080/site/events and open an event detail page. This is where you will add the iCalendar download link.

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 resourceID equals "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:componentclassname property to org.example.ICalendarEvent.
  • Add the hst:resourcetemplate property and set it to eventspage-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 .ics file.
  • Import the file into a calendar application to verify the event details.
Share Feedback
Page: /build/component-development/serve-a-dynamic-resource
Section: Build
Category *