Está en la página 1de 37

JESI QuickStart

JESI Caching Quick Start

By MC

Draft Version: 1.4

Check www.jahia.org for regular updates

© Jahia Ltd, all rights reserved.


Page 1 of 37
JESI QuickStart

Changelog

• 29/11/2005: document created.


• 23/06/2006: added doc for absolute and alwaysInvalidate attributes.
• 12/07/2006: explained fragment number constraint.
• 20/10/2006: added custom class section, aclGroup templates, manual
invalidations, key generation overview, platform-specific AOP configuration
and other minor additions.
• 06/12/2006 : Portlet caching section added.

© Jahia Ltd, all rights reserved.


Page 2 of 37
JESI QuickStart

1) Introduction

This guide will give the reader a quick overview of how to include Java Edge-Side Includes (JESI)
caching tags in their templates. These tags are translated into ESI markup by the JSP compiler. JESI
tags also take care of setting the appropriate HTTP headers required by the ESI webcache server.

2) Recommended reading

http://www.oracle.com/webapps/online-
help/jdeveloper/10.1.3/state/content/vtTopicFile.developing_with_ojsp%7Cojsp_rjesitaglib~html/nav
Id.4/navSetId._/

http://www.oracle.com/webapps/online-
help/jdeveloper/10.1.2/state/content/locale.en/vtTopicFile.developing_with_ojsp%7Cjesitags%7Eht
ml/navId.4/navSetId._/

http://www.esi.org/jesit_tag_lib_1-0.html

3) Currently Supported JESI Tags

Jahia currently supports a JESI tags defined in \tomcat\webapps\jahia\WEB-INF\tld\jesi-tags.tld (a


modified subset of the Oracle JESI tags) which are:

• jesi:template
o supported attributes:
ƒ control
ƒ cache
ƒ expiration
ƒ maxRemovalDelay
ƒ aclGroup
• jesi:fragment
o supported attributes:
ƒ control
ƒ cache
ƒ expiration
ƒ maxRemovalDelay
ƒ user
ƒ group
ƒ aclGroup
ƒ absolute
© Jahia Ltd, all rights reserved.
Page 3 of 37
JESI QuickStart

ƒ alwaysInvalidate
• jesi:codeblock
o supported attributes:
ƒ execute
• jesi:control
o supported attributes:
ƒ control
ƒ cache
ƒ expiration
ƒ maxRemovalDelay

4) Example 1

The current version of the corporate_templates contains


\tomcat\webapps\jahia\jsp\jahia\templates\mySite\corporate_portal_templates\simple.jsp which we
will take as the basis for our first example:

<%@ taglib uri="/WEB-INF/tld/jesi-tags" prefix="jesi" %>


<jesi:template cache="yes">

<%@ include file="include/header.inc"%>


<jesi:fragment cache="yes">
<table width="100%" border="0" cellspacing="0" cellpadding="0">
<tr>
<td width="159" valign="top"><%@ include file="include/left_menu.inc"%></td>
<% if (!thePrint && hasLeft != 0) { %><td class="verticaleline"><img
src="<jahia:contextURL/>/images/pix.gif" width="25" height="12" alt=""/></td><% }
%>
<td width="100%" valign="top">

<h1><%@ include file="include/page_title.inc"%></h1>


<jsp:include page="include/main_content.jsp" flush="true">
<jsp:param name="id" value="main_1"/>
</jsp:include>
<jsp:include page="include/box.jsp" flush="true">
<jsp:param name="id" value="main_1"/>
<jsp:param name="displayDetails" value="true"/>
</jsp:include>
</td>
<td><img src="<jahia:contextURL/>/images/pix.gif" width="25" height="12"
alt=""/></td>
<td valign="top">
<jsp:include page="include/box.jsp" flush="true">
<jsp:param name="id" value="right"/>
<jsp:param name="width" value="160"/>
</jsp:include>

© Jahia Ltd, all rights reserved.


Page 4 of 37
JESI QuickStart

</td>
</tr>
</table>
</jesi:fragment>

<jesi:fragment cache="yes" group="footer_banner" > <esi:comment text="This


fragment will be shared across all users" />
<%@ include file="include/footer.inc"%>
</jesi:fragment>

</jesi:template >
Simple.jsp

Let us look at the code step-by-step. We first import JESI taglib before declaring this page as an ESI
template using the jesi:template :

<%@ taglib uri="/WEB-INF/tld/jesi-tags" prefix="jesi" %>


<jesi:template cache="yes">

Note that this must be the first tag on the page. Scripts or HTML not enclosed within the
jesi:template tag will not be displayed, so be sure to carefully place this tag.

The cache="yes" attribute means that this Template (also known as page skeleton) will be cached by
the ESI webcache for the default period of time of 24 hours.

<jesi:fragment cache="yes">

The <jesi:fragment cache="yes"> tag notifies the start of an ESI Fragment. It will also be cached
for the default time period. It is equivalent to <jesi:fragment>.
The above example declares two fragments: one surrounding the main content of the page and
another the footer. Both these fragments must be enclosed within a parent jesi:template tag.

If we wanted to cache these fragments for more (or less) time, we could use the expiration attribute,
specified in seconds, such that:

<jesi:fragment expiration="15">

would mean this fragment is only valid in the ESI cache 15 seconds. Subsequent requests for this
fragment will result in a request to the Jahia server for a fresh version.

<jesi:fragment expiration="150">

this example, on the other hand, will be refreshed every 150 seconds.

© Jahia Ltd, all rights reserved.


Page 5 of 37
JESI QuickStart

To make sure the ESI server always fetches a new version of the Fragment for every request to that
page:

<jesi:fragment expiration="0"> , is also equivalent to <jesi:fragment cache="no">

The same expiration notation applies to the template such that:

<jesi:template expiration="15"> refresh every 15 seconds

<jesi:template cache="yes"> default 24 hour time-to-live

5) Template Tag

The jesi:template tag generates a skeleton for a each page. This skeleton contains everything (e.g.
html and java scripts) declared outside any enclosed jesi:fragment tags and include links to these
fragments.

In practice, the generated skeleton should comprise mostly of include links to fragments and little
content. The majority of the content should be enclosed in jesi:fragments tags. This is why we refer
to it as a skeleton since it establishes the general structure of the page.

The default behaviour of jesi:template tag is to cache each generated skeleton on a per-user basis (see
later for a shared alternative using aclGroup). That is, a new instance of the skeleton is stored in the
ESI webcache for each logged in Jahia user.

Therefore

<jesi:template cache="yes">

is equivalent to

<jesi:template cache="yes" user="<%=Jahia.getThreadParamBean().getUser().getUserKey()%>">

If you know in advance that a page will be the same for groups of users, it is possible to share a
single skeleton instance between each group member:

<jesi:template cache="yes" group="<%=getGroupName(currentUser)%>">

where getGroupName() will return a unique String describing the group to which the current user
belongs to.

It is also possible to use for example the current user’s properties to group users together. So, if say,
we had a template identical for each user except for its background colour. And the background is

© Jahia Ltd, all rights reserved.


Page 6 of 37
JESI QuickStart

defined in the current user’s profile properties. Then we could simply put the colour name as a group
identifier as such:

