Sign in

E-mail *, (xx@domain.com)
Password *

Register | Forgot password

Recent blogs

RSS - Blogs
March 9, 2010
State of OSGi in the Java world
March 4, 2010
Reach more people with Google Translate
March 3, 2010
Get My Advice
February 26, 2010
What? Where!?!
February 11, 2010
Split it!

All Blogs...


Server side represent!

February 4, 2009

In a previous blog I mentioned the technique of server side includes (SSIs). I promised to get back on that subject, well here we go!

If you create presentation WCBs, you will encounter caching.  In general, this does not present any problems. However, when you want to display information that refreshes faster than the page itself is edited, regular caching will not work.

Let's say you want to build a pagepart that displays an indication of the time of day - like "Thursday morning, January 29th 2009". Let's assume the page is edited once per week. When the page is saved, its timestamp will be set and the cache will refresh. So if we don't take special precautions, the page will display "Thursday morning, January 29th, 2009" all week until the next edit. Argh!

Server side include to the rescue!


Server side include? What gives?

Way, way back in the days, when dinosaurs walked the earth and used NCSA Mosaic to browse the Web (technically a bit later, but I couldn't resist mentioning NCSA Mosaic ;-)), the httpd server offered an option to put a special fragment in your HTML to execute CGI scripts inline. For example:


<html>
  <head>
    <title>test</title>
  </head>
  <body>
    Today is
    <!--#include virtual="/cgi-bin/showdate.pl" -->
  </body>
</html>

This fragment was named "server side include" because it prompts the server to include the output of a command on the side of the server (i.e. before sending a reponse to the browser). This option still exists today in the Apache HTTP Server even though scripting languages like JSP, ASP and PHP provide much more flexibility.


To provide more flexible ways of caching, GX WebManager builds on the same idea using server side include tags to include bits of separately generated content.


SSI in detail

To make this more insightful, let us take a closer look at a server side include in action. For now, just assume that we have prepared our page part properly. We will examine the code to generate the server side include later. As you may recall, the page will be generated and cached.


The HTML of the generated page will look something like below:

<html>
  <head>
    <title>test</title>
  </head>
  <body>
    <!--#include virtual="/web/show/some/include/url" -->
    ...
  </body>
</html>

This page HTML is then cached.

Before sending out the page, GX WebManager scans the source for server side includes. When the source contains an SSI tag, the URL is requested as if it was a normal request (meaning: it might be cached). The SSI tag is then replaced by the result of the request.


Let us examine how that works in our example. GX WebManager scans the source and encounters the SSI-tag. It requests the URL "/web/show/some/include/url", which results in HTML being generated something like this:


<div>
  Thursday morning, January 29th, 2009
</div>

And indeed, this result is also cached and also scanned for possible SSI-tags.

The result is then used to replace the SSI-tag in the generated page:


<html>
  <head>
    <title>test</title>
  </head>
  <body>
    <div>
      Thursday morning, January 29th, 2009
    </div>
    ...
  </body>
</html>

And this is the final page as it is sent as response to the browser.

So where's the gain?

Interesting to see the page being chopped into different bits, but what do we gain from doing it?
The most important effect of using the SSI is that there now are two URLs being cached:

  • the URL for the page
  • the SSI URL

The results for these URLs are being cached independently! In our example, this means that the page can be refreshed every week, while the SSI can be refreshed every hour. So the bigger part of the page is being cached for a long time, while a tiny part of it is cached for a much shorter time. Isn't it wonderful? :-D

You will find that many of the elements in the standard design already use SSIs. This makes sense; a media repository element needs to refresh when a new article is published in the media repository, not merely when the editor saves the page it is placed on.

Creating your own SSI

Okay, so SSIs are nothing short of brilliant. Now that we have established that, let's see how we can go about creating our own SSI. We will make the pagepart multifunctional; it will either display the SSI tag (when the page is requested) or its normal content (when requested with the SSI URL). To do this, we will split up the JSP files as follows:

  • "helloworldDatepart.xml": descriptor file
  • "helloworldDatepart.jspf": to display the normal content
  • "helloworldDatepartSsi.jspf": to construct the SSI tag

We have to somehow coerce the pagepart to do the right thing at the right moment. This can be achieved by adding the ssi-tag to the XML in the descriptor file for our pagepart ("helloworldDatepart.xml"):


<!-- helloworldDatepart.xml -->
 
<presentation>
  <name>helloworld datepart</name>
  <display-name>Helloworld datepart</display-name>
  <scope>PagePart</scope>
  <ssi>
    <presentation>helloworldDatepartSsi</presentation>
  </ssi>
</presentation>

The ssi-tag in this descriptor file tells WebManager to use the file "helloworldDatepartSsi.jspf" to construct an SSI and to use the file "helloworldDatepart.jspf" to construct the normal content.

So what does the "helloworldDatepartSsi.jspf" file look like?

<%-- helloworldDatepartSsi.jspf --%>
 
<%@ page language="java" session="false" buffer="none" %>
<%@ taglib uri="http://www.gx.nl/taglib/wm" prefix="wm" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
 
<wm:link cto="900" passOn="cto"
  ssiObjectId="${presentationcontext.pagePart.id}"
  ssiObjectClassName="nl.gx.webmanager.cms.layout.PagePart" />

As you can see, we use the "wm:link" tag to construct a link to the pagepart. An attribute "cto" is provided and the "passOn" attribute indicates we want the value of this "cto" attribute to be passed on in the link. The name "cto" is short for an automatic "cache timeout" and "900" is the duration in seconds that a URL will be considered valid. So the cached page part content will be valid for 15 minutes and after that it will be refreshed.

Note: The Caching document briefly touches on the subject of how caching reacts to URLs. To learn the gritty details you are better off scouring the source of the standard presentation for "*Ssi.jspf" files with working examples.

All that misses now is the normal content of our pagepart:

<%@ page language="java" session="false" buffer="none" %>
<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
 
<c:set var="pagePart" value="${presentationcontext.pagePart}" />
<c:set var="blocks" value="${pagePart.blocks}" />
<c:set var="now" value="<%=new java.util.Date()%>" />
 
<fmt:setLocale value="en_US" />
<fmt:formatDate var="dayStr" pattern="EEEE" value="${now}" />
<fmt:formatDate var="monthStr" pattern="MMMM" value="${now}" />
<fmt:formatDate var="monthDayStr" pattern="d" value="${now}" />
<fmt:formatDate var="yearStr" pattern="yyyy" value="${now}" />
<fmt:formatDate var="hourStr" pattern="H" value="${now}" />
 
<c:choose>
  <c:when test="${hourStr < 6}">
    <c:set var="daypartStr" value="night" />
  </c:when>
  <c:when test="${hourStr >= 6 && hourStr < 12}">
    <c:set var="daypartStr" value="morning" />
  </c:when>
  <c:when test="${hourStr >= 12 && hourStr < 18}">
    <c:set var="daypartStr" value="afternoon" />
  </c:when>
  <c:when test="${hourStr >= 18}">
    <c:set var="daypartStr" value="evening" />
  </c:when>
</c:choose>
 
<c:choose>
  <c:when test="${monthDayStr == 1 || monthDayStr == 21 || monthDayStr == 31}">
    <c:set var="monthDayStr" value="${monthDayStr}st" />
  </c:when>
  <c:when test="${monthDayStr == 2 || monthDayStr == 22}">
    <c:set var="monthDayStr" value="${monthDayStr}nd" />
  </c:when>
  <c:when test="${monthDayStr == 3 || monthDayStr == 23}">
    <c:set var="monthDayStr" value="${monthDayStr}rd" />
  </c:when>
  <c:otherwise>
    <c:set var="monthDayStr" value="${monthDayStr}th" />
  </c:otherwise>
</c:choose>
 
${dayStr} ${daypartStr}, ${monthStr} ${monthDayStr}, ${yearStr}

And there you have it! Now all you need is one line to include this pagepart in your "page.jsp":

<wm:pagePart label="helloworld datepart" />

Ready!

When you examine your page with SSIdebug, you will notice a server side include with a lengthy URL in the spot where you put your pagepart:


<!--#include
virtual="/web/show?id=26111&langid=42&cto=900&elementHolder=70972&ssiObjectClassName=nl.gx.webmanager.cms.layout.PagePart&ssiObjectId=76231" -->

You can request this URL and see that it outputs the right thing:

http://localhost:8080/web/show?id=26111&langid=42&cto=900&elementHolder=70972&ssiObjectClassName=nl.gx.webmanager.cms.layout.PagePart&ssiObjectId=76231

Tips and tricks


Don't use too many SSIs!

Although using a server side include has clear advantages, there also is a down side. Every extra request causes overhead. So if the request for one page results in 50 other requests you are probably causing more problems than you're solving.

Simplify SSIs; less is more!

Every unique URL will be cached. Take this into account when constructing your SSI link. Do not pass arguments that are not needed. Try and simplify the information in the link as much as possible. For example, if our SSI above would contain an extra "pageid=xxx" it would lead to a new URL for each and every page. However, our pagepart has exactly the same outcome for all pages! It is better to have that one request in the cache instead of separate requests for every page.


Examine SSIs

You can expose the SSIs on a page with SSIdebug. All SSIs on the page will be visible on the page. You can also take a look at the Administrator Status Tool to see which URLs are being requested. SSIs are regular requests, so you can see them flash by.


Can't request SSI

Did you log in as tomcat administrator? Are you requesting the URL on the backend server? If the URL does not contain "&frontendrequest=true", try adding it.


Static pages

SSIs won't work for dumped pages - unless you configure Apache recognize them. Typically you dump the pages to ".shtml" and have the system administrator configure the Apache server with these options:


Options +Includes
 
AddType text/html .shtml
AddOutputFilter INCLUDES .shtml 

As you can see there is a lot to know about server side includes. I hope this posting will help you on your way!

To sign off, some tales from the hard side:


Till next time,


Patrick



About the Author

Return to all blogs

 

Patrick Atoon

Patrick Atoon has gained nuff respect as one of the most experienced web architects in the GX Webmanager community or even the global hip hop community for that matter.

Read all Patricks blog entries

Other blog entries:

February 26, 2010
What? Where!?!
September 3, 2009
Do the Right Thing
June 18, 2009
wm:link secrets
March 2, 2009
Server side represent! (Part 2)
January 15, 2009
Making cache
December 9, 2008
Like A Version
August 19, 2008
Stop making sense
August 4, 2008
Namaste!
July 7, 2008
Japanese encore (日本のアンコール)
May 20, 2008
All amped up


Share:

del.icio.us
digg
Technorati
Slashdot
Reddit
YahooMyWeb
NewsVine
ekudos
© 2010 GX creative online development B.V.

Disclaimer

This website (GXdeveloperweb.com) may discuss or contain opinions, (sample) coding, software or other information that does not include GX official interfaces, instructions or guidelines and therefore is not supported by GX. Changes made based on this information are not supported.  GX will not be held liable for any damages caused by using or misusing the information, software, instructions, code or methods suggested on this website, and anyone using these methods does so at his/her own risk. GX offers no guarantees and assumes no responsibility or liability of any type with respect to the content of this website, including any liability resulting from incompatibility between the content of this website and the materials and services offered by GX. By using this website you will not hold, or seek to hold, GX responsible or liable with respect to the content of this website.