<?xml version="1.0"?>
<!--
  Licensed to the Apache Software Foundation (ASF) under one or more
  contributor license agreements.  See the NOTICE file distributed with
  this work for additional information regarding copyright ownership.
  The ASF licenses this file to You under the Apache License, Version 2.0
  (the "License"); you may not use this file except in compliance with
  the License.  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
-->

<!--
    XSP event-based cache sample.

    Cvs $Id: eventcache.xsp 433543 2006-08-22 06:22:54Z crossley $
 -->


<xsp:page language="java"
          xmlns:xsp="http://apache.org/xsp"
          xmlns:esql="http://apache.org/cocoon/SQL/v2"
          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.excalibur.source.impl.validity.AggregatedValidity</xsp:include>
    <xsp:include>org.apache.excalibur.source.impl.validity.TimeStampValidity</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;
    final String DATABASE_TABLE = "user";

    /**
    * 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()
    {
       // this page will only render a single view
       // depending on the database table. Therefore
       // there is no need to distinguish different
       // outcomes in the cache. If we were paging
       // through the result set, those parameters
       // should be used for the key.
       return "";
    }

    /**
    * 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 = DATABASE_TABLE;
	   // a composite validity is required here since changes to
	   // the source XSP file should invalid the cache as well as
       // changes to the database table.
	   AggregatedValidity validity = new AggregatedValidity();
       // invalidate on external events
       // multiple events can be added, the cache will be invalidated
       // when any of those events occur.
       validity.add(new EventValidity(new NamedEvent(key)));
       // invalidate on changes to XSP source
	   validity.add(new TimeStampValidity(this.dateCreated));
	   return validity;
    }
 </xsp:logic>


  <page>
    <title>Demonstrating Event-Aware Caching or Database Generated Pages.</title>
    <content>
    	<para>
	    	This xsp page is based on (copied from) the event aware cacheable
            xsp sample.
    	</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 a specific database table name: <b><xsp:expr>DATABASE_TABLE</xsp:expr></b>.
            Other parameters ie. request parameters do not matter.
        </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. I will also
            be invalidated when the XSP source is modified.
			<br/>
			My cache entry will be invalidated (actually, removed) when an event named
			<i><xsp:expr>DATABASE_TABLE</xsp:expr></i> occurs. Go to the
            <a href="../../databases/mod-db/user-list">database samples</a> and modify,
            insert, or delete a user and check if this page is updated.
		</para>

        <para>Test links:
            <ul>
                <li><a href="invalidate?table=user">uncache with action</a></li>
                <li><a href="jms-invalidate?table=user">uncache with action emitting JMS messages</a><br/>
                    This is particularily useful if your DBMS of choice can easily do HTTP
                    requests but hooking on JMS would be difficult. Still you would like to
                    control several Cocoon caches through JMS.
                </li>
                <li><a href="install?what=http">install HTTP database triggers with HSQLDB</a><br/>
                    For the HTTP example triggers, this sample needs to be available at
                    <b>http://localhost:8888/samples/jms/database/eventcache</b> because
                    that location is hard-coded into the trigger. This is usually the case if you
                    have started the provided <i>cocoon.sh</i> resp. <i>cocoon.bat</i>.
                </li>
                <li><a href="install?what=jms">install JMS database triggers with HSQLDB</a><br/>
                    For the JMS example triggers, you need to have setup a JMS system, e.g.
                    <a href="http://openjms.sf.net">OpenJMS</a></li>
                <li><a href="remove">uninstall database triggers</a></li>
            </ul>
        </para>

        <para>
          <esql:connection>
            <esql:pool>personnel</esql:pool>
              <esql:execute-query>
                <esql:query>select * from user order by name, firstname, uname, uid</esql:query>
                <esql:results>
                  <table>
                    <tbody>
                      <esql:row-results>
                        <tr>
                          <td><esql:get-string column="uname"/></td>
                          <td><esql:get-string column="firstname"/></td>
                          <td><esql:get-string column="name"/></td>
                          <td><esql:get-string column="uid"/></td>
                        </tr>
                      </esql:row-results>
                    </tbody>
                  </table>
               </esql:results>
            </esql:execute-query>
          </esql:connection>
        </para>

        <para>
          Please refer to the <a href="../../eventcache/">event based cache example</a> for more details
          on the event based cache invalidation.
        </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>