<jesi:template cache="yes" group="<%=getUserBackgroundColourPreference(currentUser)%>">

All users with the same background colour preference would share the same skeleton.

The group attribute in the examples above is dynamically generated for each user. It is also possible
to include a static group name, as such:

<jesi:template cache="yes" group="salesperson">

this declares skeleton which is shared by all users.

aclGroup Template Sharing

In a similar manner to fragment aclGroup sharing (see later), the jesi:template tag also supports an
additional attribute called aclGroup. Instead of using the username as in the 'user' attribute as defined
in the default behaviour, or generating an arbitrary string for the 'group' attribute, you can use the
aclGroup attribute to share templates between those who belong to the same Access Control List
(ACL) groups.

This is done by basically automatically generating a unique key based on the current user's ACL
group membership. This key is later appended to the fragment URL so that all users with the same
group membership rights will point to the same fragment.

The aclGroup attribute supports the following values:

• 'true' (reserved) : activate the aclGroup template caching.


• '[false]' (reserved) : deactivate the aclGroup template caching and revert to user/group
caching instead. This is the default behaviour.
• any other value : activate the aclGroup template caching and append this string value to
the unique key based on the user's ACL group membership. This basically compounds the
functionality of the 'group' and 'aclGroup' attributes.

General Comments

Only one template per JSP page is allowed.

The template developer should try to maximize template sharing between users. The reason for this
are twofold:

© Jahia Ltd, all rights reserved.


Page 7 of 37
JESI QuickStart

• When a skeleton is detected as invalid/stale, only one instance needs to be fetch by the ESI
webcache for all users sharing this skeleton, reducing response times and the workload on the
Jahia server necessary to regenerate each skeleton.

• Only one instance of a skeleton is stored on the ESI webcache for each group, reducing
memory requirements on the webcache.

Please refer to the “Final Remarks/Template Sharing” section for caveats on template sharing.

6) Fragment Tag

The jesi:fragment tag declares an area of content which must be cached separately from the skeleton.
Fragments can be shared across different users of the same page; they currently cannot be shared
across different pages (see Final Remarks).

The default caching behaviour is the same as the jesi:template tag, that is per-user caching. Therefore

<jesi:fragment> or <jesi:fragment cache="yes">

is equivalent to

<jesi:fragment
cache="yes"
user="<%=Jahia.getThreadParamBean().getUser().getUserKey()%>"
>

You can circumvent this behaviour and specify your own user caching key by setting this attribute.
For example, by setting it to another username if you know in advance they will
be displaying the same fragment.

Static and dynamic groups are also supported:

<jesi:fragment cache="yes" group="homepage_footer">

This fragment declaration, defining the “homepage_footer” static group, can be used to share the
footer fragment on the homepage between all users.

However, if the background colour of the footer depended on a preference setting in the current user's
properties, this solution wouldn't work since the same footer would be displayed to all users
independent of their background colour preferences. To share fragments with the same background
colour, one would simply need to modify the group to :

<jesi:fragment

© Jahia Ltd, all rights reserved.


Page 8 of 37
JESI QuickStart

cache="yes"
group="<%="homepage_footer" + getUserBackgroundColourPreference(currentUser) %>"
>

where getUserBackgroundColourPreference() returns a unique string for the colour selected by the
current user.

The functionality of the 'group' and 'user' attributes are roughly identical
since the 'user' attribute could be used to achieve the same effect by
setting

<jesi:fragment
cache="yes"
user="<%="homepage_footer"
+getUserBackgroundColourPreference(currentUser)%>">

However, this is not recommended. The 'user' attribute should only be


used for specifying usernames and 'group' for anything else. If we only
used the 'user' attribute then we'd introduce the possibility of naming
collisions between identical usernames and a group names.

Note that if the 'user' attribute is also set, it will take precedence and the 'group' attribute which will
be ignored.

aclGroup sharing

The jesi:fragment tag also supports an additional attribute called aclGroup. Instead of using the
username as in the 'user' attribute as defined in the default behaviour, or generating an arbitrary string
for the 'group' attribute, you can use the aclGroup attribute to share fragments between those who
belong to the same ACL groups.

This is done by basically automatically generating a unique key based on the current user's ACL
group membership. This key is later appended to the fragment URL so that all users with the same
ACL group memberships will point to the same fragment.

The aclGroup attribute supports the following values:

• 'true' (reserved) : activate the aclGroup fragment caching.


• ['false'] (reserved) : deactivate the aclGroup fragment caching and revert to user/group
caching instead. This is the default behaviour.
• any other value : activate the aclGroup fragment caching and append this string value to
the unique key based on the user's ACL group membership. This basically compounds the
functionality of the 'group' and 'aclGroup' attributes. So for example, if we want to render
a footer which displays a containerList in a user specified background colour, all users

© Jahia Ltd, all rights reserved.


Page 9 of 37
JESI QuickStart

with the same background colour settings in their profiles and with the same group
memberships will see the same list of containers with the same background colour by
setting the tag to:

<jesi:fragment
cache="yes"
aclGroup="<%="homepage_footer"+getUserBackgroundColourPreference(currentUser)%>"
>

Note that if the 'user' or 'group' attribute is also set, it will take precedence and the 'aclGroup'
attribute will be ignored.

If neither 'user', 'group' nor 'aclGroup' attributes are defined, the default behaviour of the
jesi:fragment tag is to cache each fragment by user.

If any content enclosed in this fragment exhibits a special ACL entry for
the current user's name, then a specific group for that single user is
created. This is because this user might have specific rights added or
removed on the content referenced in this fragment.

Absolute fragments

The group/user/aclGroup attributes alone make it possible to share fragments between users of the
same page, but not between users on different pages. The absolute attribute addresses this issue.

In Jahia, a page is defined by its unique /pid/xxx value. So all users accessing a page with say /pid/1
can share fragments. However, fragments cannot be shared between pages /pid/1 and /pid/2.

Using the 'absolute' attribute, fragments can be made available to all pages independent of their pid or
JSP template. The 'absolute' attribute must be used in conjunction with a group/user/aclGroup
attribute to allow cross-page user or group sharing of fragments.

The absolute attribute supports the following values:

• 'true' or 'yes': activate absolute fragment sharing.


• ['false'] or 'no': (default) deactivate absolute fragment sharing.

This is a powerful way of sharing content and maximizing cache usage. However it must be used
with caution because the content generated in an absolute fragment must be identical on all pages
sharing this content, otherwise we have no idea what will be displayed. In order to do this, every JSP
template must have the exact same code between absolute fragment tags for each absolute fragment.

© Jahia Ltd, all rights reserved.


Page 10 of 37
JESI QuickStart

This is due to the fact that the ESI server can query any page for an absolute fragment and it will
share it with any other page that displays this absolute fragment.

For example, if an absolute fragment JSP code looked like this:


<jesi:fragment absolute="true" group="footer">
My footer html here.
<jesi:fragment/>

then we could safely paste it in all JSP template and share it between all users and instantiated Jahia
pages (i.e. pid pages).

However if an absolute fragment JSP code looked like this:

int fontsize = (int) ( 8 + processingContext.getPid() );


<jesi:fragment absolute="true" group="footer">
<fontsize size="<%=fontsize%>">
My footer html here.
<jesi:fragment/>

In this example, the fontsize variable varies with the current page's pid number and therefore is
specific to each page. Thus, the first page to generate this absolute fragment and store it in the ESI
cache, will be the exactly the same one displayed by every other page displaying this absolute
fragment, independent of their current pid. This of course isn’t workable. One couldn’t use absolute
fragments for this example.

It is therefore important that the content of an absolute fragment generated by any page
be identical, no matter what page is queried for that fragment.

Usage Example 1:

<jesi:fragment absolute="true" group="footer">

This footer fragment will be shared by all pages, regardless of the original JSP template used.

Usage Example 2:

<jesi:fragment
absolute="true" group="<%="footer"+currentUserPreferences.getFooterBackgroundColour()%>">

This fragment will be shared users with the same footer background colour preference, regardless of
the page or the original JSP template used.

Usage Example 3:

<jesi:fragment absolute="true" aclGroup="true">

© Jahia Ltd, all rights reserved.


Page 11 of 37
JESI QuickStart

This fragment will be shared by all users belonging to the same user groups, regardless of the page or
the original JSP template used.

Usage Example 4:

<jesi:fragment absolute="true" user="true">

This fragment will be shared by a same user across all pages and regardless of the original JSP
template used.

The following diagram summaries the possible types of fragment sharing:

jesi:fragment Attributes Sharing between users Sharing between pids


aclGroup YES (between users belonging to the
NO
same ACL groups)
aclGroup + absolute=’true’ YES (between users belonging to the
YES
same ACL groups)
group YES NO
group + absolute=’true’ YES YES
user NO NO
user + absolute=’true’ NO YES
(no sharing attribute) NO NO
(no sharing attribute) +
NO YES
absolute=’true’

alwaysInvalidate fragments

The alwaysInvalidate attribute was introduced to force invalidations of fragments before its
expiration time or even when no content inside it was changed. It is currently used exclusively
around the page Mode tabs (i.e. Live/Preview/Compare/Edit) in the admin_menu.inc JSP file. We do
this to ensure that it will be invalidated from the ESI cache in all modes if anything is changed on the
page. This is to guarantee that the tabs are updated to reflect the current status of the page.

The alwaysInvalidate attribute supports the following values:

• 'true' or 'yes': this fragment will be invalided if any other fragment (or template) is
invalidated on the same page.
• ['false'] or 'no': (default) will only be invalidated when explicitly necessary.

If ‘true’, then a fragment is always invalidated if something is changed anywhere else on the page, in
every mode (e.g. live/preview/compare/edit modes). This is used for example on the edit tabs so that

© Jahia Ltd, all rights reserved.


Page 12 of 37
JESI QuickStart

the fragment containing the tabs is invalidated in every mode if any other fragments is invalidated.
This is due to the fact that the Live mode is only invalidated when content is validated through the
workflow; if this was the case then the tabs in Live mode would not always be coherent.
<jesi:fragment alwaysInvalidate="true" aclGroup="true">

This attribute is useful to use on fragments that need to be invalidated if anything is changed on the
page. You can use it in conjunction with aclGroup/group/user attributes. It also works with 'absolute'
attribute but review carefully if that is the behaviour you want.

Make sure that the total number of declared fragments on a page is


constant, no matter what logic is executed. It is also recommended that
for a given fragment number, no matter what logic is executed in the JSP,
it should always remain functionally similar. This is because Jahia keeps
track of fragments by their order of appearance in the JSP template. If
these guidelines are not followed some invalidations incoherencies might
occur.

So, for example, given the following template:

<jesi:template>
<jesi:fragment group="pagetitle">
Display page title
</jesi:fragment >
<% if (user.isLogged()) { %>
<jesi:fragment >
Display user info
</jesi:fragment >
<jesi:fragment group="pageHeader">
Display page header menu
</jesi:fragment >
<% } else { %>
<jesi:fragment group="pageHeader">
Display page header menu
</jesi:fragment >
<% } %>
<jesi:fragment group="mainContent">
Display main content
</jesi:fragment >
<jesi:template>

There are two problems here: the non-constant number of total fragments
(depending on if user if logged or not) and the varying order in which
they appear. So the ‘user info’ fragment #2 for logged users will also be
the pageHeader fragment #2 for guests. A better way to write this would
be:

© Jahia Ltd, all rights reserved.


Page 13 of 37
JESI QuickStart

<jesi:template>
<jesi:fragment group="pagetitle">
Display page title
</jesi:fragment >
<jesi:fragment >
<% if (user.isLogged()) { %>
Display user info
<% } else {
//do nothing
} %>
</jesi:fragment >
<jesi:fragment group="pageHeader">
Display page header menu
</jesi:fragment >
<jesi:fragment group="mainContent">
Display main content
</jesi:fragment >
<jesi:template>

7) Codeblock Tag

You can optionally use codeblock tags within the template tag, outside of any fragments, to mark
conditional execution of blocks of code.

To avoid needlessly repeating the execution of expensive template code, strategically place the code
within JESI codeblock tags. Configure each codeblock tag according to when you want the code
within it to be executed (whenever the template is requested, whenever a fragment is requested, or
always).

<jesi:template ... >


...
<jesi:codeblock execute = "template" | "fragment" | "always" >
...request-dependent JSP content...
</jesi:codeblock> ...
</jesi:template>

• template: The enclosed code will only be executed when the current request is requesting the
template. This is equivalent to not putting a codeblock tag around the code.
• fragment: The enclosed code will only be executed when a fragment is being fetched, but
won’t be executed when the template is requested.
• always: The enclosed code is always executed (for both fragment and template requests).

Its behaviour is identical to that described in http://www.oracle.com/webapps/online-


help/jdeveloper/10.1.2/state/content/locale.en/vtTopicFile.developing_with_ojsp%7Cjesitags%7Eht
ml/navId.4/navSetId._/

© Jahia Ltd, all rights reserved.


Page 14 of 37
JESI QuickStart

To maximally boost performance, we highly recommend using this tag profusely (yet thoughtfully).

8) Control Tag

The JESI control tag controls caching characteristics for JSP pages. You can use a JESI control tag
in the top-level page or any included page, but it is not mandatory.

For example, we use the control tag in the sitemap.jsp in the corporate_templates to prevent the entire
page from being cached:

<%@ taglib uri="/WEB-INF/tld/jesi-tags" prefix="jesi" %>


<%-- Don't cache the engines with ESI: --%>
<jesi:control cache="no"/>

We also use it in \webapps\jahia\views\engines\common\taglibs.jsp to disable caching of the engines.

9) Example 2

Let us now look at a more advanced example:

<%@ taglib uri="/WEB-INF/tld/jesi-tags" prefix="jesi" %>


<jesi:template expiration="6000">

<jesi:codeblock execute="always">
<%@ include file="commonDeclarations.inc"%>
</jesi:codeblock>

<jesi:codeblock execute="template">
<%@ include file="topMenuBar.inc"%>
</jesi:codeblock>

<table width="100%" border="0" cellspacing="0" cellpadding="0">


<tr>
<jesi:fragment expiration="6000">
<td width="159" valign="top"><%@ include
file="include/left_menu.inc"%></td>
</jesi:fragment>
<% if (!thePrint && hasLeft != 0) { %><td class="verticaleline"><img
src="<jahia:contextURL/>/images/pix.gif" width="25" height="12" alt=""/></td><% } %>
<td width="100%" valign="top">

