Anonymous avatar Anonymous committed 397aca8

- Moved website documentation to the OSCache project (where it belongs!)
- Updated build.xml to bring it more in line with the other OpenSymphony projects

Comments (0)

Files changed (17)

 <!-- OSCache build file - http://www.opensymphony.com/oscache -->
 <project name="oscache" default="jar" basedir=".">
 
-  <property file="build.properties" />
-  <!-- Initialise all the variables as required -->
-  <target name="init">
-    <!-- Uncomment if you want to use Jikes -->
-    <!-- property name="build.compiler" value="jikes" / -->
+    <property file="build.properties"/>
 
-    <!-- project properties -->
-    <property name="name" value="oscache"/>
-    <property name="Name" value="OSCache"/>
-    <property name="version" value="2.0"/>
-    <property name="zip_version" value="2_0"/>
+    <!-- Initialise all the variables as required -->
+    <target name="init">
 
-    <!-- directory properties -->
-    <property name="build.dir" value="build"/>
-    <property name="build.test.dir" value="build.test"/>
-    <property name="dist.dir" value="dist"/>
+        <!-- project properties -->
+        <property name="name" value="oscache"/>
+        <property name="Name" value="OSCache"/>
 
-    <property name="src.dir" value="src"/>
-    <property name="src.core" value="${src.dir}/core"/>
-    <property name="src.plugins" value="${src.dir}/plugins"/>
-    <property name="src.webapp" value="${src.dir}/webapp"/>
+        <tstamp>
+            <format property="release" pattern="-dMMMyy" locale="en" timezone="GMT"/>
+        </tstamp>
 
-    <property name="doc.dir" value="doc"/>
-    <property name="lib.dir" value="lib"/>
-    <property name="tmp.dir" value="tmp"/>
+        <!-- directory properties -->
+        <property name="build.dir" value="build"/>
+        <property name="build.test.dir" value="build.test"/>
+        <property name="dist.dir" value="dist"/>
 
-    <property name="debug" value="true"/>
+        <property name="src.dir" value="src"/>
+        <property name="src.core" value="${src.dir}/core"/>
+        <property name="src.plugins" value="${src.dir}/plugins"/>
+        <property name="src.webapp" value="${src.dir}/webapp"/>
 
-    <!-- document properties -->
-    <property name="packages" value="com.opensymphony.oscache.*"/>
-    <!-- test properties -->
-    <property name="test.web.baseURL" value="http://localhost:8080/oscache/"/>
-    <!-- This property must match with what is included in the oscache.properties files -->
-    <property name="test.cache.path" value="/tmp/cachetagscache"/>
+        <property name="doc.dir" value="docs"/>
+        <property name="lib.dir" value="lib"/>
+        <property name="tmp.dir" value="tmp"/>
 
-    <available property="junit.available" classname="junit.framework.TestCase"/>
-    <available property="clover.available" classname="org.apache.tools.ant.taskdefs.CloverCompilerAdapter"/>
-  </target>
+        <property name="debug" value="true"/>
 
+        <!-- document properties -->
+        <property name="packages" value="com.opensymphony.oscache.*"/>
 
-  <!-- Classpath -->
-  <path id="cp">
-    <fileset dir="lib">
-      <include name="build/*.jar"/>
-      <include name="core/*.jar"/>
-    </fileset>
-  </path>
+        <!-- This property must match with what is included in the oscache.properties files -->
+        <property name="test.cache.path" value="/tmp/cachetagscache"/>
 
-  <!-- Plugins Classpath -->
-  <path id="plugins.cp">
-    <path refid="cp"/>
-    <fileset dir="lib">
-      <include name="plugins/**/*.jar"/>
-    </fileset>
-  </path>
+        <property name="clover.initstring" location="${build.test.dir}/testcoverage.db"/>
 
-  <path id="jalopy.classpath">
-    <fileset dir="lib/build/jalopy">
-      <include name="*.jar"/>
-    </fileset>
-  </path>
+        <available property="junit.available" classname="junit.framework.TestCase"/>
+        <available property="clover.available" classname="org.apache.tools.ant.taskdefs.CloverCompilerAdapter"/>
+    </target>
 
-  <taskdef name="jalopy" classname="de.hunsicker.jalopy.plugin.ant.AntPlugin">
-    <classpath refid="jalopy.classpath"/>
-  </taskdef>
 
-  <target name="junit-check" depends="init" unless="junit.available">
-    <fail message="Cannot run test cases. Please copy lib/build/junit-3.8.1.jar to ${ant.home}/lib"/>
-  </target>
+    <!-- Classpath -->
+    <path id="cp">
+        <fileset dir="lib">
+            <include name="build/*.jar"/>
+            <include name="core/*.jar"/>
+        </fileset>
+    </path>
 
-<target name="clover-check" depends="init" unless="clover.available">
-    <fail message="Cannot run coverage tests. Please copy lib/build/clover-1.2.3.jar to ${ant.home}/lib"/>
-  </target>
+    <!-- Plugins Classpath -->
+    <path id="plugins.cp">
+        <path refid="cp"/>
+        <fileset dir="lib">
+            <include name="plugins/**/*.jar"/>
+        </fileset>
+    </path>
 
-  <target name="web-check" depends="init">
-    <tempfile property="temp.file" destdir="${build.dir}" prefix="warcheck"/>
-    <get src="${test.web.baseURL}/index.html" dest="${temp.file}" />
-  </target>
+    <path id="jalopy.classpath">
+        <fileset dir="lib/build/jalopy">
+            <include name="*.jar"/>
+        </fileset>
+    </path>
 
-  <!-- Prepares the build directory -->
-  <target name="prepare" depends="init">
-    <mkdir dir="${build.dir}/META-INF"/>
-    <copy file="${src.core}/etc/${name}.tld" tofile="${build.dir}/META-INF/taglib.tld"/>
-  </target>
-
-
-  <!-- Compiles the core source code -->
-  <target name="compile" depends="prepare">
-    <javac srcdir="${src.core}/java" destdir="${build.dir}" includes="com/opensymphony/oscache/**" debug="${debug}" classpathref="cp"/>
-  </target>
-
-  <target name="plugins-compile" depends="compile">
-    <javac srcdir="${src.plugins}/diskpersistence/java" destdir="${build.dir}" includes="com/opensymphony/oscache/**" debug="${debug}" classpathref="plugins.cp"/>
-
-    <javac srcdir="${src.plugins}/clustersupport/java" destdir="${build.dir}" includes="com/opensymphony/oscache/**" debug="${debug}" classpathref="plugins.cp"/>
-  </target>
-
-
-  <!-- Prepares and compiles the web application, which includes the web test suite -->
-  <target name="example-war" depends="jar">
-    <mkdir dir="${build.dir}/webapp"/>
-
-    <javac srcdir="${src.webapp}/WEB-INF/classes" destdir="${build.dir}/webapp" includes="com/opensymphony/oscache/**" debug="${debug}" classpath="${build.dir}" classpathref="cp"/>
-
-    <war destfile="${build.dir}/${name}-example.war" basedir="${src.webapp}" webxml="${src.webapp}/WEB-INF/web.xml" excludes="WEB-INF/web.xml">
-      <lib dir="${lib.dir}/core"/>
-      <lib dir="${lib.dir}/plugins/clustersupport"/>
-      <lib file="${dist.dir}/${name}.jar"/>
-      <classes dir="${build.dir}/webapp"/>
-    </war>
-  </target>
-
-
-  <!-- Build a usable jar file -->
-  <target name="jar" depends="format, compile, plugins-compile">
-    <mkdir dir="${dist.dir}"/>
-
-    <jar jarfile="${dist.dir}/${name}.jar" basedir="${build.dir}" includes="**" excludes="test/**, docs/**, *.war"/>
-  </target>
-
-
-  <!-- Cleans up generated stuff -->
-  <target name="clean" depends="init">
-    <delete dir="${build.dir}"/>
-    <delete dir="${build.test.dir}"/>
-    <delete dir="${dist.dir}"/>
-    <delete dir="${doc.dir}"/>
-  </target>
-
-  <target name="format" depends="init">
-    <jalopy fileformat="unix" convention="${src.dir}/core/etc/jalopy.xml" history="file" historymethod="adler32" loglevel="error" threads="2" classpathref="cp">
-      <fileset dir="${src.dir}">
-        <include name="**/*.java"/>
-      </fileset>
-    </jalopy>
-  </target>
-
-  <!-- Run the unit tests, used by test target,so do not call directly -->
-  <target name="run-tests">
-    <taskdef name="junit" classname="org.apache.tools.ant.taskdefs.optional.junit.JUnitTask"/>
-
-    <!-- Clear out any previous persistent cache directory -->
-    <delete dir="${test.cache.path}" failonerror="false"/>
-
-    <junit printsummary="yes" haltonfailure="yes" haltonerror="yes" fork="yes">
-      <classpath>
-        <pathelement location="${build.test.dir}"/>
-        <path refid="plugins.cp"/>
-      </classpath>
-
-      <formatter type="xml"/>
-
-      <batchtest todir="${build.dir}/docs/junit">
-        <fileset dir="${build.test.dir}">
-          <include name="**/TestComplete*.class"/>
-          <exclude name="**/web/*.*"/>
-        </fileset>
-      </batchtest>
-    </junit>
-  </target>
-
-  <target name="test-web" depends="junit-check,compile">
-    <mkdir dir="${build.dir}/docs/junit"/>
-    <mkdir dir="${build.test.dir}"/>
-
-    <!-- Clear out any previous persistent cache directory -->
-    <delete dir="${test.cache.path}"/>
-
-    <javac srcdir="${src.core}/test" destdir="${build.test.dir}" includes="com/opensymphony/oscache/web/**" debug="${debug}" classpath="${build.dir}" classpathref="cp"/>
-
-    <java classname="com.opensymphony.oscache.web.CheckDeployment" failonerror="true" classpath="${build.test.dir}" fork="yes">
-      <arg value="${test.web.baseURL}" />
-    </java>
-
-    <taskdef name="junit" classname="org.apache.tools.ant.taskdefs.optional.junit.JUnitTask"/>
-
-    <junit printsummary="yes" haltonfailure="yes" haltonerror="yes" fork="yes">
-      <sysproperty key="test.web.baseURL" value="${test.web.baseURL}"/>
-      <classpath>
-        <pathelement location="${build.test.dir}"/>
-        <pathelement location="${build.dir}"/>
-        <path refid="cp"/>
-      </classpath>
-
-      <formatter type="xml"/>
-      <formatter type="plain" useFile="false" />
-      <batchtest todir="${build.dir}/docs/junit">
-        <fileset dir="${build.test.dir}">
-          <include name="**/web/TestComplete*.class"/>
-          <include name="**/web/TestLoadComplete*.class"/>
-        </fileset>
-      </batchtest>
-    </junit>
-  </target>
-
-
-  <!-- Run JUnit tests using different combinations of disk and memory caching -->
-  <target name="test" depends="init, clover-check,junit-check">
-    <mkdir dir="${build.dir}/docs/junit"/>
-    <mkdir dir="${build.dir}/docs/clover"/>
-    <mkdir dir="${build.test.dir}"/>
-
-    <taskdef resource="clovertasks"/>
-    <clover-setup initString="${build.test.dir}/coverage.db"/>
-    <javac srcdir="${src.core}/java" destdir="${build.test.dir}"  debug="${debug}" classpathref="cp"/>
-    <javac srcdir="${src.core}/test" destdir="${build.test.dir}"  debug="${debug}" classpathref="cp"/>
-    <javac srcdir="${src.plugins}/clustersupport/java" destdir="${build.test.dir}"  debug="${debug}" classpathref="plugins.cp"/>
-    <javac srcdir="${src.plugins}/clustersupport/test" destdir="${build.test.dir}"  debug="${debug}" classpathref="plugins.cp"/>
-    <javac srcdir="${src.plugins}/diskpersistence/java" destdir="${build.test.dir}" debug="${debug}" classpathref="plugins.cp"/>
-    <javac srcdir="${src.plugins}/diskpersistence/test" destdir="${build.test.dir}" debug="${debug}" classpathref="plugins.cp"/>
-
-    <!-- Run all tests using Memory Cache Only -->
-    <copy file="${src.core}/test/oscacheMemoryOnly.properties" tofile="${build.test.dir}/oscache.properties" overwrite="yes"/>
-    <echo message="Running tests with memory cache only" level="info" />
-    <antcall target="run-tests"/>
-
-    <!-- Rerun all tests using Disk Cache Only -->
-    <copy file="${src.plugins}/diskpersistence/test/oscacheDiskOnly.properties" tofile="${build.test.dir}/oscache.properties" overwrite="yes"/>
-    <echo message="Running tests with disk cache only" level="info" />
-    <antcall target="run-tests"/>
-
-    <!-- ReRun all tests using Disk and Memory Cache -->
-    <copy file="${src.plugins}/diskpersistence/test/oscacheDiskAndMemory.properties" tofile="${build.test.dir}/oscache.properties" overwrite="yes"/>
-    <echo message="Running tests with disk and memory caches" level="info" />
-    <antcall target="run-tests"/>
-
-    <!-- ReRun all tests using Disk and Memory Cache + Clustering -->
-    <copy file="${src.plugins}/clustersupport/test/oscacheCluster.properties" tofile="${build.test.dir}/oscache.properties" overwrite="yes"/>
-    <echo message="Running tests with disk and memory caches with clustering" level="info" />
-    <antcall target="run-tests"/>
-
-    <delete dir="${test.cache.path}"/>
-  </target>
-
-
-  <!-- Generate JavaDoc -->
-  <target name="doc" depends="init">
-    <mkdir dir="${doc.dir}/api"/>
-    <javadoc sourcepath="${src.core}/java" destdir="${doc.dir}/api" packagenames="${packages}" classpathref="cp" author="true" version="true" windowTitle="${Name} ${version} API" doctitle="${Name}" footer="See &lt;a href=&quot;http://www.opensymphony.com/&quot;&gt;www.opensymphony.com&lt;/a&gt; for more information." use="true" verbose="false"/>
-  </target>
-
-
-  <!-- Create the distribution zip files -->
-  <target name="dist" depends="clean, jar, doc">
-    <mkdir dir="${tmp.dir}/doc"/>
-    <mkdir dir="${tmp.dir}/src"/>
-    <mkdir dir="${tmp.dir}/lib"/>
-    <mkdir dir="${tmp.dir}/web"/>
-
-    <copy todir="${tmp.dir}/doc">
-      <fileset dir="${doc.dir}" excludes="**/*~, **/*.swp"/>
-    </copy>
-    <copy todir="${tmp.dir}/src">
-      <fileset dir="${src.dir}" excludes="**/*~, **/*.swp"/>
-    </copy>
-    <copy todir="${tmp.dir}/lib">
-      <fileset dir="${lib.dir}" excludes="**/*~, **/*.swp"/>
-    </copy>
-    <copy todir="${tmp.dir}/web">
-      <fileset dir="${src.webapp}" excludes=",**/*.jar, **/*~, **/*.swp"/>
-    </copy>
-
-    <copy file="${dist.dir}/oscache.jar" tofile="${tmp.dir}/oscache.jar"/>
-    <copy file="${src.core}/etc/oscache.properties" tofile="${tmp.dir}/oscache.properties"/>
-    <copy file="${src.core}/etc/oscache.tld" tofile="${tmp.dir}/oscache.tld"/>
-    <copy file="build.xml" tofile="${tmp.dir}/build.xml"/>
-    <copy file="readme.txt" tofile="${tmp.dir}/readme.txt" failonerror="false"/>
-    <copy file="changes.txt" tofile="${tmp.dir}/changes.txt" failonerror="false"/>
-
-    <zip zipfile="${dist.dir}/${name}_${zip_version}_full.zip" basedir="${tmp.dir}" includes="**"/>
-
-    <delete dir="${tmp.dir}/src"/>
-    <delete dir="${tmp.dir}/lib/build"/>
-    <delete dir="${tmp.dir}/lib/plugins"/>
-    <zip zipfile="${dist.dir}/${name}_${zip_version}_binary.zip" basedir="${tmp.dir}" includes="**"/>
-
-    <delete dir="${tmp.dir}"/>
-  </target>
-
-  <target name="clover.report" depends="test">
-  <clover-report>
-      <current outfile="${build.dir}/docs/clover">
-         <fileset dir="${src.core}" excludes="**/Test*" />
-        <fileset dir="${src.plugins}" excludes="**/Test*" />
-        <format type="html"/>
-      </current>
-   </clover-report>
-  </target>
-
-  <target name="junit.report" depends="test">
-    <junitreport todir="${build.dir}/docs/junit">
-      <fileset dir="${build.dir}/docs/junit">
-        <include name="TEST-*.xml"/>
-      </fileset>
-      <report format="frames" todir="${build.dir}/docs/junit"/>
-    </junitreport>
-  </target>
-
-  <target name="reports" depends="junit.report,clover.report" />
-
-  <!-- Upload the distribution zip to SF -->
-  <target name="sfupload" depends="init">
-    <taskdef name="ftp" classname="org.apache.tools.ant.taskdefs.optional.net.FTP">
-      <classpath refid="cp"/>
+    <taskdef name="jalopy" classname="de.hunsicker.jalopy.plugin.ant.AntPlugin">
+        <classpath refid="jalopy.classpath"/>
     </taskdef>
 
-    <ftp server="upload.sourceforge.net" action="send" userid="anonymous" password="me@mydomain.com" binary="yes" verbose="yes" remotedir="incoming">
-      <fileset dir="${dist.dir}">
-        <include name="**/*.zip"/>
-      </fileset>
-    </ftp>
-  </target>
+    <target name="junit-check" depends="init" unless="junit.available">
+        <fail message="Cannot run test cases. Please copy lib/build/junit-3.8.1.jar to ${ant.home}/lib"/>
+    </target>
+
+    <target name="clover-check" depends="init" unless="clover.available">
+        <fail message="Cannot run coverage tests. Please copy lib/build/clover-1.2.3.jar to ${ant.home}/lib"/>
+    </target>
+
+    <!-- Prepares the build directory -->
+    <target name="prepare" depends="init">
+        <mkdir dir="${build.dir}/META-INF"/>
+        <copy file="${src.core}/etc/${name}.tld" tofile="${build.dir}/META-INF/taglib.tld"/>
+    </target>
+
+
+    <!-- Compiles the core source code -->
+    <target name="compile" depends="prepare">
+        <javac srcdir="${src.core}/java" destdir="${build.dir}" includes="com/opensymphony/oscache/**" debug="${debug}" classpathref="cp"/>
+    </target>
+
+    <target name="plugins-compile" depends="compile">
+        <javac srcdir="${src.plugins}/diskpersistence/java" destdir="${build.dir}" includes="com/opensymphony/oscache/**" debug="${debug}" classpathref="plugins.cp"/>
+
+        <javac srcdir="${src.plugins}/clustersupport/java" destdir="${build.dir}" includes="com/opensymphony/oscache/**" debug="${debug}" classpathref="plugins.cp"/>
+    </target>
+
+
+    <!-- Prepares and compiles the web application, which includes the web test suite -->
+    <target name="example-war" depends="jar">
+        <mkdir dir="${build.dir}/webapp"/>
+
+        <javac srcdir="${src.webapp}/WEB-INF/classes" destdir="${build.dir}/webapp" includes="com/opensymphony/oscache/**" debug="${debug}" classpath="${build.dir}" classpathref="cp"/>
+
+        <war destfile="${dist.dir}/${name}-example.war" basedir="${src.webapp}" webxml="${src.webapp}/WEB-INF/web.xml" excludes="WEB-INF/web.xml">
+            <lib dir="${lib.dir}/core"/>
+            <lib file="${dist.dir}/${name}.jar"/>
+            <classes dir="${build.dir}/webapp"/>
+        </war>
+    </target>
+
+
+    <!-- Build a usable jar file -->
+    <target name="jar" depends="format, compile, plugins-compile">
+        <mkdir dir="${dist.dir}"/>
+
+        <jar jarfile="${dist.dir}/${name}_${version}${release}.jar" basedir="${build.dir}" includes="**" excludes="test/**, docs/**, *.war"/>
+    </target>
+
+
+    <!-- Cleans up generated stuff -->
+    <target name="clean" depends="init">
+        <delete dir="${build.dir}"/>
+        <delete dir="${build.test.dir}"/>
+        <delete dir="${dist.dir}"/>
+    </target>
+
+    <target name="format" depends="init">
+        <jalopy fileformat="unix" convention="${src.dir}/core/etc/jalopy.xml" history="file" historymethod="adler32" loglevel="error" threads="2" classpathref="cp">
+            <fileset dir="${src.dir}">
+                <include name="**/*.java"/>
+            </fileset>
+        </jalopy>
+    </target>
+
+    <!-- Run the unit tests. This is used by the test target, so do not call directly -->
+    <target name="test-base">
+        <taskdef name="junit" classname="org.apache.tools.ant.taskdefs.optional.junit.JUnitTask"/>
+
+        <!-- Clear out any previous persistent cache directory -->
+        <delete dir="${test.cache.path}" failonerror="false"/>
+
+        <junit printsummary="yes" haltonfailure="yes" haltonerror="yes" fork="yes">
+            <classpath>
+                <pathelement location="${build.test.dir}"/>
+                <path refid="plugins.cp"/>
+            </classpath>
+
+            <formatter type="xml"/>
+
+            <batchtest todir="${dist.dir}/docs/junit">
+                <fileset dir="${build.test.dir}">
+                    <include name="**/TestComplete*.class"/>
+                    <exclude name="**/web/*.*"/>
+                    <exclude name="**/clustersupport/*.*"/>
+                </fileset>
+            </batchtest>
+        </junit>
+    </target>
+
+    <target name="test-cluster" if="test.cluster">
+        <taskdef name="junit" classname="org.apache.tools.ant.taskdefs.optional.junit.JUnitTask"/>
+
+        <!-- Clear out any previous persistent cache directory -->
+        <delete dir="${test.cache.path}" failonerror="false"/>
+
+        <junit printsummary="yes" haltonfailure="yes" haltonerror="yes" fork="yes">
+            <classpath>
+                <pathelement location="${build.test.dir}"/>
+                <path refid="plugins.cp"/>
+            </classpath>
+
+            <formatter type="xml"/>
+
+            <batchtest todir="${dist.dir}/docs/junit">
+                <fileset dir="${build.test.dir}">
+                    <include name="**/TestCompleteCluster.class"/>
+                </fileset>
+            </batchtest>
+        </junit>
+    </target>
+
+    <target name="test-web" if="test.web.baseURL">
+        <mkdir dir="${dist.dir}/docs/junit"/>
+        <mkdir dir="${build.test.dir}"/>
+
+        <!-- Clear out any previous persistent cache directory -->
+        <delete dir="${test.cache.path}"/>
+
+        <javac srcdir="${src.core}/test" destdir="${build.test.dir}" includes="com/opensymphony/oscache/web/**" debug="${debug}" classpath="${build.dir}" classpathref="cp"/>
+
+        <java classname="com.opensymphony.oscache.web.CheckDeployment" failonerror="true" classpath="${build.test.dir}" fork="yes">
+            <arg value="${test.web.baseURL}"/>
+        </java>
+
+        <taskdef name="junit" classname="org.apache.tools.ant.taskdefs.optional.junit.JUnitTask"/>
+
+        <junit printsummary="yes" haltonfailure="yes" haltonerror="yes" fork="yes">
+            <sysproperty key="test.web.baseURL" value="${test.web.baseURL}"/>
+            <classpath>
+                <pathelement location="${build.test.dir}"/>
+                <pathelement location="${build.dir}"/>
+                <path refid="cp"/>
+            </classpath>
+
+            <formatter type="xml"/>
+            <formatter type="plain" useFile="false"/>
+            <batchtest todir="${dist.dir}/docs/junit">
+                <fileset dir="${build.test.dir}">
+                    <include name="**/web/TestComplete*.class"/>
+                    <include name="**/web/TestLoadComplete*.class"/>
+                </fileset>
+            </batchtest>
+        </junit>
+    </target>
+
+
+    <!-- Run JUnit tests using different combinations of disk and memory caching -->
+    <target name="test" depends="init, compile, example-war, clover-check, junit-check">
+        <mkdir dir="${dist.dir}/docs/junit"/>
+        <mkdir dir="${dist.dir}/docs/clover"/>
+        <mkdir dir="${build.test.dir}"/>
+
+        <taskdef resource="clovertasks"/>
+        <javac srcdir="${src.core}/java" destdir="${build.test.dir}" debug="${debug}" classpathref="cp" compiler="org.apache.tools.ant.taskdefs.CloverCompilerAdapter"/>
+        <javac srcdir="${src.core}/test" destdir="${build.test.dir}" debug="${debug}" classpathref="cp"/>
+        <javac srcdir="${src.plugins}/clustersupport/java" destdir="${build.test.dir}" debug="${debug}" classpathref="plugins.cp" compiler="org.apache.tools.ant.taskdefs.CloverCompilerAdapter"/>
+        <javac srcdir="${src.plugins}/clustersupport/test" destdir="${build.test.dir}" debug="${debug}" classpathref="plugins.cp"/>
+        <javac srcdir="${src.plugins}/diskpersistence/java" destdir="${build.test.dir}" debug="${debug}" classpathref="plugins.cp" compiler="org.apache.tools.ant.taskdefs.CloverCompilerAdapter"/>
+        <javac srcdir="${src.plugins}/diskpersistence/test" destdir="${build.test.dir}" debug="${debug}" classpathref="plugins.cp"/>
+
+        <!-- Run tests using Memory Cache Only -->
+        <copy file="${src.core}/test/oscacheMemoryOnly.properties" tofile="${build.test.dir}/oscache.properties" overwrite="yes"/>
+        <echo message="Running tests with memory cache only" level="info"/>
+        <antcall target="test-base"/>
+        <antcall target="test-web"/>
+
+        <!-- Rerun tests using Disk Cache Only -->
+        <copy file="${src.plugins}/diskpersistence/test/oscacheDiskOnly.properties" tofile="${build.test.dir}/oscache.properties" overwrite="yes"/>
+        <echo message="Running tests with disk cache only" level="info"/>
+        <antcall target="test-base"/>
+        <antcall target="test-web"/>
+
+        <!-- ReRun tests using Disk and Memory Cache -->
+        <copy file="${src.plugins}/diskpersistence/test/oscacheDiskAndMemory.properties" tofile="${build.test.dir}/oscache.properties" overwrite="yes"/>
+        <echo message="Running tests with disk and memory caches" level="info"/>
+        <antcall target="test-base"/>
+        <antcall target="test-web"/>
+
+        <!-- Run clustering tests -->
+        <echo message="Running tests with memory caches and clustering" level="info"/>
+        <antcall target="test-cluster"/>
+
+        <delete dir="${test.cache.path}"/>
+    </target>
+
+
+    <!-- Generate JavaDoc -->
+    <target name="javadocs" depends="init">
+        <mkdir dir="${dist.dir}/docs/api"/>
+        <javadoc sourcepath="${src.core}/java" destdir="${dist.dir}/docs/api" packagenames="${packages}" classpathref="cp" author="true" version="true" windowTitle="${Name} ${version} API" doctitle="${Name}" footer="See &lt;a href=&quot;http://www.opensymphony.com/&quot;&gt;www.opensymphony.com&lt;/a&gt; for more information." use="true" verbose="false"/>
+    </target>
+
+    <target name="docs" depends="javadocs, clover.report, junit.report">
+        <copy todir="${dist.dir}/docs">
+            <fileset dir="${doc.dir}"/>
+        </copy>
+    </target>
+
+    <!-- Create the distribution zip files -->
+    <target name="dist" depends="clean, jar, docs, example-war, clover.report, junit.report">
+        <mkdir dir="${tmp.dir}/docs"/>
+        <mkdir dir="${tmp.dir}/src"/>
+        <mkdir dir="${tmp.dir}/lib"/>
+        <mkdir dir="${tmp.dir}/etc"/>
+
+        <copy todir="${tmp.dir}/docs">
+            <fileset dir="${dist.dir}/docs"/>
+        </copy>
+        <copy todir="${tmp.dir}/src">
+            <fileset dir="${src.dir}" excludes="core/etc/**"/>
+        </copy>
+        <copy todir="${tmp.dir}/lib">
+            <fileset dir="${lib.dir}" excludes="build/**" />
+        </copy>
+
+        <copy file="${dist.dir}/${name}_${version}${release}.jar" tofile="${tmp.dir}/${name}_${version}${release}.jar"/>
+        <copy file="${src.core}/etc/oscache.properties" tofile="${tmp.dir}/etc/oscache.properties"/>
+        <copy file="${src.core}/etc/oscache.tld" tofile="${tmp.dir}/etc/oscache.tld"/>
+        <copy file="readme.txt" tofile="${tmp.dir}/readme.txt" failonerror="false"/>
+
+        <zip zipfile="${dist.dir}/${name}_${version}${release}_full.zip" basedir="${tmp.dir}" includes="**"/>
+
+        <!-- Remove everything that's not in the binary release -->
+        <delete dir="${tmp.dir}/src"/>
+        <delete dir="${tmp.dir}/lib/build"/>
+        <delete dir="${tmp.dir}/lib/plugins"/>
+        <move todir="${tmp.dir}/lib">
+            <fileset dir="${tmp.dir}/lib/core"/>
+        </move>
+        <delete dir="${tmp.dir}/lib/core"/>
+        <delete dir="${tmp.dir}/docs/junit"/>
+        <delete dir="${tmp.dir}/docs/clover"/>
+
+        <zip zipfile="${dist.dir}/${name}_${version}${release}_binary.zip" basedir="${tmp.dir}" includes="**"/>
+
+        <delete dir="${tmp.dir}"/>
+    </target>
+
+    <target name="clover.report" depends="test">
+        <clover-report>
+            <current outfile="${dist.dir}/docs/clover">
+                <fileset dir="${src.core}" excludes="**/Test*"/>
+                <fileset dir="${src.plugins}" excludes="**/Test*"/>
+                <format type="html"/>
+            </current>
+        </clover-report>
+    </target>
+
+    <target name="junit.report" depends="test">
+        <junitreport todir="${dist.dir}/docs/junit">
+            <fileset dir="${dist.dir}/docs/junit">
+                <include name="TEST-*.xml"/>
+            </fileset>
+            <report format="frames" todir="${dist.dir}/docs/junit"/>
+        </junitreport>
+    </target>
+
+    <target name="reports" depends="junit.report,clover.report"/>
 
 </project>
 
