Content Application Developer Manual / Version 2512.1
Table Of Contents
The CAE employs a client-side JavaScript library to replace baseline fragments on a page with
variant fragments dynamically. To this end, the CAE intercepts all template render operations,
both for the original request and for all includes. If the render operation targets a content
item for which variants exist, the output is augmented with a <div> that
carries metadata about the available variants and the URLs from which replacement fragments can
be retrieved. Replacement fragments can be retrieved from the CAE through XML HTTP requests. In
order to speed up the rendering of the page on the client, the CAE can be configured to include
pre-rendered replacement fragments.
Once the page is personalized on the client, metadata elements are removed from the page, ensuring a clean DOM structure. If you want to inspect the page before the replacements are applied, check the original response of the page request instead of viewing the DOM in the browser.
For the Engagement Cloud integration, the user segments and test cases of the viewer are only retrieved for the live delivery. In the preview, user segments and test cases are only passed through URL parameters.
Extension Points
Because the metadata <div> elements must not be rendered outside the main HTML
<body> element, the CAE uses a set of BodyDetector instances that
determine the context of a render operation. By default, page beans indicate that the body has
not yet started, as does the view fragmentPreview. On the other hand, a page grid
and the views asPreview and prefetchFragments are assumed to occur only
inside the HTML body. You may have to adjust the configuration in
BlueprintCaeVariantAutoConfiguration, if this configuration does not match your
template structure. If a surrounding body element cannot be detected this easily, you can provide
a custom implementation of BodyDetector, which can also take the current request
object into account.
Templates accept beans for rendering, especially content beans, but the variant service is only
concerned with content items. In order to translate between beans and content, the interface
ContentVariantProcessor is used. It can determine the content item backing a bean
(method getContentFor()) and it can also create a bean for a given content item for
the purposes of rendering a link to include the content item as a fragment (method
toVariantBeanForLinking()). If you want to support variants for beans other than
content beans, pages, and page grids, you need to implement the
ContentVariantProcessor interface. For this, you also provide beans to represent the
beans for the purpose of linking as a fragment and a URL formatter and a handler to process
fragment requests. For commerce link building, the fragment bean class needs to implement the
VariantFragment interface. You can base your implementation on
PageGridVariantFragment, PageGridContentVariantProcessor,
VariantHandler.formatPageGridLink, and
VariantHandler.handlePageGridRequest.
In some cases, the CAE can determine whether a variant is active during rendering. This happens
in particular, if the CAE serves a fragment request for a variant with a specific condition and
that condition is associated with a variant of an included bean. In this situation, the CAE will
automatically replace the bean, this time using the ContentVariantProcessor method
toVariantBeanForRendering() for a bean that is passed directly into the render chain.
The ContentVariantProcessor objects are also used to resolve variant beans to
baseline beans for the purpose of generating links. Links should always target baselines to avoid
multiple URLs for similar pages and to allow bookmarks for pages with variants that become active
and inactive over time.
Some condition strings may define conditions that can be evaluated on the server from the request
context. Such conditions can be processed by a VariantConditionPredicate. The CAE
can immediately replace the rendered content by a variant that is known to be active, if there are
no variants with a higher priority that might also be active. The
VariantConditionPredicate can inspect the request object when making its decision.
Note that any potential caching layer in front of the CAE must cache requests separately, if the
predicate might judge the requests differently.
The metadata <div> also carries information for tracking views of fragments and
test cases. To enrich the tracking process, further information about a bean is obtained from a
VariantDescriptionPopulator.
Programming Model
So that all template render operations can be intercepted by the variant framework, includes must
always go through the ViewUtils.render(…) methods without a View
parameter. This ensures that the RenderNodeDecorator API can intercept the calls and
pass information through the request context.
Templates should always close all HTML elements that they open, so that the metadata
<div> elements do not result in an invalid HTML structure.
Templates should only render data for properties of a single content bean. If a template follows a link between content beans programmatically to retrieve a property of a different content bean for rendering, that access will not result in a metadata element and the client-side framework will not be able to replace it with a potential variant. Instead, an include should be used for accessing the other bean.
When adding RenderNodeDecorator objects or ViewDecorator objects, test
their interaction with the variant framework carefully.
FreeMarker Library
A FreeMarker library is provided for advanced use cases.
With the macro variantAttributes it is possible to flag HTML elements for replacement
outside the HTML body. For example, a CSS link in the HTML head might be rendered like this:
<link rel="stylesheet" href="..."<@variants.variantAttributes />>
This adds a metadata attribute to the HTML that carries the information that in other contexts
would go into the metadata <div> element. The precise positioning of the
attribute needs the collaboration of the template author.
With the macro includeVariants it is possible to specify whether replacement
fragments for the output of the current template should be directly included in the response.
This can be particularly helpful, if most of the replacement fragments should be included, but you
want to specify exceptions to the general rule. The following call makes sure that no replacements
for the current template are included:
<@variants.includeVariants value=false/>
By default, included replacements are rendered as soon as the outermost metadata
<div> ends. If you want to specify exactly where the replacements end up, you
can use the macro renderVariants. When called, it renders all encountered variants,
as long as no variant is still being processed. Typically, this macro should go at the bottom of
the page, but before loading JavaScript code.
<@variants.renderVariants />
For this macro to have any effect, there must be variants that have been referenced, but not yet rendered. This is only possible if the early rendering of replacements has been disabled through the following configuration option:
cae.variant.includeVariantsEarly=false
Client-Side Processing
The brick p13n-dynamic-include is responsible for evaluating the metadata
<div> elements and for replacing them with directly included variants or
variants retrieved using XMLHttpRequest callbacks. The brick takes care to check
replacement elements for further metadata elements, so that it is possible to have variable
content within variable content. This may result in multiple round trips to the CAE until the
page is finalized.
The replacement procedure integrates with the brick node-decoration-service and calls
undecorateNode on the node to be replaced before the replacement and
decorateNode on the replacement node after the replacement. This allows other DOM
updaters, e.g., JavaScript-based layout algorithms, to act on variable content. On the other hand,
the brick p13n-dynamic-include reacts to node decoration events in case another
procedure retrieves dynamic data from the CAE, inserts it into the DOM and calls the node
decoration service to decorate this node. This allows variants in dynamically inserted content.
Commerce Integration
The variant delivery mechanism integrates with the rendering of fragments for commerce-led
websites. In a fragment for a commerce site, all links to VariantFragment objects are
specially encoded, so that they can be rewritten by the commerce system when it includes the
fragment on a commerce site. The links are typically rewritten in a way that they point to the
commerce site and are proxied to the CAE.
Caching
Replacement fragments are retrieved from paths below /dynamic/fragment/variant and
are independent of the applicable variant conditions. Such responses may be cached by a web cache
or a browser. You can control the cache headers returned by the CAE using the
cae.cache-control.for-url-pattern configuration options.