<jesi:fragment cache="yes" aclGroup="yes">


<h1><%@ include file="include/page_title.inc"%></h1>
</jesi:fragment>

<jesi:fragment cache="yes" aclGroup="yes">


<jsp:include page="include/main_content.jsp" flush="true">

© Jahia Ltd, all rights reserved.


Page 15 of 37
JESI QuickStart

<jsp:param name="id" value="main_1"/>


</jsp:include>
</jesi:fragment>

<jesi:fragment cache="yes">
<jsp:include page="include/box.jsp" flush="true">
<jsp:param name="id" value="main_1"/>
<jsp:param name="displayDetails" value="true"/>
</jsp:include>
</jesi:fragment>

<jesi:fragment expiration="0">
The current time is <%=(new Date())%>
</jesi:fragment>

</td>
<td><img src="<jahia:contextURL/>/images/pix.gif" width="25" height="12"
alt=""/></td>
<td valign="top">
<jesi:fragment cache="yes">
<jsp:include page="include/box.jsp" flush="true">
<jsp:param name="id" value="right"/>
<jsp:param name="width" value="160"/>
</jsp:include>
</jesi:fragment>
</td>
</tr>
</table>

<jesi:codeblock execute="always">
<%
String organization =
org.apache.commons.lang.StringUtils.trimToEmpty(user.getProperty("organization"));
%>
</jesi:codeblock>

<jesi:fragment cache="yes" aclGroup="<%=organization%>">


Your <%=organization%> has the following news:

<%
int id = 1;
int newsListPid = -1;
JahiaContainerList newsLinkContainerList1 =
jData.containers().getContainerList( "newsListContainer" + id);
if ( newsLinkContainerList1 != null ) {
Enumeration newsLinkEnumeration = newsLinkContainerList1.getContainers();
while (newsLinkEnumeration.hasMoreElements()) {
JahiaContainer newsLinkContainer =
(JahiaContainer)newsLinkEnumeration.nextElement();
if ( newsLinkContainer != null ){
JahiaPage newsListLink = (JahiaPage)
newsLinkContainer.getFieldObject( "newsListLink" + id);
if ( newsListLink != null ) {
newsListPid = newsListLink.getID();
%><a href="<%=newsListLink.getUrl(jData.params())%>"
class="news"><%=newsListLink.getTitle()%></a><%
}
}
}
}

© Jahia Ltd, all rights reserved.


Page 16 of 37
JESI QuickStart

%>
</jesi:fragment>

<jesi:fragment cache="yes" group="footer_banner" >


<%@ include file="include/footer.inc"%>
</jesi:fragment>

</jesi:template >
Example2.jsp

The JSP first declares a skeleton cached on a per-user basis which automatically self-expires every
100 minutes:

<jesi:template expiration="6000">

The codeblock tag is then used to make sure that common variable declarations, javascript includes
and necessary JSP includes are executed every time both a fragment or the skeleton is requested:

<jesi:codeblock execute="always">
<%@ include file="commonDeclarations.inc"%>
</jesi:codeblock>

Next we want to render the top menu bar. For better performance, it is preferable to include this code
inside another codeblock tag; this time with the execute="template" attribute. This ensures that we
only execute this code when re-generating the skeleton and not whilst fetching each fragment. This is
because when we fetch a fragment, the generated topMenu bar (along with all the other skeleton
content) is simply ignored. So it’s an unnecessary burden to generate it to fetch a single targeted
fragment’s output.

<jesi:codeblock execute="template">
<%@ include file="topMenuBar.inc"%>
</jesi:codeblock>

Next we declare a standard per-user cached fragment:

<jesi:fragment expiration="6000">
<td width="159" valign="top"><%@ include
file="include/left_menu.inc"%></td>
</jesi:fragment>

We then make use of the aclGroup caching mechanism in the following snippet:

<jesi:fragment cache="yes" aclGroup="yes">


<h1><%@ include file="include/page_title.inc"%></h1>
</jesi:fragment>

© Jahia Ltd, all rights reserved.


Page 17 of 37
JESI QuickStart

We didn’t use a per-group based caching since, although the page title is identical for everyone, not
everyone has the same editing rights on it.

The next snippet of interest is the one displaying the current time:

<jesi:fragment expiration="0">
The current time is <%=(new Date())%>
</jesi:fragment>

We want to make sure this is never cached so each page refresh will cause the display of the correct
time.

The more interesting fragment declaration is the one displaying the news entries:

<jesi:codeblock execute="always">
<%
String organization =
org.apache.commons.lang.StringUtils.trimToEmpty(user.getProperty("organization"));
%>
</jesi:codeblock>

<jesi:fragment cache="yes" aclGroup="<%=organization%>">


<%
int id = 1;
int newsListPid = -1;
JahiaContainerList newsLinkContainerList1 =
jData.containers().getContainerList( "newsListContainer" + id);
if ( newsLinkContainerList1 != null ) {
Enumeration newsLinkEnumeration = newsLinkContainerList1.getContainers();
while (newsLinkEnumeration.hasMoreElements()) {
JahiaContainer newsLinkContainer =
(JahiaContainer)newsLinkEnumeration.nextElement();
if ( newsLinkContainer != null ){
JahiaPage newsListLink = (JahiaPage)
newsLinkContainer.getFieldObject( "newsListLink" + id);
if ( newsListLink != null ) {
newsListPid = newsListLink.getID();
%><a href="<%=newsListLink.getUrl(jData.params())%>" class="news">
<%=organization%>’s News : <%=newsListLink.getTitle()%></a><%
}
}
}
}
%>
</jesi:fragment>

We could’ve used a aclGroup="yes" in the fragment declaration to share this fragment across all
users with the same ACL group permissions. However, notice that each displayed news entry is
preceded with the user’s current organization name. The name of the organization is retrieved from
the current user’s properties. So we use instead aclGroup="<%=organization%>" to share this
© Jahia Ltd, all rights reserved.
Page 18 of 37
JESI QuickStart

fragment across all users with the same ACL group permissions and with the same organization
name in their profile.

Note that the organization String declaration is always executed using a codeblock tag because it is
both used by the skeleton to generate the caching attributes and by the fragment itself.

Finally, the footer is shared between all users using a static group:

<jesi:fragment cache="yes" group="footer_banner" >


<%@ include file="include/footer.inc"%>
</jesi:fragment>

10) Declaring Custom Class Usage

In order to make the invalidation of fragments and templates on the remote ESI cache server, Jahia
needs to know what content is displayed where and if it has been updated. Once Jahia knows, say, a
Container A has been added to a ContainerList B, it will look for all pages displaying ContainerList
B and invalidate those on the ESI server. Otherwise these pages will display the outdated version of
ContainerList B. The fragments (or templates) referencing, calling or displaying ContainerList B will
be invalidated via a SOAP xml invalidation message from Jahia to the remote ESI server.

To detect which content objects (e.g. Pages, Fields, Containers or ContainerLists) your JSPs
references, calls or displays, Jahia uses Aspect-oriented programming (AOP) to detect at execution-
time the method calls to content objects made from within the JSPs. Jahia is then able to infer and
store which content objects were called from and to which fragment or template they belong.