Add a comment to this file

docs/atlassian-sponsor.gif

Added
New image

docs/changelog.html

+<html>
+<head>
+<title>OSCache Changelog</title>
+</head>
+
+<body bgcolor="#FFFFFF">
+
+
+<h3>OSCache 2.0.1</h3>
+<p><i>(4th November 2003 - by <a href="&#109;a&#105;&#108;&#116;&#111;:chris&#64;swebtec.&#99;&#111;&#109;">Chris Miller</a>)</i></p>
+<b>Bug Fixes:</b>
+<ul>
+  <li>[CACHE-59] Silent mode could not be reset.</li>
+  <li>[CACHE-60] Fixed deadlock problem when cancelUpdate() was called while under load.</li>
+</ul>
+<b>Improvements:</b>
+<ul>
+  <li>[CACHE-51] Added an &lt;cache:addgroup /&gt; tag. This allows cache groups to be
+  dynamically added from within a &lt;cache:cache /&gt; tag.</li>
+  <li>Website documentation is now bundled with the OSCache distribution.</li>
+</ul>
+<b>Changes that may affect backwards compatibility:</b>
+<ul>
+  <li>StringUtil.split() now returns a List rather than a String[].</li>
+</ul>
+
+
+<h3>OSCache 2.0</h3>
+<p><i>(22nd September 2003 - by <a href="&#109;a&#105;&#108;&#116;&#111;:chris&#64;swebtec.&#99;&#111;&#109;">Chris Miller</a>)</i></p>
+<b>Bug Fixes:</b>
+<ul>
+  <li>[CACHE-52] Fixed a problem that caused no output on Tomcat for small JSP files.</li>
+  <li>[CACHE-53] Updated documentation to explain that a PersistenceListener must
+    be specified to enable caching to disk.</li>
+  <li>[CACHE-55] JMS was throwing an exception on Weblogic.</li>
+  <li>Altering the cache capacity on the fly using the administrator classes wasn't
+    working correctly.</li>
+</ul>
+<b>Improvements:</b>
+<ul>
+  <li>Minor FastCronParser speedup.</li>
+  <li>Made ClusterNotification constants public.</li>
+  <li>Dropped some of the logging levels from INFO down to DEBUG.</li>
+  <li>Release has been split into two - a binary release and a full release (includes source).</li>
+</ul>
+
+
+<h3>OSCache 2.0 (beta 2)</h3>
+<p><i>(4th August 2003 - by <a href="&#109;a&#105;&#108;&#116;&#111;:chris&#64;swebtec.&#99;&#111;&#109;">Chris Miller</a>)</i></p>
+<b>New Features:</b>
+<ul>
+  <li>Now supports JavaGroups version 2.1.</li>
+  <li>JMS Clustering support has been added [Romulus Pasca].</li>
+  <li>Clustering code has been refactored. As a result of this, some of the
+  clustering configuration has changed since beta 1 - please see the updated
+  clustering documentation for details.</li>
+  <li>Performance enhancement: When running under JRE 1.3.x, the LRUCache will
+  now attempt to use the Jakarta commons collections SequencedHashMap. If the
+  commons-collections.jar is not present then the code resorts to using a
+  LinkedList and a warning is logged. Note that under JRE 1.4.x and higher the
+  commons-collections.jar is not required.</li>
+  <li>Config.getProperties() method added.</li>
+</ul>
+<b>Bug Fixes:</b>
+<ul>
+  <li>[CACHE-48] FastCronParser no longer requires JDK 1.4.x.</li>
+  <li>[CACHE-45] Fixed a serialization bug.</li>
+  <li>The CachewideEvent was not holding the event date.</li>
+  <li>Prevented an error from being logged in the CachewideEvent handling (even
+  though no problem had occurred).</li>
+  <li>Fixed a subtle bug in the concurrent unit test.</li>
+  <li>The ServletCacheAdministrator's app scope cache is created on startup (via
+  the CacheContextListener).</li>
+</ul>
+
+
+<h3>OSCache 2.0 (beta 1)</h3>
+<p><i>(19th July 2003 - by <a href="&#109;a&#105;&#108;&#116;&#111;:chris&#64;swebtec.&#99;&#111;&#109;">Chris Miller</a>)</i></p>
+<b>New Features:</b>
+<ul>
+  <li>[CACHE-11] Cache grouping support. This allows cache entries to be placed
+  into an arbitrary group or groups and flushed with a single flushGroup()
+  call.</li>
+  <li>[CACHE-30] Added support for expiring cache entries based on a cron expression.
+  Entries that are older than the date/time that most recently matches the cron
+  expression will be considered stale. This is exposed to the cache tag via
+  the 'cron' attribute. See cronTest.jsp for  examples.</li>
+  <li>Event listener support has been refactored and improved. It is now possible
+  to specify a comma-delimited list of event listeners using this property.
+  Previously only one class could be specified. Events listed here should
+  implement the CacheEntryEventListener and/or the ScopeEventListener interfaces.</li>
+  <li>New event CacheMapAccessEvent.STALE_HIT. This event is fired when an attempt
+  is made to retrieve and entry from the cache, and the entry is found but is
+  stale.</li>
+  <li>Clustering support has been added as an event listener. Currently it is
+  implemented using JavaGroups (www.javagroups.com). To enable, just add the
+  BroadcastingCacheEventListener class to the cache.event.listeners property.</li>
+  <li>Now uses Jakarta Commons Logging for all log messages. This means that the
+  cache.debug configuration property is now ignored - use whatever logging
+  configuration is appropriate for your logging setup instead. [Fabian Crabus]</li>
+  <li>[CACHE-14, Matthias Nott] Now allows for content to be cached indefinitely
+  without expiration.</li>
+  <li>The build.xml &lt;javac ...&gt; directives now specify debug="true".</li>
+  <li>Performance boost: When OSCache is running on JRE 1.4 or higher, LRUCache
+  and FIFOCache use a LinkedHashSet instead of a LinkedList.</li>
+  <li>Japloy is now used to ensure source is consistently formatted.</li>
+  <li>Test cases now work on non-windows platforms. Also coverage reports added
+  courtesy of clover.</li>
+</ul>
+<b>Changes that may affect backwards compatibility:</b>
+<ul>
+  <li>The cache.entryevent.classes property in the configuration file has been
+  renamed to cache.event.listeners, since it accepts CacheEntryEventListener,
+  ScopeEventListener and CacheMapAccessEventListener types.</li>
+  <li>The cache.persistence.classes property has been renamed to cache.persistence.class
+  since it is only possible to specify one PersistenceListener.</li>
+  <li>For consistency, cache.unlimited_disk is now cache.unlimited.disk and
+  cache.useHostDomainInKey is now cache.use.host.domain.in.key.</li>
+  <li>The oscache.tld file now uses a taglib 1.2 DTD.</li>
+  <li>To build OSCache, JDK 1.4.x or higher is required. There is however no
+  runtime dependency on JDK 1.4.x.</li>
+  <li>The Cache.flushPattern() method and &lt;cache:flush pattern=&quot;...&quot;/&gt;
+  are deprecated. You are instead encouraged to group your cache entries when you
+  add them to the cache and then use the Cache.flushGroup() method or the
+  &lt;cache:flush group=&quot;...&quot;/&gt; tag to flush an entire cache group.</li>
+  <li>Disk persistence now puts all files in the same directory. This has a number
+  of side effects. Keys >255 chars will cause problems. Also, similar keys
+  might get mapped to the same file. For example, it is very inadvisable to
+  have two keys with the names 'my_key' and 'my.key'.</li>
+  <li>GeneralCacheAdministrator is no longer static. Users that relied
+  on this behaviour can still hold onto a static reference to it with
+  minor code changes.</li>
+  <li>When a NeedsRefreshException is thrown, it is now vital that the cache
+  entry is either updated, or Cache.cancelUpdate(key) is called to release
+  the lock on this cache entry. This is a consequence of the fix for [CACHE-42].</li>
+  <li>CacheProperties class was removed. It didn't work on 1.7.5 anyway.
+  The same effect can be achieved by specifying a subclass of Properties.</li>
+  <li>Autogenerated cache keys now contain the request method (eg, HEAD, GET, etc).</li>
+  <li>OSCache has been repackaged from "com.opensymphony.module.oscache.*" to
+  "com.opensymphony.oscache.*". Any code or configuration files that refer to
+  "com.opensymphony.module.oscache" will need to be updated.</li>
+</ul>
+<b>Bug Fixes:</b>
+<ul>
+  <li>[CACHE-4] WebSphere 3.5.x compatibility.</li>
+  <li>[CACHE-5] Added a mode attribute to the cache tag to allow content to be
+  cached but not sent to the output stream. See oscacheTest.jsp for an example.</li>
+  <li>[CACHE-7] "cache" Tag has no "setEncoding" method.</li>
+  <li>[CACHE-9] It could be useful being able to specify directories relative
+  to the web application dir. for config file and cache dir. Use new
+  properties aware getInstance method.</li>
+  <li>[CACHE-10] Cannot write and use custom class implementing CacheProperties.</li>
+  <li>[CACHE-13] AbstractConcurrentReadCache loops indefinitely when
+  persistRetrieve() returns null.</li>
+  <li>[CACHE-14] You can now specify an unlimited refresh time by supplying a
+  negative value for the duration.</li>
+  <li>[CACHE-17] An example war is now included - "ant example-war". Once deployed
+  this can be tested using "ant test-web".</li>
+  <li>[CACHE-26] Security hole whereby certain keys can overwrite any file.</li>
+  <li>[CACHE-28] URLs can now be used as keys with disk persistence.</li>
+  <li>[CACHE-31 and CACHE-33] The cache tag's refresh attribute will now be taken
+  into account even if a custom refresh policy has been specified.</li>
+  <li>[CACHE-34] Setting properties with AbstractCacheAdministrators.
+  New getInstance method added to ServletCacheAdministrator that takes
+  in properties.</li>
+  <li>[CACHE-35] CacheFilter needs to distinguish between HEAD and GET requests.</li>
+  <li>[CACHE-39 and CACHE-44] Synchronization with LRUCache fixed.</li>
+  <li>[CACHE-42] Threads will no longer race to (re)build expired or new
+  cache entries. By default stale content will be served if available.
+  This behaviour can be changed by setting oscache.blocking=true, which will
+  instead cause threads to block until the new cache entry is available.</li>
+  <li>[CACHE-43] Taglibs have been made spec-compliant. They now follow the
+  guidelines at http://jakarta.apache.org/taglibs/guidelines.html.</li>
+  <li>Some synchronization issues were fixed in LRUCache.getItem() and
+  AbstractConcurrentReadCache.setMaxEntries().</li>
+  <li>ScopeEventListener classes were previously not able to be specified in the
+  configuration even though the dispatching code was implemented.
+  ScopeEventListeners can now be specified using the cache.event.listeners
+  configuration property.</li>
+  <li>CacheMapAccessEvents now only fire when an attempt is made to retrieve the
+  actual cache content for external use. Previously these events were being
+  fired in circumstances that were not of statistical interest - for example
+  HIT and MISS events were being fired when updating or flushing entries from
+  the cache.</li>
+  <li>Minor bug in oscacheTestMultipleTagNoKey.jsp - some of the tag refresh times
+  weren't correctly specified.</li>
+  <li>cachetest.jsp - the 'refresh' functionality wasn't working because the
+  addition of the refresh parameter caused the cache key to be different.
+  The key is now specified explicitly.</li>
+  <li>EntryRefreshPolicy is now serializable so it can be persisted to the disk
+  cache.</li>
+  <li>ServletCacheAdministrator now sorts request parameters and filters out
+  jsessionid so they have no impact on the generated cache key.</li>
+  <li>CacheFilter only caches successful responses (status code == SC_OK).</li>
+
+</ul>
+<b>Known Problems:</b>
+(these have existed for some time in the 1.x.x versions and will be addressed in
+an upcoming 2.x.x release)
+<ul>
+  <li>Session caches (created using the ServletCacheAdministrator) have some
+  known limitations:
+  <ul>
+    <li>Due to a workaround in the code, it is possible for a system under
+        heavy load to get its persistent session caches confused across
+        sessions.</li>
+    <li>Session caches will not work in a clustered environment.</li>
+    <li>Session caches have the same settings global settings applied to them
+        as the application scope cache. This means that if you want a
+        persistent cache for the application scope cache, the session caches
+        will use it too.</li>
+  </ul>
+  </li>
+</ul>
+
+<h3>OSCache 1.7.5</h3>
+<i>(5th January 2002 - by Mike Cannon-Brookes, mike@atlassian.com)</i>
+<ul>
+<li>Fixed up logging system slightly. All errors should now be logged with logError()
+	and normal messages with log()</li>
+  <li>Fixed bug in build file which put oscache.properties inside the oscache.jar (resulting
+	in it being loaded badly in some containers)</li>
+  <li>Changed cache.capacity in the default oscache.properties file to 1000. This means up to 1000
+	items will be cached in the default setup, and LRUCache will be used (100 seemed too small)</li>
+</ul>
+
+<h3>OSCache 1.7.4</h3>
+<i>(3rd December 2001 - by Francois Beauregard, fbeauregard@pyxis-tech.com, and<br>
+ Mike Cannon-Brookes, mike@atlassian.com)</i>
+<ul>
+  <li>Made all servlet cache components serializable (fixes bug reported on list
+  with JRun)</li>
+</ul>
+
+<h3>OSCache 1.7.3</h3>
+<i>(11th November 2001 - by Francois Beauregard, fbeauregard@pyxis-tech.com)</i>
+<ul>
+  <li>TestCacheEntry had a test method with improper name (flush -> testFlush)</li>
+  <li>Pluggable entry refresh policy now available in the cache tag</li>
+</ul>
+
+<h3>OSCache 1.7.2</h3>
+<i>(31st October 2001 - by Mike Cannon-Brookes, mike@atlassian.com)</i>
+<ul>
+  <li>Cleaned up _all_ JavaDoc messages to ensure consistency and readability
+    (removed unnecessary CVS tags, added &lt;code&gt; and &lt;pre&gt; where needed,
+    added @return and @param to all methods)</li>
+  <li>Renamed nbMaxEntries to cacheCapacity and cache.size property to
+    cache.capacity (to fit better with Collections API where capacity is max size,
+    size is current size)</li>
+  <li>Renamed algoClass to algorithmClass for clarity.</li>
+  <li>Fixed up build.xml so that test classes are compiled to a different location
+    and not included in oscache.jar (to make it smaller footprint)</li>
+</ul>
+
+<h3>OSCache 1.7.1</h3>
+  <i>(26th September 2001 - by Francois Beauregard, fbeauregard@pyxis-tech.com,
+    and<br>
+    Alain Bergevin, abergevin@pyxis-tech.com, of <a href="http://www.pyxis-tech.com">Pyxis
+    Technologies Inc.</a>)</i><br>
+</p>
+<ul>
+  <li>Cache Events</li>
+  <li>Persistence mechanism refactored</li>
+  <li>Cache Algorithms FIFO + LRU (Limit the size of the cache)</li>
+  <li>AbstractConcurrentReadCache from Doug Lea's ConcurrentReaderHashMap.<br>
+    Should give oscache performance improvement</li>
+  <li>Disk Persistence does not need any locking strategies. Everything is handled
+    by AbstractConcurrentReadCache</li>
+  <li>Pluggable entry refresh policies</li>
+  <li>Unlimited cache size for disk</li>
+  <li>Specify Duration using Simple Date Format or ISO-8601 as suggested by Fredrik Lindgren)<br>
+    The next one that would make sense I think is being able to specify a specific
+    time of day.</li>
+</ul>
+
+<h3>OSCache 1.7.0</h3>
+  <i>(26th September 2001 - by Francois Beauregard, fbeauregard@pyxis-tech.com,
+  and<br>
+  Alain Bergevin, abergevin@pyxis-tech.com, of <a href="http://www.pyxis-tech.com">Pyxis
+  Technologies Inc.</a>)</i><br>
+</p>
+
+<p>This version include some refactoring, corrections and new features.<br>
+  Here are the highlights:</p>
+<ul>
+  <li>CacheAdministrator has been split
+    in 3. We have now AbstractCacheAdministrator, and ServletCacheAdministrator
+    and GeneralCacheAdministrator extends it</li>
+  <li>Packages have been adjusted. We now have oscache.base, oscache.general and oscache.Servlet.<br>
+    Adjustement must be made to the oscache.tld</li>
+  <li>ServletCacheHashMap has been created in order to reflect specific needs for
+    Servlets. It extends CacheHashMap</li>
+  <li>Support for multiple cache tag in a single page, without supplying a key.
+    Nested cache tag are not yet supported (you need to manage keys in that case).</li>
+  <li>OSCache can now cache any objects (not only JSP content) using
+    GeneralCacheAdministrator</li>
+  <li>GenerateKey now support suffixes (used to deal with multiple cache tags)</li>
+  <li>A complete JUnit test suite has been created for osCache, including a JSP
+    and a Servlet</li>
+  <li>Added the required libraries for the test unit. The JUnit JAR has been
+    upgraded to version 3.7</li>
+  <li>Required libraries are now HHTPUnit, Tidy, JUnit 3.7 and JUnitPerf</li>
+  <li>The cBuffer variable used for keyGeneration has been moved locally to
+    GenerateKey since it was a threading issue</li>
+  <li>The build file has been modified to include test running</li>
+  <li>The flushAll method is now abstract since CacheAbstractAdministrator can't
+    know all valid scopes</li>
+  <li>Removed the retry logic for disk cache read and write (not used anymore)</li>
+  <li>Fixed an issue with the needsRefresh method which returned an invalid value
+    when invoked first by returning true
+    and then invoked having to return false. Both case returned true.</li>
+  <li>The doStartTag method in CacheTag has been modified to prevent returning null
+    when cache content is missing (cache file deleted)</li>
+  <li>The doAfterBody method in CacheTag has been modified in order to prevent
+    hitting the cache twice in some situation</li>
+  <li>The useBody method in CacheTag has been renamed to setUseBody in order to
+    reflect its usage</li>
+  <li>LoadProperties interface added to CacheProperties</li>
+  <li>Added a NeedsRefreshException</li>
+  <li>Retrofited the changed made by Kesav Kumar in order to retrieve the sessionId
+    correctly</li>
+  <li>Added code toughness to avoid working with invalid parameters in public methods</li>
+  <li>Magic numbers and strings are now declared as constants</li>
+  <li>Many methods are now declared as final or protected</li>
+  <li>Imports are now more accurate, no more *</li>
+  <li>Comments and some headers modified to reflect JavaDoc standard</li>
+</ul>
+
+
+<h3>OSCache 1.6.1</h3>
+  <p><i>(16th September, 2001 - by Todd Gochenour, tgochenour@peregrine.com)</i></p>
+<ul>
+  <li>Removed attribute "encoding" in all areas, since Object serialization stores
+    strings in UTF-8 format, encoding is no longer necessary.</li>
+  <li>Added Synchronization to getCacheEntry() to insure multiple threads do not access
+    HashMap and get erroneous results.</li>
+  <li>Implemented property cache.useHostDomainInKey (true/false) to prepend URL request
+    server name to cache key when cache used by multiple servers. The "cache.domainname"
+    property found in oscache.properties (not used in code) was removed.</li>
+  <li>Corrected file caching logic so that multiple processes can share cache information
+    (file locking). Missing still is the ability to signal processes that a cache needs
+    to be flushed when using Memory Caching along with File Caching.</li>
+  <li>Unit testing revealed some minor configuration bugs which were corrected.</li>
+</ul>
+
+<h3>OSCache 1.6</h3>
+  <p><i>(5th September, 2001 - by Mike Cannon-Brookes, mike@atlassian.com)</i></p>
+
+<ul>
+  <li>Changed the CacheEntry so that it caches Object rather than String (allowing
+    image caching) (Serge Knystautas, sergek@lokitech.com)</li>
+  <li>Cached objects are now serialized to disk so cannot be read by humans anymore
+    (this allows us to cache Object) (Serge Knystautas, sergek@lokitech.com)</li>
+  <li>Added a Servlet 2.3 CacheFilter (and associated response classes) that caches
+    whole requests (Serge Knystautas, sergek@lokitech.com)</li>
+  <li>Minor changes to CacheAdministrator (the way Cache and CacheEntry's are retrieved)
+    - merging Serge and Todd's changes</li>
+</ul>
+
+<h3>OSCache 1.5</h3>
+  <p><i>(6th August, 2001 - by Todd Gochenour, tgochenour@peregrine.com)</i></p>
+<ul>
+  <li>Added boolean "cache.memory" attribute to oscache.properties to eliminate memory
+    consumption and rely strictly on disk storage.</li>
+  <li>Added three interfaces "CacheLog", "CacheProperties", and "CacheContents" to allow
+    plugable implementations for these functions. The CacheContents interface allows the
+    pages to be cached using a database.</li>
+  <li>Added "Language" attribute to CacheTag and FlushTag to distinguish a page that
+    supports I18N generation. The ISO-639 language code is used when the scope of the page
+    is "Application". The code defines a subdirectory under the "application" directory of
+    file caching.</li>
+  <li>Modified the CacheAdministrator.generateKey() function to append the request's
+    QueryString to the URI when automatically generating keys. The QueryString is encoded
+    using the MD5 digest base64 algorithms.</li>
+  <li>Added attribute "encoding" to a CacheTag so that the file IO does proper conversion
+    when reading and writing the cache files. (per suggestion of Pedro Gomez)</li>
+  <li>Added retries when SecurityException is thrown. Java has no built in exclusive file
+    locking implementations. The file is written to a lock file and then renamed as an
+    atomic operation so that multiple processes on the same box can reliable access cache data.</li>
+  <li>Added "pattern" attribute to FlushTag which invokes a CacheHashMap.flushPattern()
+    function to scan for and flush all keys that contain the value of the pattern. (per
+    suggestion of Todd Rudrick)</li>
+  <li>Added support for a CacheTag time value of zero which turns off caching for that tag.
+    (per suggestion of Pedro Gomez)</li>
+</ul>
+
+<h3>OSCache 1.3</h3>
+  <p><i>(9th June, 2001 - by Mike Cannon-Brookes, mike@atlassian.com)</i></p>
+<ul>
+  <li>Fixed a single bug in the file caching - should now work</li>
+  <li>Added property to set the cache key (not sure if this is useful)</li>
+  <li>Cleaned up a lot of the code, refactored slightly so that the tags are more light
+    weight and rely more on the Administrator and CacheHashMap for functionality.</li>
+</ul>
+
+<h3>OSCache 1.2.5</h3>
+  <p><i>(18th May, 2001 - by Mike Cannon-Brookes, mike@atlassian.com)</i></p>
+<ul>
+  <li>Added ability to turn off file caching (just remove or comment out cache.properties)</li>
+  <li>Removed a pesky (but ineffectual) bug where session caches being removed from disk
+    were throwing NullPointerExceptions</li>
+</ul>
+
+<h3>OSCache 1.2.1</h3>
+  <p><i>(10th May, 2001 - by Mike Cannon-Brookes, mike@atlassian.com)</i></p>
+<ul>
+  <li>Speed improvements in CacheEntry and CacheAdministrator (by Kesav Kumar -
+    kesavk@voquette.com)</li>
+  <li>Fixed DOCTYPE in taglib.tld (also Kesav!)</li>
+  <li>Removed backup / swap / temp files from zip (and changed build file)</li>
+</ul>
+
+<h3>OSCache 1.2</h3>
+  <p><i>(28th March, 2001 - by Mike Cannon-Brookes, mike@atlassian.com)</i></p>
+<ul>
+  <li>Fixed a large bug that resulted in CacheEntry's not refreshing. Large enough
+    in a Caching library to demand a new point release ;)</li>
+</ul>
+
+<h3>OSCache 1.1</h3>
+  <p><i>(25th March, 2001 - by Mike Cannon-Brookes, mike@atlassian.com)</i></p>
+<ul>
+  <li>Moved up to 1.1 because a lot of documentation improving and some small bug fixing
+    has been done</li>
+  <li>Javadocs should now be very readable for all classes and methods</li>
+  <li>Fixed a NullPointer that was being thrown in CacheEntry.needsRefresh()</li>
+  <li>Cleaned up the build file so it now produces releasable zip files easily</li>
+  <li>Added servlet.jar so that the compiling now works OOB (Out Of the Box)</li>
+</ul>
+
+<h3>OSCache 1.0 (beta release 2)</h3>
+  <p><i>(20th March, 2001 - by Mike Cannon-Brookes, mike@atlassian.com)</i></p>
+<ul>
+  <li>Fixed more bugs.</li>
+  <li>Moved things around so that the CacheAdministrator has more functionality and
+    is now a Singleton (per web app context). This means no more depedency on
+    ServletContextListener to start the CacheAdministrator.</li>
+  <li>Therefore we are now Servlet 2.2 / JSP 1.1 compliant! w00!</li>
+</ul>
+
+<h3>OSCache 1.0 (beta release 1)</h3>
+  <p><i>(20th February, 2001 - by Mike Cannon-Brookes, mike@atlassian.com)</i></p>
+<ul>
+  <li>Fixed a few bugs.</li>
+  <li>Greatest of which there is no longer a disk leakage from session caches on disk.</li>
+  <li>Also session caching bugs fixed, usecached bugs fixed - lots of work done here.</li>
+  <li>Implemented <flush scope="" key=""> to flush individual keys.</li>
+</ul>
+
+<h3>OSCache 1.0 (beta release 0)</h3>
+  <p><i>(26th November, 2000 - by Mike Cannon-Brookes, mike@atlassian.com)</i></p>
+<ul>
+  <li>Initial release of OSCache</li>
+  <li>Conceptualised a few things I've been working on over the past month.</li>
+  <li>Added persistent on disk caching and error tolerance (through &lt;usecached /&gt; tag)</li>
+</ul>
+</body>
+</html>

