Dispatcher versions are independent of AEM. You may have been redirected to this page if you followed a link to the Dispatcher documentation that is embedded in AEM or CQ documentation.
Use Dispatcher to process page requests in multiple web domains while supporting the following conditions:
For example, a company publishes websites for two of their brands: Brand A and Brand B. The content for the website pages are authored in AEM, and stored in the same repository workspace:
/
| - content
| - sitea
| - content nodes
| - siteb
| - content nodes
Pages for BrandA.com
are stored below /content/sitea
. Client requests for the URL https://BrandA.com/en.html
are returned the rendered page for the /content/sitea/en
node. Similarly, pages for BrandB.com
are stored below /content/siteb
.
When using Dispatcher to cache content, associations must be made between the page URL in the client HTTP request, the path of the corresponding file in the cache, and the path of the corresponding file in the repository.
When clients send HTTP requests to the web server, the URL of the requested page must be resolved to the content in the Dispatcher cache, and eventually to the content in the repository.
When Dispatcher Flush replication agents request that Dispatcher invalidates cached files, the path of the content in the repository must resolve to the content in the cache.
To use Dispatcher with multiple domains, you need to configure AEM, Dispatcher, and your web server. The solutions described on this page are general and apply to most environments. Due to the complexity of some AEM topologies, your solution can require further custom configurations to resolve particular issues. You will likely need to adapt the examples to satisfy your existing IT infrastructure and management policies.
To enable domain URLs and content paths to resolve to cached files, at some point in the process a file path or page URL must be translated. Descriptions of the following common strategies are provided, where path or URL translations occur at different points in the process:
It is generally desirable to use short URLs for web pages. Typically, page URLs mirror the structure of the repository folders that contain the web content. However, the URLs do not reveal the topmost repository nodes, such as /content
. The client is not necessarily aware of the structure of the AEM repository.
Your environment must implement the following configurations to support Dispatcher working with multiple domains:
The example solutions that are provided apply to an environment with the following characteristics:
The AEM author and publish instances are deployed on Linux systems.
Apache HTTPD is the web server, deployed on a Linux system.
The AEM content repository and the document root of the web server use the following file structures (the document root of the Apache web server is /usr/lib/apache/httpd-2.4.3/htdocs)
:
Repository
| - /content
| - sitea
| | - content nodes
| - siteb
| - content nodes
Document root of the web server
| - /usr
| - lib
| - apache
| - httpd-2.4.3
| - htdocs
| - content
| - sitea
| - content nodes
| - siteb
| - content nodes
Sling mapping for resource resolution enables you to associate incoming URLs with AEM content paths. Create mappings on the AEM publish instance so that render requests from Dispatcher resolve to the correct content in the repository.
Dispatcher requests for page rendering identify the page using the URL that it is passed from the web server. When the URL includes a domain name, Sling mappings resolve the URL to the content. The following graphic illustrates a mapping of the branda.com/en.html
URL to the /content/sitea/en
node.
The Dispatcher cache mirrors the repository node structure. Therefore, when page activations occur the resulting requests for invalditing the cached page require no URL or path translations.
Define virtual hosts on the web server so that a different document root can be assigned to each web domain:
The following example httpd.conf
file configures two virtual domains for an Apache web server:
With this configuration, the web server performs the following actions when it recieves a request for https://branda.com/en/products.html
:
Associates the URL with the virtual host that has a ServerName
of branda.com.
Forwards the URL to Dispatcher.
# load the Dispatcher module
LoadModule dispatcher_module modules/mod_dispatcher.so
# configure the Dispatcher module
<IfModule disp_apache2.c>
DispatcherConfig conf/dispatcher.any
DispatcherLog logs/dispatcher.log
DispatcherLogLevel 3
DispatcherNoServerHeader 0
DispatcherDeclineRoot 0
DispatcherUseProcessedURL 0
DispatcherPassError 0
</IfModule>
# Define virtual host for brandA.com
<VirtualHost *:80>
ServerName branda.com
DocumentRoot /usr/lib/apache/httpd-2.4.3/htdocs/content/sitea
<Directory /usr/lib/apache/httpd-2.4.3/htdocs/content/sitea>
<IfModule disp_apache2.c>
SetHandler dispatcher-handler
ModMimeUsePathInfo On
</IfModule>
Options FollowSymLinks
AllowOverride None
</Directory>
</VirtualHost>
# define virtual host for brandB.com
<VirtualHost *:80>
ServerName brandB.com
DocumentRoot /usr/lib/apache/httpd-2.4.3/htdocs/content/siteb
<Directory /usr/lib/apache/httpd-2.4.3/htdocs/content/siteb>
<IfModule disp_apache2.c>
SetHandler dispatcher-handler
ModMimeUsePathInfo On
</IfModule>
Options FollowSymLinks
AllowOverride None
</Directory>
</VirtualHost>
# document root for web server
DocumentRoot "/usr/lib/apache/httpd-2.4.3/htdocs"
Note that virtual hosts inherit the DispatcherConfig property value that is configured in the main server section. Virtual hosts can include their own DispatcherConfig property to override the main server configuration.
To support URLs that include domain names and their corresponding virtual hosts, define the following Dispatcher farms:
Farms for virtual hosts must have the following configurations so that the URLs in client HTTP requests are resolved to the correct files in the Dispatcher cache:
The /virtualhosts
property is set to the domain name. This property enables Dispatcher to associate the farm with the domain.
The /filter
property allows access to the path of the request URL truncated after the domain name part. For example, for the https://branda.com/en.html
URL, the path is interpreted as /en.html
, so the filter must allow access to this path.
The /docroot
property is set to the path of the root directory of the domain’s site content in the Dispatcher cache. This path is used as the prefix for the concatenated URL from the original request. For example, the docroot of /usr/lib/apache/httpd-2.4.3/htdocs/sitea
causes the request for https://branda.com/en.html
to resolve to the /usr/lib/apache/httpd-2.4.3/htdocs/sitea/en.html
file.
Additionally, the AEM publish instance must be designated as the render for the virtual host. Configure other farm properties as required. The following code is an abbreviated farm configuration for the branda.com domain:
/farm_sitea {
...
/virtualhosts { "branda.com" }
/renders {
/rend01 { /hostname "127.0.0.1" /port "4503" }
}
/filter {
/0001 { /type "deny" /glob "*" }
/0023 { /type "allow" /glob "*/en*" }
...
}
/cache {
/docroot "/usr/lib/apache/httpd-2.4.3/htdocs/content/sitea"
...
}
...
}
A Dispatcher farm is required for handling requests for invalidating cached files. This farm must be able to access .stat files in the docroot directories of each virtual host.
The following property configurations enable Dispatcher to resolve files in the AEM content repository from files in the cache:
/docroot
property is set to the default docroot of the web server. Typically, this is the directory where the /content
folder is created. An example value for Apache on Linux is /usr/lib/apache/httpd-2.4.3/htdocs
./filter
property allows access to files below the /content
directory.The /statfileslevel
property must be high enough so that .stat files are created in the root directory of each virtual host. This property enables the cache of each domain to be invalidated separately. For the example setup, a /statfileslevel
value of 2
creates .stat files in the *docroot*/content/sitea
directory and the *docroot*/content/siteb
directory.
Additionally, the publish instance must be designated as the render for the virtual host. Configure other farm properties as required. The following code is an abbreviated configuration for the farm that is used for invalidating the cache:
/farm_flush {
...
/virtualhosts { "invalidation_only" }
/renders {
/rend01 { /hostname "127.0.0.1" /port "4503" }
}
/filter {
/0001 { /type "deny" /glob "*" }
/0023 { /type "allow" /glob "*/content*" }
...
}
/cache {
/docroot "/usr/lib/apache/httpd-2.4.3/htdocs"
/statfileslevel "2"
...
}
...
}
When you start the web server, the Dispatcher log (in debug mode) indicates the initialization of all farms:
Dispatcher initializing (build 4.1.2)
[Fri Nov 02 16:27:18 2012] [D] [24974(140006182991616)] farms[farm_sitea].cache.docroot = /usr/lib/apache/httpd-2.4.3/htdocs/content/sitea
[Fri Nov 02 16:27:18 2012] [D] [24974(140006182991616)] farms[farm_siteb].cache.docroot = /usr/lib/apache/httpd-2.4.3/htdocs/content/siteb
[Fri Nov 02 16:27:18 2012] [D] [24974(140006182991616)] farms[farm_flush].cache.docroot = /usr/lib/apache/httpd-2.4.3/htdocs
[Fri Nov 02 16:27:18 2012] [I] [24974(140006182991616)] Dispatcher initialized (build 4.1.2)
Use Sling mapping for resource resolution so that domain-based URLs resolve to content on the AEM publish instance. The resource mapping translates the incoming URLs from Dispatcher (originally from client HTTP requests) to content nodes.
To learn about Sling resource mapping, see Mappings for Resource Resolution in the Sling documentation.
Typically, mappings are required for the following resources, although additional mappings can be necessary:
/content
)/etc/designs
)/libs
folderAfter you create the mapping for the content page, to discover additional required mappings use a web browser to open a page on the web server. In the error.log file of the publish instance, locate messages about resources that are not found. The following example message indicates that a mapping for /etc/clientlibs
is required:
01.11.2012 15:59:24.601 *INFO* [10.36.34.243 [1351799964599] GET /etc/clientlibs/foundation/jquery.js HTTP/1.1] org.apache.sling.engine.impl.SlingRequestProcessorImpl service: Resource /content/sitea/etc/clientlibs/foundation/jquery.js not found
The linkchecker transformer of the default Apache Sling rewriter automatically modifies hyperlinks in the page to prevent broken links. However, link rewriting is performed only when the link target is an HTML or HTM file. To update links to other file types, create a transformer component and add it to an HTML rewriter pipeline.
The following table lists the nodes that implement resource mapping for the branda.com domain. Similar nodes are created for the brandb.com
domain, such as /etc/map/http/brandb.com
. In all cases, mappings are required when references in the page HTML to not resolve correctly in the context of Sling.
Node path | Type | Property |
---|---|---|
/etc/map/http/branda.com |
sling:Mapping | Name: sling:internalRedirect Type: String Value: /content/sitea |
/etc/map/http/branda.com/libs |
sling:Mapping | Name: sling:internalRedirect Type: String Value: /libs |
/etc/map/http/branda.com/etc |
sling:Mapping | |
/etc/map/http/branda.com/etc/designs |
sling:Mapping | Name: sling:internalRedirect VType: String VValue: /etc/designs |
/etc/map/http/branda.com/etc/clientlibs |
sling:Mapping | Name: sling:internalRedirect VType: String VValue: /etc/clientlibs |
The Dispatcher Flush replication agent on the AEM publish instance must send invalidation requests to the correct Dispatcher farm. To target a farm, use the URI property of the Dispatcher Flush replication agent (on the Transport tab). Include the value of the /virtualhost
property for the Dispatcher farm that is configured for invalidating the cache:
https://*webserver_name*:*port*/*virtual_host*/dispatcher/invalidate.cache
For example, to use the farm_flush
farm of the previous example, the URI is https://localhost:80/invalidation_only/dispatcher/invalidate.cache
.
Use the internal URL rewriting feature of your web server to translate domain-based URLs to file paths in the Dispatcher cache. For example, client requests for the https://brandA.com/en.html
page are translated to the content/sitea/en.html
file in the document root of the web server.
The Dispatcher cache mirrors the repository node structure. Therefore, when page activations occur the resulting requests for invalidating the cached page require no URL or path translations.
Configure the following aspects on the web server:
DispatcherUseProcessedURL
property in Installing Dispatcher.)The following example httpd.conf file configures two virtual hosts for an Apache web server:
The server names (which coincide with the domain names) are brandA.com
(line 16) and brandB.com
(line 32).
The document root of each virtual domain is the directory in the Dispatcher cache that contains the site’s pages. (lines 20 and 33)
The URL rewrite rule for each virtual domain is a regular expression that prefixes the path of the requested page with the path to the pages in the cache. (lines 19 and 35)
The DispatherUseProcessedURL
property is set to 1
. (line 10)
For example, the web server performs the following actions when it receives a request with the https://brandA.com/en/products.html
URL:
ServerName
of brandA.com.
/content/sitea/en/products.html.
# load the Dispatcher module
LoadModule dispatcher_module modules/mod_dispatcher.so
# configure the Dispatcher module
<IfModule disp_apache2.c>
DispatcherConfig conf/dispatcher.any
DispatcherLog logs/dispatcher.log
DispatcherLogLevel 3
DispatcherNoServerHeader 0
DispatcherDeclineRoot 0
DispatcherUseProcessedURL 1
DispatcherPassError 0
</IfModule>
# Define virtual host for brandA.com
<VirtualHost *:80>
ServerName branda.com
DocumentRoot /usr/lib/apache/httpd-2.4.3/htdocs/content/sitea
RewriteEngine on
RewriteRule ^/(.*)\.html$ /content/sitea/$1.html [PT]
<Directory /usr/lib/apache/httpd-2.4.3/htdocs/content/sitea>
<IfModule disp_apache2.c>
SetHandler dispatcher-handler
ModMimeUsePathInfo On
</IfModule>
Options FollowSymLinks
AllowOverride None
</Directory>
</VirtualHost>
# define virtual host for brandB.com
<VirtualHost *:80>
ServerName brandB.com
DocumentRoot /usr/lib/apache/httpd-2.4.3/htdocs/content/siteb
RewriteEngine on
RewriteRule ^/(.*)\.html$ /content/siteb/$1.html [PT]
<Directory /usr/lib/apache/httpd-2.4.3/htdocs/content/siteb>
<IfModule disp_apache2.c>
SetHandler dispatcher-handler
ModMimeUsePathInfo On
</IfModule>
Options FollowSymLinks
AllowOverride None
</Directory>
</VirtualHost>
# document root for web server
DocumentRoot "/usr/lib/apache/httpd-2.4.3/htdocs"
When the web server rewrites URLs, Dispatcher requires a single farm defined according to Configuring Dispatcher. The following configurations are required to support the web server virtual hosts and URL renaming rules:
/virtualhosts
property must include the ServerName values for the all VirtualHost definitions./statfileslevel
property must be high enough to create .stat files in the directories that contain the content files for each domain.The following example configuration file is based on the example dispatcher.any
file that is installed with Dispatcher. The following changes are required to support the web server configurations of the previous httpd.conf
file:
/virtualhosts
property causes Dispatcher to handle requests for the brandA.com
and brandB.com
domains. (line 12)/statfileslevel
property is set to 2, so that stat files are created in each directory that contains the domain’s web content (line 41): /statfileslevel "2"
As usual, the document root of the cache is the same as the document root of the web server (line 40): /usr/lib/apache/httpd-2.4.3/htdocs
dispatcher.any
/name "testDispatcher"
/farms
{
/dispfarm0
{
/clientheaders
{
"*"
}
/virtualhosts
{
"brandA.com" "brandB.com"
}
/renders
{
/rend01 { /hostname "127.0.0.1" /port "4503" }
}
/filter
{
/0001 { /type "deny" /glob "*" }
/0023 { /type "allow" /glob "*/content*" } # disable this rule to allow mapped content only
/0041 { /type "allow" /glob "* *.css *" } # enable css
/0042 { /type "allow" /glob "* *.gif *" } # enable gifs
/0043 { /type "allow" /glob "* *.ico *" } # enable icos
/0044 { /type "allow" /glob "* *.js *" } # enable javascript
/0045 { /type "allow" /glob "* *.png *" } # enable png
/0046 { /type "allow" /glob "* *.swf *" } # enable flash
/0061 { /type "allow" /glob "POST /content/[.]*.form.html" } # allow POSTs to form selectors under content
/0062 { /type "allow" /glob "* /libs/cq/personalization/*" } # enable personalization
/0081 { /type "deny" /glob "GET *.infinity.json*" }
/0082 { /type "deny" /glob "GET *.tidy.json*" }
/0083 { /type "deny" /glob "GET *.sysview.xml*" }
/0084 { /type "deny" /glob "GET *.docview.json*" }
/0085 { /type "deny" /glob "GET *.docview.xml*" }
/0086 { /type "deny" /glob "GET *.*[0-9].json*" }
/0090 { /type "deny" /glob "* *.query.json*" }
}
/cache
{
/docroot "/usr/lib/apache/httpd-2.4.3/htdocs"
/statfileslevel "2"
/allowAuthorized "0"
/rules
{
/0000 { /glob "*" /type "allow" }
}
/invalidate
{
/0000 { /glob "*" /type "deny" }
/0001 { /glob "*.html" /type "allow" }
}
/allowedClients
{
}
}
/statistics
{
/categories
{
/html { /glob "*.html" }
/others { /glob "*" }
}
}
}
}
Because a single Dispatcher farm is defined, the Dispatcher Flush replication agent on the AEM publish instance requires no special configurations.
To rewrite references to files that have extensions other than .html or .htm, create a Sling rewriter transformer component and add it to the default rewriter pipeline.
Rewrite references when resource paths do not resolve correctly in the web server context. For example, a transformer is required when image-generating components create links such as /content/sitea/en/products.navimage.png. The topnav component of the How to Create a Fully Featured Internet Website creates such links.
The Sling rewriter is a module that post-processes Sling output. SAX pipeline implementations of the rewriter consist of a generator, one or more transformers, and a serializer:
AEM uses a default pipeline rewriter that processes documents of type text/html:
htmlparser
.linkchecker
, mobile
, mobiledebug
, contentsync
. The linkchecker
transformer externalizes paths to referenced HTML or HTM files to prevent broken links.The /libs/cq/config/rewriter/default
node defines the pipeline.
Perform the following tasks to create a transformer component and use it in a pipeline:
org.apache.sling.rewriter.TransformerFactory
interface. This class creates instances of your transformer class. Specify values for the transformer.type
property (the transformer alias) and configure the class as an OSGi service component.org.apache.sling.rewriter.Transformer
interface. To minimize the work, you can extend the org.apache.cocoon.xml.sax.AbstractSAXPipe
class. Override the startElement method to customize the rewriting behavior. This method is called for every SAX event that is passed to the transformer.You can instead configure the TransformerFactory to that the transformer is inserted into every rewriter that is defined. Consequently you do not need to configure a pipeline:
pipeline.mode
property to global
.service.ranking
property to a positive integer.pipeline.type
property.Use the multimodule archetype of the Content Package Maven Plugin to create your Maven project. The POMs automatically create and install a content package.
The following examples implement a transformer that rewrites references to image files.
The examples are not robust and should not be used in a production environment.
package com.adobe.example;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Service;
import org.apache.felix.scr.annotations.Property;
import org.apache.sling.rewriter.Transformer;
import org.apache.sling.rewriter.TransformerFactory;
@Component
@Service
public class MyRewriterTransformerFactory implements TransformerFactory {
/* Define the alias */
@Property(value="mytransformer")
static final String PIPELINE_TYPE ="pipeline.type";
public Transformer createTransformer() {
return new MyRewriterTransformer ();
}
}
package com.adobe.example;
import java.io.IOException;
import org.apache.cocoon.xml.sax.AbstractSAXPipe;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.rewriter.ProcessingComponentConfiguration;
import org.apache.sling.rewriter.ProcessingContext;
import org.apache.sling.rewriter.Transformer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;
import javax.servlet.http.HttpServletRequest;
public class MyRewriterTransformer extends AbstractSAXPipe implements Transformer {
private static final Logger log = LoggerFactory.getLogger(MyRewriterTransformer.class);
private SlingHttpServletRequest httpRequest;
/* The element and attribute to act on */
private static final String ATT_NAME = new String("src");
private static final String EL_NAME = new String("img");
public MyRewriterTransformer () {
}
public void dispose() {
}
public void init(ProcessingContext context, ProcessingComponentConfiguration config) throws IOException {
this.httpRequest = context.getRequest();
log.debug("Transforming request {}.", httpRequest.getRequestURI());
}
@Override
public void startElement (String nsUri, String localname, String qname, Attributes atts) throws SAXException {
/* copy the element attributes */
AttributesImpl linkAtts = new AttributesImpl(atts);
/* Only interested in EL_NAME elements */
if(EL_NAME.equalsIgnoreCase(localname)){
/* iterate through the attributes of the element and act only on ATT_NAME attributes */
for (int i=0; i < linkAtts.getLength(); i++) {
if (ATT_NAME.equalsIgnoreCase(linkAtts.getLocalName(i))) {
String path_in_link = linkAtts.getValue(i);
/* use the resource resolver of the http request to reverse-resolve the path */
String mappedPath = httpRequest.getResourceResolver().map(httpRequest, path_in_link);
log.info("Tranformed {} to {}.", path_in_link,mappedPath);
/* update the attribute value */
linkAtts.setValue(i,mappedPath);
}
}
}
/* return updated attributes to super and continue with the transformer chain */
super.startElement(nsUri, localname, qname, linkAtts);
}
}
Create a JCR node that defines a pipeline that uses your transformer. The following node definition creates a pipeline that processes text/html files. The default AEM generator and parser for HTML are used.
If you set the Transformer property pipeline.mode
to global
, you do not need to configure a pipeline. The global
mode inserts the transformer into all pipelines.
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:jcr="https://www.jcp.org/jcr/1.0" xmlns:nt="https://www.jcp.org/jcr/nt/1.0"
jcr:primaryType="nt:unstructured"
contentTypes="[text/html]"
enabled="{Boolean}true"
generatorType="htmlparser"
order="5"
serializerType="htmlwriter"
transformerTypes="[mytransformer]">
</jcr:root>
The following graphic shows the CRXDE Lite representation of the node: