| <?xml version="1.0" encoding="ISO-8859-1"?> |
| |
| <!--+ |
| | XSP event-based cache sample. |
| | |
| | CVS $Id: eventcache.xsp,v 1.4 2004/02/17 00:15:21 joerg Exp $ |
| +--> |
| |
| <xsp:page language="java" |
| xmlns:xsp="http://apache.org/xsp" |
| xmlns:xsp-request="http://apache.org/xsp/request/2.0"> |
| |
| <xsp:structure> |
| <xsp:include>org.apache.excalibur.source.SourceValidity</xsp:include> |
| <xsp:include>org.apache.cocoon.caching.validity.EventValidity</xsp:include> |
| <xsp:include>org.apache.cocoon.caching.validity.NamedEvent</xsp:include> |
| <xsp:include>java.io.Serializable</xsp:include> |
| </xsp:structure> |
| |
| <xsp:logic> |
| // artificial slowdown to make the effects of the cache visible |
| final int DELAY_SECS = 2; |
| |
| /** |
| * Generate the unique key for the cache. |
| * |
| * This key must be unique inside the space of this XSP page, it is used |
| * to find the page contents in the cache (if getValidity says that the |
| * contents are still valid). |
| * |
| * This method will be invoked before the getValidity() method. |
| * |
| * @return The generated key or null if the component |
| * is currently not cacheable. |
| */ |
| public Serializable getKey() |
| { |
| // for our test, pages having the same value of "pageKey" will share |
| // the same cache location |
| String key = request.getParameter("pageKey") ; |
| return ((key==null||"".equals(key)) ? "one" : key); |
| } |
| |
| /** |
| * Generate the validity object, tells the cache how long to |
| * keep contents having this key around. In this case, it will |
| * be until an Event is retrieved matching the NamedEvent created below. |
| * |
| * Before this method can be invoked the getKey() method |
| * will be invoked. |
| * |
| * @return The generated validity object or null if the |
| * component is currently not cacheable. |
| */ |
| public SourceValidity getValidity() { |
| String key = request.getParameter("pageKey") ; |
| return new EventValidity( |
| new NamedEvent( |
| (key==null||"".equals(key)) ? "one" : key)); |
| } |
| </xsp:logic> |
| |
| |
| <page> |
| <title>Demonstrating Event-Aware Caching</title> |
| <content> |
| <para> |
| This xsp page is based on (copied from) the cacheable xsp sample |
| but there are some important differences. If you don't already |
| understand at least the basics of caching in Cocoon, you should |
| probably start there, not here. Read the text below, and the |
| sitemap and source for more details. |
| </para> |
| <para> |
| I pause for <xsp:expr>DELAY_SECS</xsp:expr> seconds during generation, so |
| that you can tell if I'm being served from the cache or not. |
| <br/> |
| What you see here was generated on <b><xsp:expr>new java.util.Date()</xsp:expr></b>. |
| </para> |
| |
| <para> |
| I'm cached for each unique value of request parameter 'pageKey'. Other |
| parameters do not matter. |
| <br/> |
| Here the value is: |
| <b><xsp-request:get-parameter name="pageKey"/></b>. |
| <br/> |
| If this is not the same as the 'pageKey' parameter in the page URL, we have a problem. |
| </para> |
| |
| <para> |
| Unlike other cacheable pages in Cocoon, I can be un-cached by events external |
| to Cocoon - for instance, when a database table or row is updated. |
| <br/> |
| My cache entry will be invalidated (actually, removed) when an event named |
| <i><xsp-request:get-parameter name="pageKey"/></i> occurs. This can be manually |
| simulated by clicking one of the "uncache" links below. |
| </para> |
| <para>Test links: |
| <ul> |
| <li><a href="?pageKey=one">pageKey=one</a> |
| (<a href="action?pageKey=one&event=one">uncache with action</a>) |
| (<a href="flow?pageKey=one&event=one">uncache with flow</a>)</li> |
| <li><a href="?pageKey=two">pageKey=two</a> |
| (<a href="action?pageKey=two&event=two">uncache with action</a>) |
| (<a href="flow?pageKey=two&event=two">uncache with flow</a>)</li> |
| </ul> |
| Note: the random numbers you see included in the url after an uncache link |
| serve two purposes in the example, making it easier to see the effect of the |
| cache invalidation. They prevent browser caching and they demonstrate that |
| only our designated key matters in the retrieval from cache. |
| </para> |
| <para> |
| This event based cache system consists essentially of three parts: |
| <ul> |
| <li>A new type of SourceValidity, EventValidity, which contains information |
| on the Event which will invalidate this cached content. Until this event is |
| received, EventValidities will usually always return valid, though they don't |
| have to.</li> |
| <li>An extension to Cocoon's Cache implementation. Cocoon's Cache is really just |
| a thin wrapper around Avalon-Excalibur's Store project. The EventAwareCacheImpl |
| does two things. It examines each pipeline on its way into the cache to |
| determine if any of its SourceValidities are instances of EventValidity. If so, |
| it notifies an event registry as described next. The second critical function of |
| the EventAware cache implementation is that it allows other components to |
| contact it and notify it of an Event. The Cache then looks up the keys |
| mapped to that event in the event registry and cleans out the cache and |
| registry accordingly. <i>See the sitemap of this sample for an example of |
| configuring a pipeline to use this implementation.</i></li> |
| <li>The EventRegistry is responsible for mapping Events to cache keys, and |
| providing information about that mapping to systems that need it, usually just |
| the EventAwareCache. Another crucial responsibility of the EventRegistry is to |
| persist its data across container shutdown and startup. The default implementation |
| does by serializing an object to disk (currently in WEB-INF). If recovering this |
| fails, the EventAwareCache is notified, and it is expected to ensure there are no |
| orphaned EventValidities (currently by clearing the entire cache). |
| </li> |
| </ul> |
| Note that though this example uses xsp with actions or flow, any pipeline component can be |
| made to use EventValidity, and any code with access to the ComponentManager can |
| translate real-world events to Events and notify the Cache of them. |
| </para> |
| <xsp:logic> |
| // slowdown page generation. |
| try { |
| Thread.sleep(DELAY_SECS * 1000L); |
| } catch (InterruptedException ie) { |
| // Not much that can be done... |
| } |
| </xsp:logic> |
| </content> |
| </page> |
| </xsp:page> |