docs/clustering.html

+<html>
+<head>
+<title>Clustering OSCache</title>
+</head>
+
+<body bgcolor="#FFFFFF">
+
+<p>New in OSCache 2.0 is support for clustering of caches. OSCache currently ships with
+implementations that allow you to use either <a href="http://www.javagroups.com">JavaGroups</a>
+or <a href="http://java.sun.com/products/jms">JMS</a> as the underlying broadcast protocol.
+</p>
+
+<p>Caches across a cluster only broadcast messages when flush events occur. This means that the
+content of the caches are built up independently on each server, but whenever content becomes
+stale on one server it is made stale on them all. This provides a very high performing solution
+since we never have to pass cached objects around the cluster. And since there is no central
+server that is in charge of the cluster, the clustering is very robust.</p>
+
+
+<p>Configuring OSCache to cluster is very simple. Follow either the JMS or the JavaGroups instructions
+below depending on which protocol you want to use.</p>
+
+
+<h3>JMS Configuration</h3>
+
+<p>Configure your JMS server. OSCache requires that a JMS <code>ConnectionFactory</code> and a <code>Topic</code>
+are available via JNDI. See your JMS server's documentation for details.</p>
+
+<p>Add the JMS broadcasting listener to your <code>oscache.properties</code> file like this:</p>
+
+<p><code>cache.event.listeners=com.opensymphony.oscache.plugins.clustersupport.JMSBroadcastingListener</code></p>
+
+<p>(Note that this listener requires JMS 1.1 or higher, however legacy support for 1.0.x is also provided.
+If your JMS server only supports JMS 1.0.x then use <code>JMS10BroadcastingListener</code> instead of
+<code>JMSBroadcastingListener</code>. The rest of this documentation applies equally to both the 1.1 and 1.0
+listeners.)</p>
+
+<p>The JMS listener supports the following configuration parameters:
+<ul>
+<li><b>cache.cluster.jms.topic.factory</b> - The JNDI name that binds the JMS topic connection factory. This
+should match the name that is specified in your JMS server's configuration. Typically it will be something like
+<code>"java:comp/env/jms/TopicConnectionFactory"</code></li>
+<li><b>cache.cluster.jms.topic.name</b> - The JNDI name of the topic that will be used for the OSCache
+sending the messages. This should match the name of a topic that is configured on your JMS server. Typically
+this value will be something like <code>"java:comp/env/jms/OSCacheTopic"</code>.</li>
+<li><b>cache.cluster.jms.node.name</b> - A name that uniquely identifies this node in the cluster. This is used
+to prevent nodes from processing their own broadcast messages. Each node in the cluster must have a different
+value, for example <code>"node1"</code>, <code>"node2"</code>, ... .</li>
+</ul></p>
+
+<p>If you are running OSCache from a standalone application or are not running in an environment where
+<code>new InitialContext()</code> will find your JNDI <code>InitialContextFactory</code> or provider URL,
+you will have to specify them either in a <code>jndi.properties</code> file or as system properties. See the
+<code><a href="http://java.sun.com/j2se/1.4.2/docs/api/javax/naming/InitialContext.html">InitalContext</a></code>
+documentation for details.</p>
+
+
+<h3>JavaGroups Configuration</h3>
+
+<p>Just make sure you have javagroups-all.jar file in your classpath (for a webapp put it in WEB-INF/lib),
+and add the JavaGrops broadcasting listener to your <code>oscache.properties</code> file like this:</p>
+
+<p><code>cache.event.listeners=com.opensymphony.oscache.plugins.clustersupport.JavaGroupsBroadcastingListener</code></p>
+
+<p>In most cases, that's it! OSCache will now broadcast any cache flush events across the LAN. The javagroups-all.jar
+library is not included with the binary distribution due to its size, however you can obtain it either by downloading
+the full oscache distribution, or by visiting the <a href="http://www.javagroups.com">JavaGroups</a> website.</p>
+
+<p>If you want to run more than one OSCache cluster on the same LAN, you will need to use different
+multicast IP addresses. This allows the caches to exist in separate multicast groups and therefore
+not interfere with each other. The IP to use can be specified in your <code>oscache.properties</code>
+file by the <code>cache.cluster.multicast.ip</code> property. The default value is <code>231.12.21.132</code>,
+however you can use any class D IP address. Class D address fall in the range <code>224.0.0.0</code>
+through <code>239.255.255.255</code>.</p>
+
+<p>If you need more control over the multicast configuration (eg setting network timeout or time-to-live
+values), you can use the <code>cache.cluster.properties</code> configuration property. Use this
+<em>instead of</em> the <code>cache.cluster.multicast.ip</code> property. The default value is:</p>
+
+<p><code>UDP(mcast_addr=231.12.21.132;mcast_port=45566;ip_ttl=32;mcast_send_buf_size=150000;mcast_recv_buf_size=80000):PING(timeout=2000;num_initial_members=3):MERGE2(min_interval=5000;max_interval=10000):FD_SOCK:VERIFY_SUSPECT(timeout=1500):pbcast.NAKACK(gc_lag=50;retransmit_timeout=300,600,1200,2400,4800):pbcast.STABLE(desired_avg_gossip=20000):UNICAST(timeout=5000):FRAG(frag_size=8096;down_thread=false;up_thread=false):pbcast.GMS(join_timeout=5000;join_retry_timeout=2000;shun=false;print_local_addr=true)</code></p>
+
+See the <a href="http://www.javagroups.com">JavaGroups</a> site for more information. In particular,
+look at the documentation of Channels in the <a href="http://www.javagroups.com/javagroupsnew/docs/newuser/index.html">User's Guide</a>.
+</body>
+</html>