When an content object is updated/modified/deleted, an eventlistener catches these events and


invalidated any pages that reference that updated content object.

This is normally transparent to the template developer, except in the case when custom classes are
called from within your JSPs. If the code executed in these classes does not reference any Jahia API
calls, then this section does not apply. However, if your classes make use of Jahia content objects,
then they need to be declared to the AspectWerkz AOP mechanism. This will allow Jahia to track
which content objects your code made use of and to locate in which template or fragment it did so.

For example, say we have developed a Java class to retrieve the size of a ContainerList:

package org.reader.mycode;

import org.jahia.data.JahiaData;
import org.jahia.data.containers.JahiaContainerList;
import org.jahia.exceptions.JahiaException;

© Jahia Ltd, all rights reserved.


Page 19 of 37
JESI QuickStart

/**
* User: Reader
* Date: Jul 31, 2006
* Time: 11:09:39 AM
* Copyright (C) Jahia Inc.
*/
public class MyClass {
public MyClass () {
}

public static int getContainerListSize (


JahiaData jData,
String listName,
int pageId) throws JahiaException {

JahiaContainerList absoluteContainerList =
jData.containers().getAbsoluteContainerList(listName, pageId);

if (absoluteContainerList!=null)
return absoluteContainerList.getFullSize();
else
return 0;
}
}

This class is called from your custom JSP, such as:

<%--
My JSP
--%>
<%@ page import="java.lang.*"%>
<%@ page import="java.net.*"%>
<%@ page import="javax.servlet.*"%>
<%@ page import="org.reader.mycode.*"%>
<%@ taglib uri="ajaxLib" prefix="ajax" %>
<%@ taglib uri="jahiaHtmlLib" prefix="jahiaHtml" %>
<%@ taglib uri="contentLib" prefix="content" %>
<%@ taglib uri="JahiaLib" prefix="jahia" %>
<%@ taglib uri="contentLib" prefix="content" %>
<%@ taglib uri="/WEB-INF/tld/jesi-tags" prefix="jesi" %>
<jesi:template>

<%
JahiaData jData = (JahiaData) request.getAttribute(
"org.jahia.data.JahiaData" );
ParamBean jParams = jData.params();
int listSize = MyClass.getContainerListSize(10);
%>
<html>
<body>

<jesi:fragment>

© Jahia Ltd, all rights reserved.


Page 20 of 37
JESI QuickStart

My list size is : <%=listSize%>


</jesi:fragment>

</body>
</html>

</jesi:template >

If AOP doesn’t know about MyClass, then if ContainerList id=10 is modified, the corresponding
page will not be invalidated.

To do this, simply open the \YOUR_TOMCAT\webapps\jahia\WEB-INF\aol.xml and add the path to


your MyClass class there. An already completed sample file is available at
\YOUR_TOMCAT\webapps\jahia\WEB-INF\aol.xml.custom.example for the MyClass example. In
short, the package to your classes needs to be included :

<include package="org.reader.mycode"/>

as well as the scope to your classes in each pointcut declaration :

<pointcut name="addContainerList_pc" >



OR within(org.reader.mycode.MyClass+.*(..))

This means that AOP capturing of content object Jahia API calls will occur whilst executing the any
MyClass methods, including MyClass subclasses. The MyClass+ means all subclasses of MyClass
and *(..) means any method with any number of parameters. You can narrow the scope of course.
For more details on the syntax of aop.xml, please refer to:

http://aspectwerkz.codehaus.org/xml_definition.html.

11) Configuring AOP for your Platform

By default, AOP is configured by default to run on the Apache Tomcat platform. If you intend to use
Jahia on another platform such as WebSphere or WebLogic, you need to make a few minor changes
to the \YOUR_SERVER\webapps\jahia\WEB-INF\aol.xml file.

© Jahia Ltd, all rights reserved.


Page 21 of 37
JESI QuickStart

The following line

<include package="org.apache.jsp.jsp.jahia.templates"/>

as well as any occurrence of :

within(org.apache.jsp.jsp.jahia.templates..*)

need to be changed. The package org.apache.jsp.jsp.jahia.templates is the package Tomcat compiles


and packages the default Jahia templates to. It tells AOP to capture Jahia content update method-calls
made from within JSP templates only, and not anywhere else in the Jahia code.

We could also have used the following declaration :

<include package=" org.apache.jasper.runtime.HttpJspBase"/>

with :

within(org.apache.jasper.runtime.HttpJspBase+)

which has the same effect since all compiled JSP classes are derived from the same HttpJspBase.
Again, refer to http://aspectwerkz.codehaus.org/xml_definition.html for more syntax details.

A different servlet container, such as WebSphere, will probably have a different template package
name or JSP base class. This can be done by inspecting the servlet code generated from the
compilation of JSP files (to be found in the temporary directory where your servlet container
compiles JSP files). You’ll want to pay special attention to either the package statement or the
extends/implements statements.

When you successfully configure your platform to work with AOP, feel
free to contribute your updated AOP file to Jahia so that we can pre-
package pre-configured aop.xml files for various platforms.

12) Manual Invalidations

In parallel to automatic invalidations carried out by Jahia when content is modified, template
developers can initiate invalidations manually to force the remote ESI server(s) to clear specific

© Jahia Ltd, all rights reserved.


Page 22 of 37
JESI QuickStart

cache entries for skeletons (i.e. templates) and/or fragments. This is useful if the changes are
generated by your JSP code logic, and not by Jahia content changes such as in forms.

The invalidations methods discussed here are located in the


org.jahia.services.esi.EsiSOAPInvalidatorService class. Javadoc details are
http://www.jahia.org/javadoc-dev_5/org/jahia/services/esi/EsiSOAPInvalidatorService.html

• Invalidating a whole page

The following code will invalidate the current page and all its fragments in all modes (e.g. Live,
Preview and Edit modes), in all languages and over all users:

<%@ page import="org.jahia.services.esi.EsiSOAPInvalidatorService"%>


<%
JahiaData jData = (JahiaData) request.getAttribute( "org.jahia.data.JahiaData" );

//invalidate page and all its fragments


ServicesRegistry.getInstance().getEsiSOAPInvalidatorService().SOAPInvalid
atePageAndAllFrags(jData.params(), jData.params().getPageID() );
%>

All fragments of any type (e.g group, aclGroup or user) are invalidated, including any absolute
fragments referenced by this page.

A more selective method allows one to include or exclude non-absolute and absolute fragments:

SOAPInvalidatePageAndAllFrags(ProcessingContext pc, int pid,


boolean includeAbsoluteFrags,
boolean includeNonAbsoluteFrags)

Note that if absolute fragments are included then other pages will have to be re-aggregated on the ESI
server if they also reference these absolute fragments.

• Invalidating non-absolute fragments

Sometimes, you’ll want to invalidate only a specific fragment on a page. This is done using the
following method:

SOAPInvalidateFrags(ProcessingContext pc, int pid, Set fragIDs)

You’ll need to retrieve the fragment id, which is the position number it appears on the page, from the
current PageContext. The PageContext object is updated at the very end of the fragment execution,
so it must be executed just after the final </jesi:fragment> closing tag. If this is not the case in your
code, you might be retrieving the fragment id of the previous fragment.

