Customize Link Processing
Overview
This page describes how to customize internal link processing in the Bloomreach Content delivery tier.
When to Use
Customize link processing when you need to modify how internal links are generated or resolved, such as changing URL structures that do not match your repository organization or sitemap configuration.
Background
Bloomreach Content maps documents to pages using a sitemap. Internal links are created and resolved based on this mapping. The link creation and resolution process can be extended using the HstLinkProcessor interface. Implement this interface to apply custom logic before or after link processing.
HstLinkProcessor
The org.hippoecm.hst.core.linking.HstLinkProcessor interface provides two extension points:
HstLink postProcess(HstLink link)
Invoked after a link is created byorg.hippoecm.hst.core.linking.HstLinkCreator.HstLink preProcess(HstLink link)
Invoked before a link is matched byorg.hippoecm.hst.core.request.HstSiteMapMatcher.
The delivery tier uses a chain of link processors. You can add multiple custom processors to this chain using Spring configuration.
Important:
Implementations of HstLinkProcessor must be thread-safe. Do not store state in member variables.
Example
Scenario
Suppose you have a project created from the Bloomreach Content Maven archetype with the Simple Content feature added.
Documents of type myproject:contentdocument are stored in /content/documents/myproject/content.
The following sitemap configuration maps these documents to URLs and page templates:
/hst:myproject/hst:configurations/myproject/hst:sitemap: /content: jcr:primaryType: hst:sitemapitem hst:componentconfigurationid: hst:pages/contentlist hst:relativecontentpath: content /_any_.html: jcr:primaryType: hst:sitemapitem hst:componentconfigurationid: hst:pages/contentpage hst:relativecontentpath: ${parent}/${1}
A document at /content/documents/myproject/content/sample-document is available at http://localhost:8080/site/content/sample-document.html.
Now, if you organize documents in subfolders based on the first character of the document name, your repository structure might look like:
/content/documents/myproject: /content: jcr:primaryType: hippostd:folder /a: jcr:primaryType: hippostd:folder /about-hippo: jcr:primaryType: hippo:handle /archetype: jcr:primaryType: hippo:handle /b: jcr:primaryType: hippostd:folder /best-practices: jcr:primaryType: hippo:handle /big-hippo: jcr:primaryType: hippo:handle /c: jcr:primaryType: hippostd:folder /code-formatting: jcr:primaryType: hippo:handle /create-project: jcr:primaryType: hippo:handle
This structure results in URLs such as http://localhost:8080/site/content/a/about-bloomreach.html and http://localhost:8080/site/content/b/best-practices.html.
If your requirement is to remove the subfolder from the URL (for example, http://localhost:8080/site/content/about-bloomreach.html), you need to customize link processing.
Approach
Implement a custom HstLinkProcessor to:
- Remove the subfolder element from generated links that start with
content/, socontent/a/about-bloomreachbecomescontent/about-bloomreach. - Add the subfolder element when matching incoming URLs, so
content/about-bloomreachbecomescontent/a/about-bloomreachbefore resolving the document.
Implementation Steps
1. Implement HstLinkProcessor
Create a custom processor by extending HstLinkProcessorTemplate:
site/components/src/main/java/org/example/ExampleHstLinkProcessor.java
package org.example; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.hippoecm.hst.core.linking.HstLink; import org.hippoecm.hst.linking.HstLinkProcessorTemplate; public class ExampleHstLinkProcessor extends HstLinkProcessorTemplate { @Override protected HstLink doPostProcess(HstLink link) { String path = link.getPath(); if (path.startsWith("content/")) { String pattern = "(content/)./(.+)"; Pattern r = Pattern.compile(pattern); Matcher m = r.matcher(path); if (m.find()) { path = m.replaceAll("$1$2"); link.setPath(path); } } return link; } @Override protected HstLink doPreProcess(HstLink link) { String path = link.getPath(); if (path.startsWith("content/")) { String pattern = "(content)(/.)(.?)"; Pattern r = Pattern.compile(pattern); Matcher m = r.matcher(path); if (m.find()) { path = m.replaceAll("$1$2$2$3"); link.setPath(path); } } return link; } }
doPostProcessremoves the subfolder from the generated link path.doPreProcessadds the subfolder back based on the first character of the document name.
2. Register the Processor in Spring
Configure the processor in your Spring context:
site/components/src/main/resources/META-INF/hst-assembly/overrides/customLinkProcessors.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd"> <bean id="org.hippoecm.hst.core.linking.HstLinkProcessor" class="org.hippoecm.hst.core.linking.HstLinkProcessorChain"> <property name="processorsInChain"> <list> <bean class="org.example.ExampleHstLinkProcessor" /> </list> </property> </bean> </beans>
Verification
- Generate a link to a content document. The resulting URL should not include the subfolder (e.g.,
/content/about-bloomreach.html). - Access a URL without the subfolder. The processor should resolve it to the correct document in the repository.