docs/configuration.html

+<html>
+<head>
+<title>OSCache Configuration Guide</title>
+</head>
+<body bgcolor="#FFFFFF">
+<p>This guide only covers the configuration of OSCache by using the <code>oscache.properties</code> file.
+  To see how to install OSCache and where to place the <code>oscache.properties</code> file, see the
+  <a href="install.html">Installation Guide</a>.</p>
+
+The following properties are able to be set in the <code>oscache.properties</code> file:
+
+<h3>cache.memory</h3>
+<p>Valid values are <code>true</code> or <code>false</code>, with <code>true</code> being the default value.
+If you want to disable memory caching, just comment out or remove this line.</p>
+<p>Note: disabling memory AND disk caching is possible but fairly stupid ;)</p>
+
+<h3>cache.capacity</h3>
+<p>The maximum number of items that a cache will hold. By default the capacity is unlimited - the cache will
+never remove any items. Negative values will also be treated as meaning unlimited capacity.</p>
+
+<h3>cache.algorithm</h3>
+<p>The default cache algorithm to use. Note that in order to use an algorithm the cache size must also
+be specified. If the cache size is not specified, the cache algorithm will be Unlimited cache regardless
+of the value of this property. If you specify a size but not an algorithm, the cache algorithm used will be
+<code>com.opensymphony.oscache.base.algorithm.LRUCache</code>.</p>
+<p>OSCache currently comes with three algorithms:
+<ul>
+  <li><code>com.opensymphony.oscache.base.algorithm.LRUCache</code> - Least Recently Used. This is the
+  default when a <code>cache.capacity</code> is set.</li>
+  <li><code>com.opensymphony.oscache.base.algorithm.FIFOCache</code> - First In First Out.</li>
+  <li><code>com.opensymphony.oscache.base.algorithm.UnlimitedCache</code> - Content that is added to
+  the cache will never be discarded. This is the default when no value is set for the <code>cache.capacity</code>
+  property.</li>
+</ul>
+</p>
+
+<h3>cache.unlimited.disk</h3>
+<p>Indicates whether the disk cache should be treated as unlimited or not. The default value is
+<code>false</code>.</p>
+
+<h3>cache.persistence.class</h3>
+<p>Specifies the class to use for persisting cache entries. This class must implement the <code>PersistenceListener</code>
+interface. OSCache comes with an implementation that provides filesystem based persistence. Set this property
+to <code>com.opensymphony.oscache.plugins.diskpersistence.DiskPersistenceListener</code> to enable this
+implementation. By specifying your own class here you should be able to persist cache data using say JDBC or LDAP.</p>
+<p>The <code>DiskPersistenceListener</code> class requires the following extra configuration property to be
+set:
+<blockquote>
+<h3>cache.path</h3>
+<p>This specifies the directory on disk where caches will be stored. The directory will be created if it
+doesn't already exist, but remember that OSCache must have permission to write to this location.</p>
+<p>Note: for Windows machines, the backslash character '\' needs to be escaped. ie in Windows:</p>
+<p><code>cache.path=c:\\myapp\\cache</code></p>
+<p>or *ix:</p>
+<p><code>cache.path=/opt/myapp/cache</code></p>
+</blockquote>
+
+<h3>cache.event.listeners</h3>
+<p>This takes a comma-delimited list of fully-qualified class names. Each class in the list <em>must</em>
+implement one (or more) of the following interfaces:
+<ul>
+  <li><b>CacheEntryEventListener</b> - Receives cache add/update/flush and remove events.</li>
+  <li><b>CacheMapAccessEventListener</b> - Receives cache access events. This allows you to keep statistical
+  information to track how effectively the cache is working.</li>
+</ul>
+No listeners are configured by default, however some ship with OSCache that you may wish to enable:
+<ul>
+  <li><b>com.opensymphony.oscache.plugins.clustersupport.BroadcastingCacheEventListener</b>
+    - provides clustering support for OSCache. Enabling this will cause cache flush events to be broadcast to
+    other instances of OSCache running on your LAN. See <a href="clustering.html">Clustering OSCache</a> for
+    further information about this event listener.</li>
+  <li><b>com.opensymphony.oscache.extra.CacheEntryEventListenerImpl</b> - a simple listener implementation
+    that maintains a running count of all of the entry events that occur during a cache's lifetime.</li>
+  <li><b>com.opensymphony.oscache.extra.CacheMapAccessEventListenerImpl</b> - a simple listener implementation
+    that keeps count of all the cache map events (cache hits and misses, and stale hits) that occur on a cache
+    instance.</li>
+</ul>
+It is also of course quite straightforward to write your own event listener. See the
+<a href="api">JavaDoc API</a> for further details.</p>
+
+<h3>cache.key</h3>
+<p>This is the key that will be used by the ServletCacheAdministrator (and hence the custom tags) to
+store the cache object in the application and session scope. The default value when this property is
+not specified is <code>"__oscache_cache"</code>. If you want to access this default value in your code,
+it is available as <code>com.opensymphony.oscache.base.Const.DEFAULT_CACHE_KEY</code>.</p>
+
+<h3>cache.use.host.domain.in.key</h3>
+<p>If your server is configured with multiple hosts, you may wish to add host name information to
+automatically generated cache keys. If so, set this property to <code>true</code>. The default value
+is <code>false</code>.</p>
+
+<h3>Additional Properties</h3>
+
+<p>In additon to the above basic options, any other properties that are specified in this file will still be
+loaded and can be made available to your event handlers. For example, the <code>JavaGroupsBroadcastingListener</code>
+supports the following additional properties:</p>
+
+<p><b>cache.cluster.multicast.ip</b></p>
+<p>The multicast IP to use for this cache cluster. Defaults to <code>231.12.21.132</code>.
+
+<p><b>cache.cluster.properties</b></p>
+<p>Specifies additional configuration options for the clustering. The default setting is</p>
+<p><code>UDP(mcast_addr=231.12.21.132;mcast_port=45566;ip_ttl=32;mcast_send_buf_size=150000;mcast_recv_buf_size=80000):PING(timeout=2000;num_initial_members=3):MERGE2(min_interval=5000;max_interval=10000):FD_SOCK:VERIFY_SUSPECT(timeout=1500):pbcast.NAKACK(gc_lag=50;retransmit_timeout=300,600,1200,2400,4800):pbcast.STABLE(desired_avg_gossip=20000):UNICAST(timeout=5000):FRAG(frag_size=8096;down_thread=false;up_thread=false):pbcast.GMS(join_timeout=5000;join_retry_timeout=2000;shun=false;print_local_addr=true)</code></p>
+
+<p>See the <a href="clustering.html">Clustering OSCache</a> documentation for further details on the above
+two properties.</p>
+</body>
+</html>
+<html>
+<head>
+<title>Expiring Cached Content with Cron Expressions</title>
+</head>
+
+<body bgcolor="#FFFFFF">
+<p>Prior to version 2.0 of OSCache, content expiry could only be specified in terms of how long a
+piece of content had been in the cache, ie, it was based on the age of the content. If you needed
+to expire it at a particular time of day or on a specific date, you had to write a custom
+<code>RefreshPolicy</code> class.</p>
+<p>OSCache 2.0 now gives you the ability to expire content at specific dates and/or times based on
+a <em>cron expression</em>.</p>
+
+<h3>What is a Cron Expression?</h3>
+<p>Many of you are probably already familiar with the unix cron program. For those that aren't,
+cron is a daemon process that allows users to execute commands or scripts automatically at
+user-configurable dates and times. The important part as far as OSCache is concerned is the cron
+expression syntax that allows users to dictate when commands should be executed - you can now use
+the same syntax to expire content in OSCache! A cron expression is a simple text string that
+specifies particular dates and/or times that are matched against.</p>
+
+<h3>How Does OSCache Match Against an Expression?</h3>
+<p>OSCache uses cron expressions in a manner that might seem 'backwards' to what you might
+initially expect. When using a cron expression to test if a cache entry is stale, OSCache finds
+the date and time (prior to the current time) that <em>most recently matches</em> the supplied
+expression. This date/time is used as the expiry time - entries that were placed in the cache prior
+to this expiry time are considered stale and result in a <code>NeedsRefreshException</code> being
+thrown.</p>
+<p>As an example, suppose you specify a cron expiry that matches every hour, on the hour
+(<code>"0 * * * *"</code>). If the current time is 10:42pm, then any content that was placed in
+the cache prior to 10:00pm would be considered stale.</p>
+
+<h3>The Cron Expression Syntax</h3>
+<p>A cron expression consists of the following 5 fields:
+<ul>
+  <li><b>Minute</b> - specifies what minute of the hour to expire content on. It is a number
+    between 0 and 59.</li>
+  <li><b>Hour</b> - determines what hour of the day content will expire on. It is specified
+    using the 24-hour clock, so the values must be between 0 (midnight) and 23 (11pm).</li>
+  <li><b>DOM</b> - the Day of the Month. This is a number from 1 to 31. It indicates what day the
+    content should expire on. For example, to expire content on the 10th of every month, set this
+    field to 10.</li>
+  <li><b>Month</b> - month of the year to expire the content. This can be specified either
+    numerically (1 through 12), or by using the actual month name (eg 'January'). Month names are
+    case-insensitive and only the first three characters are taken into account - the rest are
+    ignored.</li>
+  <li><b>DOW</b> - The Day of the Week that the content should be expired on. This can be a numeric
+    value (0-6, where 0 = Sunday, 1 = Monday, ..., 6 = Saturday), or you can use the actual day name.
+    As is the case with month names, DOW names are case-insensitive and only the first three
+    characters matter.</li>
+</ul>
+
+If you don't want to specify a value for a particular field (ie you want the cron expression to
+match <em>all</em> values for that field), just use a * character for the field value.</p>
+
+<p>As an example, an expression that expired content at 11:45pm each day during April would
+look like this: <code>"45 23 * April *"</code>.</p>
+
+<p>OSCache also allows you to optionally specify lists, ranges and intervals (or even a combination
+of all three) within each field:
+<ul>
+  <li><b>Lists</b> - items in a list are delimited using the ',' character. Content expiry times
+    will be matched against all values in the list for that field. For example,
+    <code>"0,15,30,45 * * * *"</code> will expire content every quarter-hour on the quarter hour.</li>
+  <li><b>Ranges</b> - ranges are specified using the '-' character. A range will include all
+    values from the start to the end value (inclusive). For example, <code>"* * * Jan-June *"</code>
+    will expire content every minute only during the first 6 months of the year.</li>
+  <li><b>Intervals</b> - an interval is specified using the '/' character. The value to the left of
+    the '/' character indicates either the starting point or the range of values that should be
+    incremented over, while the value to the right of the '/' specifies the interval or step size.
+    Some examples - <code>"10/20 * * * *"</code> is equivalent to <code>"10,30,50 * * * *"</code>,
+    while <code>"10-45/20 * * * *"</code> would only match 10 and 30 minutes past the hour, since 50
+    is outside the specified range. Supplying '*' as the left-hand value of an interval will match
+    the same values as if you had specified a range over all possible values. Eg <code>"*/10 * * * *"</code>
+    matches minutes 0,10,20,30,40 and 50.</code></li>
+</ul></p>
+
+<p>To have a look at further examples of both valid and invalid syntax, it is suggested you take a look
+at the JUnit test cases in the <code>com.opensymphony.oscache.util.TestFastCronParser</code>
+class. This class is located under the <code>src/core/test</code> directory. For examples of how to
+specify cron expiry times using the taglibs, see the <a href="tags.html">Tag Reference</a> and the
+<code>cronTest.jsp</code> file in the example web application.</p>
+
+
+<h3>Notes</h3>
+<p>
+<ul>
+  <li>You can specify both a cron expression and a refresh interval at the same time if you like.
+    This is useful in cases where you always want to expire content at midnight, but you also never
+    want it to be more than 6 hours old.</li>
+  <li>Specifying out of range values, such as a 13 in the month field, will cause a
+    <code>ParseException</code> to be thrown.</li>
+  <li>If a DOM is specified that cannot exist given the allowable months, a <code>ParseException</code>
+    will be thrown. For example, <code>"* * 31 Feb *"</code> will fail because no date will ever match
+    the 31st February!</li>
+  <li>The DOM and DOW fields cannot both be specified at the same time. One must always be set to '*'
+    otherwise a <code>ParseException</code> will be thrown.</li>
+  <li>Leap years and local daylight savings time are taken into account. Eg <code>"0 0 29 Feb *"</code>
+    will match midnight on the 29th February, ie only once every 4 years.</li>
+  <li>Currently the time used to match the cron expression against is always based on the local time
+    on the server. If there is demand support for specifying an alternate timezone may be added in a
+    future release.</li>
+</ul></p>
+</body>
+</html>