© Jahia Ltd, all rights reserved.


Page 23 of 37
JESI QuickStart

The fragment will then be synchronously removed from the ESI cache, which means that once the
SOAPInvalidateFrags method is called, the fragment is not in the ESI cache anymore. Note that
your invalidation will only take effect for the next request to the page. So you cannot invalidate a
fragment and regenerate it, all in the same request. Only on the next request will the regenerated
fragment be displayed.

There is little point in executing this method inside the actual fragment which you want to invalidate,
since if the fragment is being executed then its updated version is being sent to the ESI server.

Usually, you’ll want to call the SOAPInvalidateFrags method from within the enclosing template or
from within another fragment. So if a template or a fragment is being regenerated, you can force the
invalidation of another fragment within the page or the template itself on the current or other pages. It
is used for example in the corporate_templates_v2 in \common\top.inc for the ESI flush button.

The following code will invalidate the above fragment:

<jesi:fragment aclGroup="true">
Lots of fragment content goes here...
</jesi:fragment>

<%
Integer fragmentID = (Integer) pageContext.getAttribute
("org.jahia.taglibs.esi.fragmentID");

Set fragKeys = new HashSet();


fragKeys.add(fragmentID);

ServicesRegistry.getInstance().getEsiSOAPInvalidatorService().SOAPInvalidateFrags
(jParams, jParams.getPageID(), fragKeys);

%>
fragmentID=<%=fragmentID%>

The invalidation method will only be called when the template is being regenerated. To limit or
expand the times when your invalidation code is executed, use the jesi:codeblock tag. For example,
the following code snippet will be executed only when a fragment is being generated:

<jesi:codeblock execute="fragment">
<%
Integer fragmentID = (Integer) pageContext.getAttribute
("org.jahia.taglibs.esi.fragmentID");

ServicesRegistry.getInstance().getEsiSOAPInvalidatorService().SOAPInvalidateFrags
(jParams, jParams.getPageID(),fragmentID.intValue());

© Jahia Ltd, all rights reserved.


Page 24 of 37
JESI QuickStart

%>
</jesi:codeblock>

• Invalidating absolute fragments

To invalidate a specific absolute fragment, you need to retrieve its unique identifying key first, as
such:

<jesi:fragment aclGroup="myAbsKey3" absolute="true">


Absolute ESI fragment content here
</jesi:fragment>

<%
String absoluteFragmentKey = (String) pageContext.getAttribute
("org.jahia.taglibs.esi.absoluteFragmentKey");

ServicesRegistry.getInstance().getEsiSOAPInvalidatorService().SOAPInvalidateAbsol
uteFrags(jParams, absoluteFragmentKey);
%>

absoluteFragmentKey=<%=absoluteFragmentKey%>

Again, make sure the getAttribute method is called just after the </jesi:fragment> closing tag to be
sure to get the key for the targeted fragment.

• Invalidating for a user

To a certain extend, you can invalidate all the templates/fragments generated by a given user. By
generated, it is meant fragments that were generated in response to a request from a given user. So a
shared fragment X (e.g. group, aclGroup or absolute) might be displayed on user A’s page, but it
might’ve been generated by user B. So if we invalidate all entries for user A, fragment X will not be
invalidated even if it is displayed by user A.

Therefore this method is effective for invalidations of user-specific fragments and for non-
aclGrouped templates. If the template are non-aclGrouped (meaning that they are generated for each
user) then all these templates will be invalidated with this command. All aclGroup=true templates
used by a user will not necessarily be invalidated, except if the current user has generated them.

SOAPInvalidateAllUserEntries(ProcessingContext pc, JahiaUser jahiaUser)


SOAPInvalidateAllUserEntries(ProcessingContext pc, Set users)

• Invalidating the whole cache

© Jahia Ltd, all rights reserved.


Page 25 of 37
JESI QuickStart

It is also possible to empty the entire ESI cache with a single command:

emptyEsiServerCache(SettingsBean settings, boolean emptyOnlyHtml)

The emptyOnlyHtml parameter controls the invalidation of only Jahia pages and fragments, or of
everything including cached Javascript, image, css and other non-Jahia-page objects.

• Combo method

The following method allows the invalidation of multiple pages (and all their fragments) as well as
all the entries generated by a set of users, all in one go.

SOAPInvalidatePagesAndAllFragsAndAllUserEntries(ProcessingContext pc,
Set pids,
Set users,
boolean includeAbsoluteFrags,
boolean includeNonAbsoluteFrags)

• Content-based invalidation mechanism

Once a content object is changed, Jahia will automatically invalidate all the templates/fragments
which display it. If however, you want to force this process from your JSP templates, you need to fire
an event that contains a reference to this content object and Jahia will do the rest.

JahiaEvent objectUpdatedEvent =
new JahiaEvent(this, Jahia.getThreadParamBean(), myContentObject);

ServicesRegistry.getInstance ().getJahiaEventService ()
.fireContentObjectUpdated(objectUpdatedEvent);

where myContentObject can be either ContentContainerList, a ContentContainer,


ContentPage, a ContentField etc.

The invalidation will be executed on the next request made to the Jahia server.
It will also invalidate content in the Preview, Compare and Edit mode.

To invalidate in the Live mode also, the following command is used instead:

(new EsiInvalidationEventListener())
.invalidateContentObjectInAllModes(Jahia.getThreadParamBean() , myContentObject);

• GUI invalidation mechanisms

© Jahia Ltd, all rights reserved.


Page 26 of 37
JESI QuickStart

Another way to manually clear the ESI cache and without any coding required, is to use Jahia’s
Administration Center or the ESI server’s Administration Center. Note that if you modify one or
more files in your template directory, you do not need to initiate a manual ESI cache flush. This is
done automatically by Jahia when it detects any file changes in the template directory.

13) Portlet Caching

If you are using Portlets in your JSPs, here is what you need to know about using them with ESI
caching.

Usage:

• One portlet per page

Portlets need to be enclosed within a jesi:fragment tag. The main difference is that you’ll want to set
your expiration delay to ‘0’. Normal rules apply to the remaining the fragments on the page, as well
as the enclosing jesi:template. This means that the fragment containing the portlet will always be
regenerated, but the rest of the page can be cached.

Taking the simple.jsp as an example and assuming that the available boxes are all portlets, then
simply inserting a 0 expiration will do the trick:

<jesi:fragment expiration="0" aclGroup="true">


<jsp:include page="box/box.jsp" flush="true">
<jsp:param name="id" value="full"/>
<jsp:param name="displayDetails" value="true"/>
</jsp:include>
</jesi:fragment>

• Multiple portlets per page

If you have more than one portlet per page, then you can put them all in the same 0 expiration
fragment or in separate 0 expiration fragments. Since each portlet fragment is generated during the
same request as the other portlet fragments, information sharing between portlets is therefore
supported.

• ESI Caching one portlet per page

Portlet fragments can still be cached by ESI, using a non-zero expiration value, but with certain
limitations.

© Jahia Ltd, all rights reserved.


Page 27 of 37
JESI QuickStart

The cache key on the ESI server for fragments is based on the request URL for the page (please read
Key Generation Overview section first). In the case of a page containing a portlet, URLs can be of the
form :