docs/download.html

+<html>
+<head>
+<title>OSCache Downloads</title>
+</head>
+
+<body bgcolor="#FFFFFF">
+
+<h3>Released Versions</h3>
+<p>The following versions of OSCache are currently available. All source and API docs are included in the
+  download.</p>
+<p>Please see the <a href="install.html">Installation Guide</a> for installation instructions.</p>
+<ul>
+  <li>OSCache 2.0 - <a href="https://oscache.dev.java.net/files/documents/629/1050/oscache_2_0_binary.zip">binary zip</a> |
+    <a href="https://oscache.dev.java.net/files/documents/629/1051/oscache_2_0_full.zip">source zip</a>
+    - September 22nd, 2003</li>
+  <li>OSCache 2.0 beta 2 - <a href="https://oscache.dev.java.net/files/documents/629/603/oscache_2_0_0b2.zip">zip</a>
+    - August 4th, 2003</li>
+  <li>OSCache 2.0 beta 1 - <a href="http://oscache.dev.java.net/files/documents/629/467/oscache_2_0_0b1.zip">zip</a>
+    - July 19th, 2003</li>
+  <li>OSCache 1.7.5 - <a href="http://prdownloads.sourceforge.net/opensymphony/oscache_1_7_5.zip">zip</a>
+    - January 8th, 2002</li>
+  <li>OSCache 1.7.2 - <a href="http://prdownloads.sourceforge.net/opensymphony/oscache_1_7_2_0.zip">zip</a>
+    - November 5th, 2001</li>
+  <li>OSCache 1.6.1 - <a href="http://prdownloads.sourceforge.net/opensymphony/oscache_1_6_1.zip">zip</a>
+    - September 17th, 2001</li>
+  <li>OSCache 1.2.1 - <a href="http://prdownloads.sourceforge.net/opensymphony/oscache_1_2_1.zip">zip</a>
+    - May 10th, 2001</li>
+  <li>OSCache 1.2 - <a href="http://prdownloads.sourceforge.net/opensymphony/oscache_1_2.zip">zip</a>
+    - March 28th, 2001</li>
+  <li>OSCache 1.1 - <a href="http://prdownloads.sourceforge.net/opensymphony/oscache_1_1.zip">zip</a>
+    - March 25th, 2001</li>
+  <li>OSCache 1.0 beta 0 - <a href="http://download.sourceforge.net/opensymphony/oscache-1.0beta0.zip">zip</a>
+    | <a href="http://download.sourceforge.net/opensymphony/oscache-1.0beta0.tar.gz">tar.gz</a>
+    - December 4th, 2000</li>
+</ul>
+
+<h3>CVS Access</h3>
+<p>The OSCache project is hosted at <a href="http://oscache.dev.java.net">http://oscache.dev.java.net</a>. You can
+browse the CVS tree <a href="http://oscache.dev.java.net/source/browse/oscache">here</a>. Instructions for checking
+the code out of CVS are available <a href="http://oscache.dev.java.net/servlets/ProjectSource">here</a>.</p>
+</body>
+</html>
+<html>
+<head>
+<title>OSCache FAQ</title>
+</head>
+
+<body bgcolor="#FFFFFF">
+<p><i>Got a question you'd like to ask? <a href="&#109;a&#105;&#108;&#116;&#111;:chris&#64;swebtec.&#99;&#111;&#109;">
+Ask us</a> and we'll add it to the FAQ.</i></p>
+
+<p><b>Questions</b></p>
+<ul>
+  <li><a href="#use">What can I use OSCache for exactly?</a></li>
+  <li><a href="#where">Where is the data cached?</a></li>
+  <li><a href="#objects">Can OSCache cache Java objects rather than portions
+     of JSP pages? I mean if I create a Product object, can I cache it and use it later
+     so that I don't have to fetch data again?</a></li>
+  <li><a href="#features">What other features does OSCache have?</a></li>
+  <li><a href="#examples">Can you give me some examples of how the OSCache
+     tags are used?</a></li>
+  <li><a href="#nested">Can OSCache tags be nested?</a></li>
+  <li><a href="#size">What control do you have over the cache size? I can imagine
+     the size of the in-memory cache getting very big. Is it possible to set a max cache
+     size and then remove the least-recently-used entries from the cache?</a></li>
+  <li><a href="#remove">How does OSCache decide which object to remove? What caching
+     algorithm does OSCache use?</a></li>
+  <li><a href="#clustering">How does OSCache's clustering work?</a></li>
+  <li><a href="#expire">What happens if I need to expire data in the cache?</a></li>
+  <li><a href="#group">Can you tell me more about grouping cache entries? How might this be
+     used?</a></li>
+  <li><a href="#api">I don't want to use the taglibs, I want to access OSCache directly
+     from within my application. Where do I start?</a></li>
+</ul>
+
+<ul>
+  <li><a href="#help">Where else can I go for help if I can't find an answer to my question here?</a></li>
+</ul>
+
+<p>&nbsp;</p>
+<p><a name="use"></a><b>What can I use OSCache for exactly?</b></p>
+
+<p>OSCache can be used on three different levels:
+<ul>
+  <li><b>JSP Caching</b> - The first and simplest approach is to use the supplied
+    taglibs to cache portions of JSP pages after the page has been rendered. This
+    sounds simple but it's remarkably powerful and useful for almost every JSP
+    application.</li>
+  <li><b>Request Caching</b> - OSCache comes with a filter that allows you to cache
+    entire HTTP responses - including dynamically generated images!</li>
+  <li><b>General-Purpose Cache</b> - You can also use OSCache as a general-purpose
+    caching solution by calling its API directly from your code. This allows arbitrary
+    Java objects to be cached, and provides more control over the cache's behaviour.
+    Note that <em>any</em> Java application can use OSCache in this manner; there is
+    no requirement for a web server to be present when calling the API directly.</li>
+</ul></p>
+
+<p>All three approaches can be mixed and matched within the same application.</p>
+
+<br>
+<p><a name="where"></a><b>Where is the data cached?</b></p>
+
+<p>Out of the box, OSCache is capable of caching data in memory (so it is very
+fast), and/or to disk (so your cache can be persistent across server restarts).
+Support is also provided for managing a cluster of caches across multiple
+servers.</p>
+<p>In addition to these capabilities, it is possible to plug in custom
+persistence code and custom event handlers, so you could easily extend OSCache
+to persist cached objects to say a database or an LDAP directory.</p>
+
+<br>
+<p><a name="objects"></a><b>Can OSCache cache Java objects rather than portions of JSP pages? I mean
+if I create a Product object, can I cache it and use it later so that I don't
+have to fetch data again?</b></p>
+
+<p>Yes, however to do this you will need to write code that talks to the
+OSCache API directly. The taglibs are currently only designed to cache
+rendered JSP content. This should hopefully not be too big a limitation since
+any creation or manipulation of java objects should generally be performed in
+beans or MVC action classes rather than JSP scriptlets anyway.</p>
+
+<br>
+<p><a name="features"></a><b>What other features does OSCache have?</b></p>
+
+<p>There is a full list of features in the <a href="features.html">Features</a>
+documentation.</p>
+
+<br>
+<p><a name="examples"></a><b>Can you give me some examples of how the OSCache tags are used?</b></p>
+  <i>Example 1:</i></p>
+<blockquote><tt><code> &lt;cache:cache time=&quot;600&quot;&gt;<br>
+  &nbsp; &nbsp; &lt;%= myBean.getTitle() %&gt;<br>
+  &lt;/cache:cache&gt; </code></tt></blockquote>
+<p> This will only access your EJB once every 10 minutes. Every other request
+  it will just serve the cached JSP content that was produced the first time (this
+  results in much faster page loading). </p>
+<p><i>Example 2:</i><br>
+</p>
+<blockquote><tt><code> &lt;cache:cache key=&quot;foobar&quot; scope=&quot;session&quot;&gt;<br>
+  &nbsp; &nbsp; &lt;%= myBean.getTitle() %&gt;<br>
+  &lt;/cache:cache&gt; </code></tt></blockquote>
+<p>This time the cache is keyed (you could have a programmatic key here too, like
+  &lt;%= foobarString %&gt;) and it's scoped by session. </p>
+<p>This is revolutionary as far as caching goes. You can now have cached content,
+  that's different for every user! No more full page caches with no dynamic content!</p>
+<p><i>Example 3 (a very powerful &amp; useful way to use the taglibs):</i></p>
+<blockquote><tt><code> &lt;cache:cache&gt;<br>
+  &nbsp; &nbsp; &lt;% try { %&gt;<br>
+  &nbsp; &nbsp; &nbsp; &nbsp; &lt;%= myBean.getTitle() %&gt;><br>
+  &nbsp; &nbsp; &lt;% } catch (Exception e) { %&gt;<br>
+  &nbsp; &nbsp; &nbsp; &nbsp; &lt;% application.log(&quot;Exception occurred in
+  myBean.getTitle(): &quot; + e); %&gt;<br>
+  &nbsp; &nbsp; &nbsp; &nbsp; &lt;cache:usecached /&gt;<br>
+  &nbsp; &nbsp; &lt;% } %&gt;<br>
+  &lt;/cache:cache&gt; </code></tt></blockquote>
+<p>If a RemoteException occurs trying to get the EJB title (for example the database
+  goes down) the cached content will be served so the user will not suspect a thing.
+  No error page as per a normal JSP application. What does this mean? It means greater
+  error tolerance in your JSP apps! </p>
+<p>One example of where this is useful - when our machine restarts, our app server
+  loads faster than the database server. No problem - because the cache is persistent,
+  it serves cached content while the database boots, then seamlessly kicks in
+  to the database for a cache refresh when the database is ready.</p>
+<p>See the <a href="tags.html">Tag Reference</a> and the example web application for further
+  taglib examples.</p>
+
+<br>
+<p><a name="nested"></a><b>Can OSCache tags be nested?</b></p>
+<p>You can't currently nest &lt;cache&gt; tags within one another - not that
+you'd probably want to. It is because of the cache object being placed in the
+page scope for use by programmers within the tag.</p>
+
+<p>We're not sure if anyone actually uses this so we might remove it to allow
+for tag nesting (presumably across includes or something).</p>
+
+<br>
+<p><a name="size"></a><b>What control do you have over the cache size? I can imagine the size of
+the in-memory cache getting very big. Is it possible to set a max cache size
+and then remove the least-recently-used entries from the cache?</b></p>
+
+<p>You can limit the memory cache by the number of objects that are cached.
+When an object is added to the cache and the limit is exceeded, another
+object will be removed from the cache to make room.</p>
+
+<p>Currently the disk cache can either be set to unlimited, or tied to the same
+size as the memory cache (ie, objects will be removed from the disk cache at
+the same time as they are removed from the memory cache. Depending on the
+useage patterns of your cache, restarting your application could mean that the
+disk cache might continue to grow). We understand that this is not ideal and
+there is room for improvement here. Stay tuned!</p>
+
+<br>
+<p><a name="remove"></a><b>How does OSCache decide which object to remove? What caching algorithm
+does OSCache use?</b></p>
+
+<p>The caching algorithm is configurable. OSCache currently ships with 3 different
+algorithms - <b>LRU</b> (Least Recently Used), <b>FIFO</b> (First In First
+Out), and <b>Unlimited</b>. Should one of those not prove suitable, it is also
+possible to specify a custom algorithm class.</p>
+
+<br>
+<p><a name="clustering"></a><b>How does OSCache's clustering work?</b></p>
+
+<p>The clustering is implemented as a listener that catches 'flush' events. These
+events are then broadcast across the network (using either the
+<a href="http://www.javagroups.com">JavaGroups</a> library or JMS) so that other nodes
+in the cluster can flush the relevant object(s) from their local cache. Note that
+for performance reasons, when objects are added to a cache they are <em>not</em>
+broadcast to other nodes. This means that each node in the cluster maintains their
+own relatively indedependent cache, yet still remains fresh.</p>
+
+<p>If this mechanism does not suit your requirements, you can always code up a
+different solution by writing a custom event handler.</p>
+
+<br>
+<p><a name="expire"></a><b>What happens if I need to expire data in the cache?</b></p>
+
+<p>Cache entries can be flushed explicitly in several ways:
+<ul>
+<li>Individual entries can be flushed by specifying the cache key of the entry
+to flush eg <code>&lt;cache:flush key=&quot;myKey&quot; scope=&quot;application&quot;/&gt;</code></li>
+<li>When adding an entry to the cache, it can optionally be placed into one or
+more groups. An entire group of entries can then be flushed by specifying the
+name of the group to flush. eg <code>&lt;cache:flush group=&quot;group1&quot; scope=&quot;application&quot;/&gt;</code></li>
+<li>A pattern can be specified; all keys that contain the supplied pattern will
+be flushed. eg <code>&lt;cache:flush pattern=&quot;menu&quot; scope=&quot;application&quot;/&gt;</code> will
+flush all keys that contain the string &quot;menu&quot;. (note that this approach
+is now deprecated. The cache grouping is more flexible and performs better than
+pattern flushing.)</li>
+</ul>
+In addition, cached data can be expired at retrieval time by specifying a maximum
+age for the data, or by indicating what dates and/or times the data should expire.
+See the <code>time</code>, <code>duration</code> and <code>cron</code> attributes
+of the <a href="tags.html#cache">&lt;cache&gt;</a> tag for more information.</p>
+
+<br>
+<p><a name="group"></a><b>Can you tell me more about grouping cache entries? How might this be
+used?</b></p>
+
+<p>This is a powerful feature that makes it easy to manage your cache content.
+Suppose you are rendering a website and the pages that you are caching depend
+on various factors. Perhaps they use various shared templates, some database
+content, and maybe some of them depend on an external data feed. By creating
+a cache group for each of these factors, each cached page can be placed into
+the group(s) that the page is dependent on. Then when say an external datafeed
+is updated it is trivial to flush all pages that depend on that datafeed.</p>
+<p>For example:</p>
+
+inside displayProduct.jsp:
+
+<blockquote><tt><code>...<br>
+&lt;cache:cache key=&quot;myKey1&quot; groups=&quot;product100,datafeed&quot;&gt;<br>
+  &nbsp; &nbsp; &lt;%= myProductBean.getProduct(100).getName() %&gt;<br>
+  &nbsp; &nbsp; &lt;%= myDatafeedBean.getDataFeed().getTotal() %&gt;<br>
+  &lt;/cache:cache&gt;<br>
+...
+</code></tt></blockquote>
+
+inside updateDatafeed.jsp:
+
+<blockquote><tt><code>...<br>
+&lt;%= myDatafeedBean.refreshDatafeed() %&gt;<br><br>
+&lt;%-- Flush all cache entries that depend on the datafeed --%&gt;<br>
+&lt;cache:flush group=&quot;datafeed&quot; scope=&quot;application&quot;&gt;<br>
+...
+</code></tt></blockquote>
+
+<br>
+<p><a name="api"></a><b>I don't want to use the taglibs, I want to access OSCache directly from within
+my application. Where do I start?</b></p>
+
+<p>We'd suggest the best place to start would be to look at the <code>GeneralCacheAdministrator</code>
+class. It provides a simple wrapper for a single cache instance and should give you all
+the basic functionality you need. If you want to work with multiple caches or manipulate
+your cache beyond what <code>GeneralCacheAdministrator</code> provides, consider either
+writing your own administrator class using GeneralCacheAdministrator as a starting point,
+or just create and use the Cache class directly. See the Javadocs for more information.</p>
+
+<br>
+<p><a name="help"></a><b>Where else can I go for help if I can't find an answer to my question here?</b></p>
+
+<p>The best place to try is on the OSCache <a href="http://sourceforge.net/mail/?group_id=9890">mailing list</a>.
+It reaches a wide audience and is your best chance of getting a fast response. Remember to search the archives
+first to see if your question has already been answered.</p>
+
+<br>
+<p>
+<i>Got a question you'd like to ask? <a href="&#109;a&#105;&#108;&#116;&#111;:chris&#64;swebtec.&#99;&#111;&#109;">Ask us</a>
+and we'll add it to the FAQ.</i>
+</body>
+
+</html>

docs/features.html

+<html>
+<head>
+<title>OSCache Features</title>
+</head>
+
+<body bgcolor="#FFFFFF">
+
+<p><b>Fast in-memory caching</b></p>
+<ul>
+  <li>OSCache allows you to <i>execute dynamic content periodically</i> (eg every
+    30 minutes) rather than every request and store the result in memory. Each
+    further request is served directly from the memory cache, resulting in dramatic
+    speed increases.</li>
+  <li><i> The cache is keyed programmatically</i>. This means you can calculate a
+    cache key that works for your situation. For example an ecommerce site might use
+    product ID as keys, or content site might use an article date and article ID combination.</li>
+  <li>The cache is stored in standard scopes that any JSP programmer is familiar with
+    (application or session). The session scope allows you to have <i>different
+    cached content per user</i>. This is one unlike any other caching system we've
+    ever seen.</li>
+</ul>
+
+<p><b>Persistent on-disk caching</b></p>
+<ul>
+  <li>OSCache can also write the cache to disk. This provides <i>caching across
+    server restarts</i>, and <i>caching of datasets that do not fit into memory</i>.
+    Caching can be configured to use memory or file caching, or a combination of
+    both.</li>
+  <li>If you want to persist the cache to somewhere other than disk, you can plug in a
+    custom PersistenceListener. This allows you to persist the cache to anywhere (for
+    example to a database via JDBC or to LDAP via JNDI).</li>
+  <li>When using both disk caching and memory caching. It is possible to limit the
+    cache size to avoid using too much memory but let disk cache unlimited,
+    resulting in browser style complementary disk cache. When cached objects are removed
+    from memory, they are still on disk. If the item is needed again and it is not
+    expired the cache file will be used. This also gives fault tolerance if the
+    server crashes.<br>
+  </li>
+</ul>
+
+<p><b>Excellent Performance</b></p>
+<ul>
+  <li>Written with performance in mind.</li>
+  <li>Mulitple cache requests can be handled concurrently.</li>
+  <li>Only one requesting thread needs to update an expired cache entry even if
+    multiple threads are requesting it simultaneously. Other threads can be
+    configured to either receive the recently-expired object, or block until the
+    cached object is updated. Similarly, when a new entry is being added to the
+    cache, other threads requesting that entry will block until it is ready rather
+    than run off and race to build the same object. In a high load environment
+    this can provide enormous performance benefits.</li>
+  <li>Automatically takes advantage of JRE 1.4 or higher if available.</li>
+</ul>
+
+<p><b>Clustering support</b></p>
+<ul>
+  <li>OSCache can easily be configured to cluster across multiple boxes. This
+    provides both scalability and failover support without any changes required
+    in your caching code.
+  </li>
+</ul>
+
+<p><b>Flexible Caching System</b></p>
+<ul>
+  <li>OSCache allows you to cache portions of <i>JSP pages</i>, <i>arbitrary Java objects</i>,
+    and even <i>entire servlet responses</i>.</li>
+  <li>Cache capacity can be set allowing you to limit the number of cached objects.</li>
+  <li>Multiple caching algorithms are supported such as LRU (Least Recently Used),
+    FIFO (First In First Out), or unlimited. It is also possible to plug in your own
+    custom algorithm.</li>
+  <li>You are given a huge amount of control over the way cached objects expire. Objects
+    can be cached indefinitely, expired once they reach a certain age, or expired based
+    on a cron expression. Programmatic flushing is also possible, and if that is still not
+    enough pluggable RefreshPolicies allow custom refresh strategies.
+  <li>Cached objects can be grouped together however you like, allowing for powerful
+    management of cached data. This is an extremely useful feature that is far more powerful
+    than what other caching solutions typically offer (such as the flushing of cache keys
+    that match a particular pattern).</li>
+  <li>Fully event driven! OSCache fires events for various happenings 'under
+    the hood' such as cache entry events (adding, updating, flushing and removing)
+    and cache accesses (hit, stale hit and miss). It is easy to add your own event
+    handlers.</li>
+  <li>Multiple caches can be created, each with their own unique configuration.</li>
+</ul>
+
+<p><b>Simple JSP Tag Library</b></p>
+<ul>
+  <li>The tag library to perform and control the caching is very simple. See
+    the <a href="tags.html">Tag Reference</a> for more information.</li>
+</ul>
+
+<p><b>Caching Filter</b></p>
+<ul>
+  <li>A Servlet 2.3 Filter allows for caching of <i>entire pages</i> and
+  <i>generated binary files</i> (like dynamically created images or PDF files).
+  </li>
+</ul>
+
+<p><b>Comprehensive API</b></p>
+<ul>
+  <li>For the ultimate control, OSCache can be used through its straightforward API. You can
+    instantiate, configure and control multiple caches programmatically. It would be possible
+    for example to create one small in-memory cache that held currency conversion rates and
+    was updated daily at 2am, while another cache could be purely disk based and used for
+    holding dynamically created images.</li>
+</ul>
+
+<p><b>Exception Handling</b></p>
+<ul>
+  <li>OSCache provides a way for your site to <i>gracefully tolerate errors</i>.
+    This is not error prevention, rather if an error occurs it should not stop
+    your site from functioning. For example if your database goes down, normally
+    your product descriptions will not be browsable. Using OSCache you can cache
+    those descriptions so you can still browse them.</li>
+</ul>
+
+<p><b>Cache Flushing</b></p>
+<ul>
+  <li>Flushing of caches can be controlled via JSP Tags, so these functions can
+    easily be built into your administration interface.</li>
+  <li>There is programmatic control over what caches are flushed (eg all caches
+    or just a particular scope).</li>
+  <li>Cached objects can be expired in a number of ways. Objects can be told to expire
+    once they reach a certain age, or, through the use of cron expressions, on particular
+    dates and/or times (eg it is trivial to make an object expire every weekday
+    at 3am). If this is not enough, you can expire objects programmatically as required,
+    or plug in your own custom RefreshPolicy class that can dynamically decide when
+    an object should be flushed.
+    </li>
+  <li>Entire groups of objects can be easily flushed from the cache. For example
+    suppose you were caching product data as well as entire pages of your website.
+    When a product was updated, you could flush not just the product object but
+    also all the pages that contain information about that product. No more waiting
+    for the cached objects to expire before the updated content shows up on your site!</li>
+</ul>
+
+<p><b>Portable caching</b></p>
+<ul>
+  <li>Pure Java, this means it is platform independent. </li>
+  <li>OSCache is compliant with Servlet 2.3 and JSP 1.2 standards, which means
+    it should work in the latest generation of servlet containers and application
+    servers.</li>
+</ul>
+
+<p><b>i18n Aware</b></p>
+<ul>
+  <li>The caching is i18n aware and supports all encodings.</li>
+</ul>
+
+<p><b>Solid Reputation</b></p>
+<ul>
+  <li>Thousands of downloads, hundreds of users on the
+    <a href="http://sourceforge.net/mail/?group_id=9890">mailing list.</a></li>
+  <li>Comprehensive <a href="http://www.junit.org">JUnit</a> test suite
+    that covers every aspect of OSCache, including a web stress test and
+    various concurrent cache access scenarios. To back this up, the kind
+    folks at <a href="http://www.cortexebusiness.com.au/">Cortex</a> have
+    supplied us with a <a href="http://www.thecortex.net/clover/">Clover</a>
+    license to provide detailed code coverage analysis of our unit tests.</li>
+  <li>We have solid <a href="http://jira.opensymphony.com">issue tracking</a>
+    using <a href="http://www.atlassian.com/software/jira">JIRA</a> to keep
+    track of any feature requests, bug reports and development progress.
+    JIRA is provided courtesy of <a href="http://www.atlassian.com">Atlassian</a>.</li>
+</ul>
+</body>
+</html>
+<html>
+<head>
+<title>Caching Content with the CacheFilter</title>
+</head>
+
+<body bgcolor="#FFFFFF">
+
+<p><b>OSCache</b> comes with a servlet filter that enables you to transparently cache entire pages
+of your website, and even binary files. Caching of binary files is extremely useful when they are
+generated dynamically, eg PDF files or images.</p>
+
+<p>To configure the filter, add something like the following to your web.xml file (obviously you
+will want to set the URL pattern to match only the content you want to cache; this example will
+cache all JSP pages):
+
+<pre><code>
+   &lt;filter&gt;
+      &lt;filter-name&gt;CacheFilter&lt;/filter-name&gt;
+      &lt;filter-class&gt;com.opensymphony.oscache.web.filter.CacheFilter&lt;/filter-class&gt;
+   &lt;/filter&gt;
+   &lt;filter-mapping&gt;
+      &lt;filter-name&gt;CacheFilter&lt;/filter-name&gt;
+      &lt;url-pattern&gt;*.jsp&lt;/url-pattern&gt;
+   &lt;/filter-mapping&gt;
+</code></pre>
+
+<p>The default duration is one hour and the default scope for the cache is application scope. You
+can change these settings using initialization parameters. The <code>time</code> parameter sets
+the cache time (in seconds), while the <code>scope</code> parameter lets you set the scope. Valid
+values for the scope are <code>application</code> and <code>session</code>.</p>
+
+<p>As an example, the following settings would cache content for 10 minutes in session scope:
+<pre><code>
+   &lt;filter&gt;
+      &lt;filter-name&gt;CacheFilter&lt;/filter-name&gt;
+      &lt;filter-class&gt;com.opensymphony.oscache.web.filter.CacheFilter&lt;/filter-class&gt;
+      &lt;init-param&gt;
+         &lt;param-name&gt;time&lt;/param-name&gt;
+         &lt;param-value&gt;600&lt;/param-value&gt;
+      &lt;/init-param&gt;
+      &lt;init-param&gt;
+         &lt;param-name&gt;scope&lt;/param-name&gt;
+         &lt;param-value&gt;session&lt;/param-value&gt;
+      &lt;/init-param&gt;
+   &lt;/filter&gt;
+</code></pre></p>
+
+<p>Note that the filter will only cache content that has a status of 200 (<code>HttpServletResponse.SC_OK</code>).</p>
+</body>
+</html>
+<html>
+<head>
+<title>OSCache 2.0 Overview</title>
+</head>
+<body bgcolor="#FFFFFF">
+
+<p><b>OSCache</b> is a widely used, high performance J2EE caching solution.</p>
+<h3>The Problems Solved</h3>
+<p><b>OSCache</b> solves fundamental problems for dynamic websites:</p>
+<ul>
+  <li><b>Caching Dynamic Content</b> - Dynamic content must often be executed in some form each
+  	request, but sometimes that content doesn't change every request. Caching the whole page does
+  	not help because <i>sections</i> of the page change every request.
+    <ul>
+      <li><b>OSCache</b> solves this problem by providing a means to cache sections of JSP pages.</li>
+    </ul>
+  </li>
+  <li><b>Caching Binary Content</b> - Generated images and PDFs can be very costly in terms
+  	of server load.
+    <ul>
+      <li><b>OSCache</b> solves this problem through a Servlet 2.3 CachingFilter which can cache any
+      	URI (such as an entire page or a generated image/PDF)</li>
+    </ul>
+  </li>
+  <li><b>Error Tolerance</b> - If one error occurs somewhere on your dynamic page, chances are the
+  	whole page will be returned as an error, even if 95% of the page executed correctly.
+    <ul>
+      <li><b>OSCache</b> solves this problem by allowing you to serve the cached content in the event
+      	of an error, and then reporting the error appropriately.</li>
+    </ul>
+  </li>
+</ul>
+
+<h3>Brief Feature List</h3>
+<p>In addition to it's servlet-specific features, <b>OSCache</b> can be used as a generic caching
+  solution for <i>any</i> Java application. A few of its generic features include:</p>
+<ul>
+  <li><b>Caching of Arbitrary Objects</b> - You are not restricted to caching portions of JSP pages
+    or HTTP requests. Any Java object can be cached.</li>
+  <li><b>Comprehensive API</b> - The <b>OSCache</b> API gives you full programmatic control over all of
+    <b>OSCache's</b> features.</li>
+  <li><b>Persistent Caching</b> - The cache can optionally be disk-based, thereby allowing expensive-to-create
+    data to remain cached even across application restarts.</li>
+  <li><b>Clustering</b> - Support for clustering of cached data can be enabled with a single configuration
+    parameter. No code changes required.</li>
+  <li><b>Expiry of Cache Entries</b> - You have a huge amount of control over how cached objects expire,
+    including pluggable RefreshPolicies if the default functionality does not meet your requirements.</li>
+</ul>
+
+<p>We encourage you to take a look at the full <a href="features.html">feature list</a> to see what else
+   <b>OSCache</b> has to offer.</p>
+
+<p>Other documentation:</p>
+<ul>
+  <li><b><a href="features.html">Feature List</a></b> - Details on <b>OSCache</b>'s features and how they are best used</li>
+  <li><b><a href="requirements.html">Requirements</a></b> - What is required to run <b>OSCache</b></li>
+  <li><b><a href="changelog.html">Change Log</a></b> - See what's new in the latest version of <b>OSCache</b></li>
+  <li><b><a href="faq.html">FAQ</a></b> - Frequently Asked Questions about <b>OSCache</b></li>
+  <li><b><a href="install.html">Installation Guide</a></b> - How to install <b>OSCache</b> and where to get it.</li>
+  <li><b><a href="configuration.html">Configuration</a></b> - Configuration options for <b>OSCache</b>.</li>
+  <li><b><a href="filter.html">Caching Content with the CacheFilter</a></b> - How to configure OSCache to cache entire servlet responses.</li>
+  <li><b><a href="tags.html">JSP Tags</a></b> - Detailed documentation on <b>OSCache</b>'s tags and how to use them.</li>
+  <li><b><a href="clustering.html">Clustering OSCache</a></b> - How to use <code>OSCache</code> in a cluster.</li>
+  <li><b><a href="cron.html">Cron Expressions</a></b> - How to use the cron expression syntax to expire content.</li>
+  <li><b><a href="api">JavaDoc API</a></b> - The <b>OSCache</b> API documentation in JavaDoc format.</li>
+</ul>
+
+</body>
+
+</html>