http://localhost:8081/jahia/Jahia/site/mySite/pid/3/jesi_appid/227_2/_ns/YWphaGlhX3BvcnRsZXRf
dGVzdDo6dGVzdHBvcnRsZXQ6Oi01OGFhOTdkZDoxMGY0ZGRjYjM1NjotN2ZmZnxm

where the part after /jesi_appid/ can be different for each request. So we abstract away this variable
portlet part in our cache key to

http://localhost:8081/jahia/Jahia/site/mySite/pid/3/jesi_appid/

This entails that there will only be one cache entry no matter what the variable portlet URL part is.
The consequence is that means that the latest version of the portlet will be served, no matter what the
current variable portlet URL part is. For some portlets, this is not a problem. For others, it might
mean that if a user clicks inside the portlet but still gets the cached version (at least until it expired or
is manually invalidated by yourself).

• ESI Caching multiple portlets per page

If there are multiple portlet fragments on a page and some of them are cached, be sure that there is no
information sharing between them. This is because portlets will be generated on an individual basis
per request, and not all in the same request. If your portlets are independent, then this isn’t an issue. If
they are, this might lead to
unexpected behaviours.

• ESI Sharing portlet

User, group and aclGroup based fragment sharing also applies to portlet fragments. So each user can
have his own version of the portlet, or each user in the same group, or with the same rights. This does
not absolve you from following the restrictions due to the truncated portlet URL in the cache key.

14) Final Remarks

• Template Group Sharing

In practice, template sharing is limited since a group shared skeleton cannot contain fragments
individual to each user. All fragments in a shared skeleton are the same. Let us look at an example:

<jesi:template cache="yes" group="salesperson">


….

© Jahia Ltd, all rights reserved.


Page 28 of 37
JESI QuickStart

<jesi:fragment group="<%= getUserBackgroundColourPreference(currentUser)%>">


…. Fragment 1 ….
</jesi:fragment>

<jesi:fragment >
…. Fragment 2 ….
</jesi:fragment>
….
<jesi:fragment group="salesProjections">
…. Fragment 3 ….
</jesi:fragment>
….
<jesi:fragment aclGroup="true">
…. Fragment 4 ….
</jesi:fragment>
….
</jesi:template>

The template is shared between all users using the static group identifier “salesperson”. However,
Fragment 1 uses a user property to define sharing. The first time this template is executed the result
will be correct for the requesting user, in that Fragment 1 will use his/her preferred background
colour defined in his/her profile. The skeleton is then stored in the ESI webcache.

However, all subsequent users requesting this page will also get this cached skeleton. The problem is
that the include link for Fragment 1 is hardcoded. It points to the fragment group defined by the first
user’s background colour preference. As a result all users, no matter what preferred background
colour is declared in their profile, will get the same instance of Fragment 1.

The same goes for Fragment 2. Here the default jesi:fragment behaviour –per user caching– is
invoked since no attribute is define. All users will see the Fragment 2 initiated by the first user
requesting this fragment.

Only Fragment 3 is correctly defined here. It is shared on a static basis via the “salesProjections”
group. There is no danger of its content being shared incorrectly.

Fragment 4 is incorrect since the rights of the first user to generate this group template will be used to
generate the include link to Fragment 4. Another user, with different rights, should point to another
aclGroup fragment. However this will not be the case here. Therefore aclGroup fragments should not
be used with group sharing.

For these reasons, it is preferable to minimize group template (i.e. skeleton) sharing whilst
maximizing fragment sharing. By minimizing the content stored in each template and using
jesi:codeblock tags, the workload necessary to generate skeletons on a per-user basis (instead of on a
per-group basis) can be kept to a minimum.

• Template aclGroup Sharing

© Jahia Ltd, all rights reserved.


Page 29 of 37
JESI QuickStart

aclGroup template sharing is more flexible than group sharing since it always for aclGroup and per-
user caching:

<jesi:template cache="yes" aclGroup="true">


….
<jesi:fragment group="<%= getUserBackgroundColourPreference(currentUser)%>">
…. Fragment 1 ….
</jesi:fragment>

<jesi:fragment >
…. Fragment 2 ….
</jesi:fragment>
….
<jesi:fragment group="salesProjections">
…. Fragment 3 ….
</jesi:fragment>
….
<jesi:fragment aclGroup="true">
…. Fragment 4 ….
</jesi:fragment>
….
<jesi:fragment aclGroup="myAbsoluteFrag9" absolute="true">
…. Fragment 5 ….
</jesi:fragment>
….
<jesi:fragment aclGroup="<%=getUserBackgroundColourPreference(currentUser)%>">
…. Fragment 6 ….
</jesi:fragment>
….
</jesi:template>

Fragment 1 is still incorrect since different users might have a different group value, even if they
have the same rights.

Fragment 2 is now correct. It will only be displayed by the same user. This is because, during a
request, the current username is dynamically swapped in the include link to the user fragment of the
aclGroup shared template skeleton.

Fragment 3 is also correct.

Fragment 4 is correct. It will only be displayed by a user with the same rights. This is because, during
a request, the current user’s rights are dynamically swapped in the include link to the aclGroup
fragment of the aclGroup shared template skeleton.

Fragment 5 is correct.

Fragment 6 is incorrect since the prefix aclGroup key might be different for different users (as in
Fragment 1).

© Jahia Ltd, all rights reserved.


Page 30 of 37
JESI QuickStart

• Nested fragment tags are currently not supported.

<jesi:fragment cache="yes">

<jesi:fragment cache="yes">

</jesi:fragment>

</jesi:fragment>

• Jahia’s /cache/off, /cache/offonce and /cache/bypass URL parameters are supported by


the ESI server. This feature can be disabled in the tomcat\webapps\ROOT\WEB-
INF\config\data.xml file.

• The maxRemovalDelay attribute is currently ignored.

• We intend to add fine grained control of the behaviours to adopt for any errors that
may occur during fragment generation. For example, choose between displaying a
default error message in place of an inaccessible fragment, using the stale yet already
cached version of a fragment or displaying custom fallback content.

• We intend to add the jesi:include tag to be used in replacement of the jsp:include tag.
This will allow absolute fragments to be shared between pages and not just users of
the same page.

15) Key Generation Overview

In order to get a better grasp of template and fragment sharing, a schematic overview of the key
generation process is given here. These keys are used as entry points into hashmaps on the ESI server
to store fragments and templates.

The following simplified example is for illustrative purposes, the exact inner workings of Jahia’s ESI
might be slightly different (see source code for details).

• Template/Skeleton

So given the following JSP:

<jesi:template>
Header
<jesi:fragment >
Frag1 content
</jesi:fragment>

© Jahia Ltd, all rights reserved.


Page 31 of 37
JESI QuickStart

Footer
</jesi:template>

For a request to http://myEsiServer:8081/jahia/Jahia/pid/1 by user John and if the page isn’t yet
cached, the ESI server must first fetch the skeleton (i.e. esi template) for the page to determine which
fragments are required. Jahia will roughly generate the following html for this skeleton request from
the ESI server:

<html>
Header
<esi:fragment src="http://myJahiaServer:8080/jahia/Jahia/pid/1?__esi_fragment=1&user=John">
Footer
</html>