docs/install.html

+<html>
+<head>
+<title>OSCache Installation Guide</title>
+</head>
+
+<body bgcolor="#FFFFFF">
+<p>This installation guide shows you how to configure OSCache for use inside your JSP pages. It assumes
+  you have downloaded the latest version (<a href="download.html">available here</a>).</p>
+<p>If you intend to use OSCache via the API rather than via the taglibs, these instructions do not apply.
+  Just make sure oscache.jar is somewhere on your application's classpath.</p>
+<h3>Extraction Steps</h3>
+<p>Extract the downloaded file to a directory of your choosing. </p>
+<p>Put the <code>/oscache.jar</code> file in the <code>/WEB-INF/lib</code> directory</p>
+<p>Make sure commons=logging.jar is on your classpath (normally this also means putting it in
+  <code>/WEB-INF/lib</code>.</p>
+<p>If you are using JDK 1.3.x it is optional, but strongly recommended, to add commons-collections.jar
+  to your classpath. OSCache will use this to provide a significant speed increase. (Note that with
+  JDK 1.4 and higher, commons-collections.jar will not be used - the 1.4 implementation is faster
+  still).</p>
+<p>Put the <code>/src/oscache.properties</code> file in the <code>/WEB-INF/classes</code>
+  directory and edit the properties contained within it (for example if you want
+  disk caching, configure the persistence listener and edit the <code>cache.path</code> property
+  to point to where you want the cache files stored on disk). See the
+  <a href="configuration.html">Configuration Guide</a> for further details on what options are
+  available.</p>
+<p>Remember to escape any \ characters in Windows paths - ie if you want cache
+  files to go in c:\cachedir, the cache.path property should be set to c:\\cachedir.</p>
+<p>Put the <code>/src/META-INF/taglib.tld</code> file in your <code>/WEB-INF/classes</code>
+  directory. You can rename this to <code>oscache.tld</code> if you have any conflicting
+  tld files.</p>
+<p>Your directory structure should now look something like this:</p>
+<BLOCKQUOTE> <TT> <CODE> $WEB_APPLICATION\WEB-INF\lib\oscache.jar<br/>
+  $WEB_APPLICATION\WEB-INF\classes\oscache.properties<br/>
+  $WEB_APPLICATION\WEB-INF\classes\taglib.tld<br/>
+  </CODE> </TT> </BLOCKQUOTE>
+<h3>Installation Steps</h3>
+<p>Add the following to your web.xml file</p>
+<BLOCKQUOTE>
+  <p><TT> <CODE> &lt;taglib&gt;<br>
+    &nbsp; &nbsp; &nbsp; &lt;taglib-uri&gt;oscache&lt;/taglib-uri&gt;<br>
+    &nbsp; &nbsp; &nbsp; &lt;taglib-location&gt;/WEB-INF/classes/taglib.tld&lt;/taglib-location&gt;<br>
+    &lt;/taglib&gt;
+    </CODE></TT> </p>
+</BLOCKQUOTE>
+<p>Now add the appropriate <a href="tags.html">tags</a> to your JSP files and you're done.</p>
+<p>It should work properly. <a href="../contact.html">Tell us</a> on the mailing list if it doesn't work in your container.</p>
+<h3>Logging and Debugging</h3>
+<p>OSCache now uses <a href="http://jakarta.apache.org/commons/logging.html">Jakarta Commons Logging</a>
+  for logging any messages. Please see the Commons Logging documentation for details on logging
+  configuration.</p>
+<p>Note that OSCache has been compiled with debugging information enabled so you should be able to
+  use your favourite debugger to step through the source if need be.</p>
+</body>
+</html>

docs/navpanel.jsp

+<p>
+<h3>About</h3>
+<a href="<%= request.getContextPath() %>/oscache/">Overview</a> <br>
+<a href="<%= request.getContextPath() %>/oscache/features.html">Feature List</a><br>
+<a href="<%= request.getContextPath() %>/oscache/download.html">Download</a><br>
+<a href="<%= request.getContextPath() %>/oscache/changelog.html">Changelog</a><br>
+<a href="<%= request.getContextPath() %>/oscache/requirements.html">Requirements</a><br>
+</p>
+
+<p>
+<h3>Documentation</h3>
+<a href="<%= request.getContextPath() %>/oscache/install.html">Installation Guide</a><br>
+<a href="<%= request.getContextPath() %>/oscache/faq.html">FAQ</a><br>
+<a href="<%= request.getContextPath() %>/oscache/configuration.html">Configuration</a><br>
+<a href="<%= request.getContextPath() %>/oscache/tags.html">Tag Reference</a><br>
+<a href="<%= request.getContextPath() %>/oscache/filter.html">The Caching Filter</a><br>
+<a href="<%= request.getContextPath() %>/oscache/cron.html">Cron Expressions</a><br>
+<a href="<%= request.getContextPath() %>/oscache/clustering.html">Clustering</a><br>
+<a href="<%= request.getContextPath() %>/oscache/api/">API Docs</a>
+</p>
+
+<p>
+<h3>Services</h3>
+<b>JIRA</b><br>
+- <a href="http://jira.opensymphony.com/secure/BrowseProject.jspa?id=10001">Issue Overview</a><br>
+- <a href="http://jira.opensymphony.com/secure/BrowseProject.jspa?id=10001&report=roadmap">Roadmap</a><br>
+- <a href="http://jira.opensymphony.com/secure/BrowseProject.jspa?id=10001&report=changelog">Changelog</a><br>
+<b>Wiki</b><br>
+- <a href="http://wiki.opensymphony.com/space/OSCache">OSCache page</a>
+</p>
+
+<p>
+
+<h3>Sponsor Companies</h3>
+These companies have contributed a lot to OSCache and we thank them.<br>
+
+<a href="http://www.pyxis-tech.com"><img src="<%= request.getContextPath() %>/oscache/pyxis-box-sponsor.gif" width="120" height="60" border="0" alt="Pyxis Technologies" vspace="2"></a><br>
+<a href="http://www.atlassian.com"><img src="<%= request.getContextPath() %>/oscache/atlassian-sponsor.gif" width="120" height="60" border="0" alt="Atlassian" vspace="2"></a>
+
+</p>
Add a comment to this file

docs/pyxis-box-sponsor.gif

Added
New image

docs/requirements.html

+<html>
+<head>
+<title>OSCache Requirements</title>
+</head>
+
+<body bgcolor="#FFFFFF">
+<p><b>OSCache</b> can be used directly to provide caching for any Java application.
+Using the OSCache tag library requires Servlet 2.2 and JSP 1.2 support to run properly.
+<p>So far it has been tested in the following application servers and web containers:</p>
+<ul>
+  <li><a href="http://www.orionserver.com">OrionServer</a> (version 1.4.0 and
+    above)</li>
+  <li><a href="http://www.macromedia.com">Macromedia JRun</a> (version 3.0 and
+    above)</li>
+  <li><a href="http://www.weblogic.com">BEA Weblogic</a> (should work on version
+    5.x and above)</li>
+  <li><a href="http://www.ibm.com/websphere">IBM Websphere</a> (tested on version
+    5.0)</li>
+  <li><a href="http://www.ibm.com/websphere">Silverstream</a> (tested on version
+    3.7.4)</li>
+  <li><a href="http://www.caucho.com">Caucho Resin</a> (version 1.2.3) - thanks
+    to <a href="mailto:sami.siren@sonera.inet.fi">Sami Siren</a> for this test</li>
+  <li><a href="http://jakarta.apache.org/tomcat">Tomcat</a> (version 4.0 and above)</li>
+</ul>
+<p>This does not mean it will not run on other servers! It should run on any specification
+  compliant container. If you have run OSCache successfully in other servers, please
+  <a href="&#109;a&#105;&#108;&#116;&#111;:chris&#64;swebtec.&#99;&#111;&#109;">let
+  us know</a> and we'll add to this list.</p>
+<p>The Caching Filter (for caching entire pages, and binary content such as GIFs
+  and PDFs) requires Servlet 2.3 support. It is known to work on Orion, Weblogic
+  and Tomcat 4.0.</p>
+<p>OSCache is compatible with JRE 1.3 and higher. For best performance, JRE 1.4.x
+  or higher should be used.</p>
+<p>&nbsp;</p>
+</body>
+</html>
+<html>
+<head>
+<title>OSCache Tag Reference</title>
+</head>
+
+<body bgcolor="#FFFFFF">
+<p><b>OSCache</b> comes with a JSP tag library that controls all its major functions. The tags
+  are listed below with descriptions, attributes and examples of use.</p>
+<p>For instructions on installing OSCache in a web application, see the
+  <a href="install.html">Installation Guide</a>.</p>
+<p>The tags are:</p>
+<ul>
+  <li><a href="#cache">cache</a> - The main caching tag</li>
+  <li><a href="#usecached">usecached</a> - A nested tag to force using a cached version.</li>
+  <li><a href="#flush">flush</a> - To flush caches programmatically.</li>
+</ul>
+<p>For all listed attributes, <font color="#CC0000">req</font> means it that attribute
+  is required and any value in [] is a default value. All attributes can accept runtime
+  expressions.</p>
+<p>From the title of the tag you can see whether or not the tag has a body.</p>
+<ul>
+  <li>&lt;tag&gt;&lt;/tag&gt; tags always have a body</li>
+  <li>&lt;tag /&gt; does not have a body </li>
+  <li>&lt;tag /&gt;&lt;/tag&gt; can have a body or not depending on the circumstances.</li>
+</ul>
+<h3><br>
+  <a name="cache"></a>&lt;cache&gt;&lt;/cache&gt;</h3>
+<p><b>Description:</b></p>
+<blockquote>
+  <p>This is the main tag of OSCache. The body of the tag will be cached according to the
+    attributes specified. The first time a cache is used the body content is executed and
+    cached.</p>
+  <p>Each subsequent time the tag is run, it will check to see if the cached content is stale.
+    Content is considered stale due to one (or more) of the following being true:
+    <ul>
+      <li>The cached body content has been in the cache for longer than the time specified
+        by the time or duration attribute.</li>
+      <li>The cron attribute matches a date/time that is more recent than the time the body
+        content was originally cached.</li>
+      <li>The scope the body content is cached in was flushed since the content was originally
+        cached.</li>
+    </ul>
+  </p>
+  <p>If the cached body content is stale, the tag will execute the body again and recache the
+    new body content. Otherwise it will serve the cached content and the body will be skipped
+    (resulting in a large speed increase).</p>
+</blockquote>
+<p><b>Attributes:</b></p>
+<ul>
+  <li><b>key</b> - [The request URI + query string] - The cache key, any string.
+    This should be unique for the given scope since duplicate keys will map to the same cache
+    entry. The default value uses an escaped version of the URI and query string of the current
+    page.<br/>It is possible to specify multiple cache tags in the same page without specifying