The skeleton is stored in the ESI server’s cache at hashmap key:

method=GET_user=John_Url=http://myEsiServer:8081/jahia/Jahia/pid/1

where method is the HTTP method utilized to fetch the page, user is the JahiaUser who requested the
page and Url is the request URL.

Notice that the skeleton is stored on a per-user basis, this is because the <jesi:template> tag by default
caches skeletons (i.e. esi templates) on a per user basis. See later for an example of aclGroup
templates.

• user Fragment

The ESI server then parses the HTML, detects any fragment links and, in this case, will fetch
fragment 1. __esi_fragment=1&user=John identifies fragment one which is specific to user John.

Jahia returns the content of fragment 1 to the ESI server for the request
http://myJahiaServer:8080/jahia/Jahia/pid/1?__esi_fragment=1&user=John, in this case the string
“Frag1 content”. The hashmap key for this fragment is then:

method=GET_Url=http://myJahiaServer:8080/jahia/Jahia/pid/1?__esi_fragment=1&user=
John

• group Fragment

If Fragment 1 had been declared as below in the JSP template:

<jesi:fragment group="salesProjections">
Frag1 content
</jesi:fragment>

Its resulting include link in the skeleton would look like this :

© Jahia Ltd, all rights reserved.


Page 32 of 37
JESI QuickStart

<esi:fragment src="http://myJahiaServer:8080/jahia/Jahia/pid/1?__esi_fragment=1&group=salesProjections">

and its ESI server hashmap key would be:

method=GET_Url=http://myJahiaServer:8080/jahia/Jahia/pid/1?__esi_fragment=1&group
=salesProjections

• aclGroup Fragment

If Fragment 1 had been declared as below in the JSP template:

<jesi:fragment aclGroup="true">
Frag1 content
</jesi:fragment>

If John was member of group1 and group2, it’s resulting include link in the skeleton would look like
this :

<esi:fragment
src="http://myJahiaServer:8080/jahia/Jahia/pid/1?__esi_fragment=1&aclGroup=group1_group2">

and its ESI server hashmap key would be:

method=GET_Url=http://myJahiaServer:8080/jahia/Jahia/pid/1?__esi_fragment=1&aclGr
oup=group1_group2

Additionally, if Fragment 1 had been declared as below in the JSP template:

<jesi:fragment aclGroup="myMarker">
Frag1 content
</jesi:fragment>

Its resulting include link in the skeleton would look like this :

<esi:fragment
src="http://myJahiaServer:8080/jahia/Jahia/pid/1?__esi_fragment=1&aclGroup=myMarker_group1_group2">

and its ESI server hashmap key would be:

method=GET_Url=http://myJahiaServer:8080/jahia/Jahia/pid/1?__esi_fragment=1&aclGr
oup=myMarker_group1_group2

Finally, expanding on the example above, if user John had specific rights over any content displayed
inside fragment 1, then the system would’ve automatically reverted to a non-shared user-specific
version of the fragment, such that the resulting include link in the skeleton would look like this :

© Jahia Ltd, all rights reserved.


Page 33 of 37
JESI QuickStart

<esi:fragment
src="http://myJahiaServer:8080/jahia/Jahia/pid/1?__esi_fragment=1&aclGroup=myMarker_John">

and its ESI server hashmap key would be:

method=GET_Url=http://myJahiaServer:8080/jahia/Jahia/pid/1?__esi_fragment=1&aclGr
oup=myMarker_John

• absolute Fragment

If Fragment 1 had been declared as below in the JSP template:

<jesi:fragment aclGroup="myMarker" absolute="true">


Frag1 content
</jesi:fragment>

It’s resulting include link in the skeleton would look like this :

<esi:fragment
src="http://myJahiaServer:8080/jahia/Jahia/pid/1?__esi_fragment=1&aclGroup=myMarker_group1_group2">

and its ESI server hashmap key would be:

method=GET_Url=http://myJahiaServer:8080/jahia/Jahia/pid/ABSOLUTE_MARKER?__esi_fr
agment=ABSOLUTE_MARKER&aclGroup=myMarker_group1_group2

Notice how the pid and frag number are removed. This is because if this fragment is shared across
multiple pages, we want its hashmap key to be independent of these.

• aclGroup Template/Skeleton

If the JSP template is declared as such:

<jesi:template aclGroup="myMarker" >


Header
<jesi:fragment >
Frag1 content
</jesi:fragment>
Footer
</jesi:template>

For the user John, the skeleton is stored in the ESI server’s cache at hashmap key:

method=GET_aclGroup=group1_group2_Url=http://myEsiServer:8081/jahia/Jahia/pid/1

This means that it can be shared by any user with the same rights. The resulting include links to
fragments are consequently more complex, but the overall mechanism remains the same.
© Jahia Ltd, all rights reserved.
Page 34 of 37
JESI QuickStart

16) JESI TLD

For reference, here is the current listing of the JESI TLD declaration file available in
\tomcat\webapps\jahia\WEB-INF\tld\jesi-tags.tld :

<?xml version = '1.0' encoding = 'ISO-8859-1'?>


<!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
"http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
<taglib>

<tlib-version>1.0</tlib-version>
<jsp-version>1.2</jsp-version>
<short-name>jesi</short-name>

<description>Java Edge Side Include (JESI) tags</description>

<tag>
<name>fragment</name>
<tag-class>org.jahia.taglibs.esi.JesiFragmentTag</tag-class>
<body-content>JSP</body-content>
<description>Creates a separate cacheable object from a page fragment.</description>

<attribute>
<name>control</name>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>cache</name>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>expiration</name>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>maxRemovalDelay</name>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>user</name>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>group</name>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<!-- generates one fragment for all users in same groups, so anything between this
fragment cannot reference
user properties or any external databases as they will be ignored -->
<name>aclGroup</name>
<rtexprvalue>true</rtexprvalue>
</attribute>
<name>absolute</name>

© Jahia Ltd, all rights reserved.


Page 35 of 37
JESI QuickStart

<rtexprvalue>true</rtexprvalue>
</attribute>
<name>alwaysInvalidate</name>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
<tag>
<name>codeblock</name>
<tag-class>org.jahia.taglibs.esi.JesiCodeblockTag</tag-class>
<body-content>JSP</body-content>
<description>Allows conditional execution of its body in template or fragment
request</description>
<attribute>
<name>execute</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
<tag>
<name>template</name>
<tag-class>org.jahia.taglibs.esi.JesiTemplateTag</tag-class>
<body-content>JSP</body-content>
<description>Controls ESI caching characteristics of non-fragment content of the
page.</description>
<attribute>
<name>control</name>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>cache</name>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>expiration</name>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>maxRemovalDelay</name>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>user</name>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>group</name>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
<tag>
<name>control</name>
<tag-class>org.jahia.taglibs.esi.JesiControlTag</tag-class>
<body-content>EMPTY</body-content>
<description>Controls ESI caching characteristics of the page.</description>
<attribute>
<name>control</name>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>cache</name>

© Jahia Ltd, all rights reserved.


Page 36 of 37
JESI QuickStart

<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>expiration</name>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>maxRemovalDelay</name>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
</taglib>

jesi-tags.tld

© Jahia Ltd, all rights reserved.


Page 37 of 37

También podría gustarte