Update of /cvsroot/opensymphony/website/web/oscache
In directory sc8-pr-cvs1:/tmp/cvs-serv22445/web/oscache
Modified Files:
cron.jsp features.jsp install.jsp tags.jsp
Log Message:
- fixed some broken links caused by the .html -> .jsp conversion.
- improved the cron documentation.
Index: cron.jsp
===================================================================
RCS file: /cvsroot/opensymphony/website/web/oscache/cron.jsp,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- cron.jsp 27 Jul 2003 14:33:43 -0000 1.1
+++ cron.jsp 13 Aug 2003 16:17:10 -0000 1.2
@@ -1 +1 @@
-<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!</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>
<%@ include file="navpanel.jsp" %>
</body>
</html>
\ No newline at end of file
+<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>
<%@ include file="navpanel.jsp" %>
</body>
</html>
\ No newline at end of file
Index: features.jsp
===================================================================
RCS file: /cvsroot/opensymphony/website/web/oscache/features.jsp,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- features.jsp 27 Jul 2003 14:33:43 -0000 1.1
+++ features.jsp 13 Aug 2003 16:17:10 -0000 1.2
@@ -1 +1 @@
-<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>.
</ul>
<%@ include file="navpanel.jsp" %>
</body>
</html>
\ No newline at end of file
+<html>
<head>
<title>OSCache Features</title>
</head>
<body bgcolor="#FFFFFF">
<p><>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.jsp">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>.
</ul>
<%@ include file="navpanel.jsp" %>
</body>
</html>
\ No newline at end of file
Index: install.jsp
===================================================================
RCS file: /cvsroot/opensymphony/website/web/oscache/install.jsp,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- install.jsp 27 Jul 2003 14:33:43 -0000 1.1
+++ install.jsp 13 Aug 2003 16:17:10 -0000 1.2
@@ -1 +1 @@
-<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.jsp">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>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, edit the <code>cache.path</code> property to point to where you
want the cache files stored on disk). See the <a href="configuration.jsp">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 property should be 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> <taglib><br>
<taglib-uri>oscache</taglib-uri><br>
<taglib-location>/WEB-INF/classes/taglib.tld</taglib-location><br>
</taglib>
</CODE></TT> </p>
</BLOCKQUOTE>
<p>Now add the appropriate <a href="tags.jsp">tags</a> to your JSP files and
you're done.</p>
<p>It should work properly. <a href="../contact.jsp">Tell us</a> on the mailing list if it doesn't work in your container.</p>
<h3>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.
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>
<%@ include file="navpanel.jsp" %>
</body>
</html>
\ No newline at end of file
+<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.jsp">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>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, edit the <code>cache.path</code> property to point to where you
want the cache files stored on disk). See the <a href="configuration.jsp">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 property should be 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> <taglib><br>
<taglib-uri>oscache</taglib-uri><br>
<taglib-location>/WEB-INF/classes/taglib.tld</taglib-location><br>
</taglib>
</CODE></TT> </p>
</BLOCKQUOTE>
<p>Now add the appropriate <a href="tags.jsp">tags</a> to your JSP files and
you're done.</p>
<p>It should work properly. <a href="../contact.jsp">Tell us</a> on the mailing list if it doesn't work in your container.</p>
<h3>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.
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>
<%@ include file="navpanel.jsp" %>
/body>
</html>
\ No newline at end of file
Index: tags.jsp
===================================================================
RCS file: /cvsroot/opensymphony/website/web/oscache/tags.jsp,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- tags.jsp 27 Jul 2003 14:33:43 -0000 1.1
+++ tags.jsp 13 Aug 2003 16:17:10 -0000 1.2
@@ -1 +1 @@
-<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.jsp">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><tag></tag> tags always have a body</li>
<li><tag /> does not have a body </li>
<li><tag /></tag> can have a body or not depending on the circumstances.</li>
</ul>
<h3><br>
<a name="cache"></a><cache></cache></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
keys - in this situation an index is appended to the key of subsequent tags. However this
usage is discouraged since if the flow of the page is inconsistent, or cache tags are nested,
the indicies will potentially change each time the page is executed, resulting in seemingly
jumbled cache entries.</li>
<li><b>scope</b> - [application] - The scope of this cache (valid values are
"application" and "session").</li>
<li><b>time</b> - [3600] The amount of time to cache this content for (in seconds).
(Default is 3600 seconds, one hour). Supplying a negative value for this attribute means
that the content never expires.</li>
<li><b>duration</b> - [] - The duration of this cache (this attribute is an
alternative to <b>time</b>). duration can be specified using Simple Date Format
or ISO-8601 date format.</li>
<li><b>cron</b> - [] - A cron expression that determines when this cached content will expire.
This allows content to be expired at particular dates and/or times, rather than once a cache
entry reaches a certain age. See <a href="cron.html">Cron Expressions</a> to read more about
this attribute.</li>
<li><b>refresh</b> - [false] - A boolean. If true, the cache will be refreshed regardless of
whether it is considered stale or not. This enables you to decide at runtime whether or not
to rebuild the content.</li>
<li><b>mode</b> - [] - Setting this to "silent" will prevent the body of the tag from
being written to the output stream. This may be useful if you want to preload the cache with
content without actually displaying that content to the user.</li>
<li><b>groups</b> - [] - A comma-delimited list of group names can be provided. This allows
cache entries to be grouped according to your needs. Grouping is useful when you have cached
content that depends on other parts of your application or data - when that dependency changes,
flushing the relevant group will cause all cache entries in that group to be expired.</li>
<li><b>language</b> - [] - The ISO-639 language code to distinguish different content cached
under an otherwise identical key. This is useful on a multilingual site where the same JSP
code is used to render content in different languages depending on the current user's
preferences.</li>
<li><b>refreshpolicyclass</b> - [] - A fully-qualified classname that extends
<code>com.opensymphony.oscache.web.WebEntryRefreshPolicy</code>. This allows you to
programmatically determine whether cached content should be exipired.</li>
<li><b>refreshpolicyparam</b> - [] - Any arbitrary parameters that you need to pass through to
the refreshpolicyclass. Specifying this attribute without specifying a refreshpolicyclass
will have no effect.</li>
</ul>
<p><b>Examples:</b></p>
<blockquote>
<p>This will cache the JSP content using the current URI as a key (which means this must be
the only cache tag on the page to work).</p>
<p><code><cache:cache><br>
... some jsp content ...<br>
</cache:cache> </code></p>
<p>This will cache the content with a constant key in the user's session scope.
Any page that uses this key will access one shared cache.</p>
<p><code><cache:cache key="foobar" scope="session"><br>
... some jsp content ...<br>
</cache:cache> </code></p>
<p>This will cache the content with a programmatic key (here a product ID) for
30 minutes. It will also refresh if the variable <code>needRefresh</code>
is true.</p>
<p><code><cache:cache key="<%= product.getId() %>" time="1800"
refresh="<%= needRefresh %>"><br>
... some jsp content ...<br>
</cache:cache> </code></p>
<p>This will cache the content with a programmatic key, expiring it every morning at 2am.
It will also refresh if the variable <code>needRefresh</code> is true.</p>
<p><code><cache:cache key="<%= product.getId() %>" cron="0 2 * * *"
refresh="<%= needRefresh %>"><br>
... some jsp content ...<br>
</cache:cache> </code></p>
<p>Suppose we had a dynamic list of categories that we pull from a database, and we also store
currency exchange rates that get updated occasionally by calling a webservice. Suppose also that
we have some content that displays information about both the categories and the current exchange
rate values. The following example caches the body content and assigns it to two cache groups,
"currencyData" and "categoryList". When the exchange rates or the category
list is updated, the appropriate group can be flushed causing this content (along with any other
content associated with that group) to be exipired and then rebuilt the next time the page
is processed:</p>
<p><code><cache:cache key="<%= product.getId() %>" time="-1"
group="currencyData, categories"><br>
... display category list ...<br>
... display currency information ...<br>
</cache:cache> </code></p>
</blockquote>
<h3><br>
<a name="usecached"></a><usecached /></h3>
<p><b>Description:</b></p>
<blockquote>
<p>This tag is nested within a <cache> tag and tells its parent whether
or not to use the cached version.</p>
</blockquote>
<p><b>Attributes:</b></p>
<ul>
<li><b>use</b> - [true] - A boolean that tells the tag whether or not to use the cached
version. (true = use cached version). This is useful for programmatic control of the cache.</li>
</ul>
<p><b>Example:</b></p>
<blockquote>
<p>This is a good example of error tolerance. If an exception occurs, the cached
version of this content will be output instead.</p>
<p><code><cache:cache></code><code><br>
<% try { %><br>
... some jsp content ...<br>
<% } catch (Exception e) { %><br>
<cache:usecached /><br>
<% } %><br>
</cache:cache> </code></p>
</blockquote>
<h3><br>
<a name="flush"></a><flush /></h3>
<p><b>Description:</b></p>
<blockquote>
<p>This tag is used to flush caches at runtime. It is especially useful because
it can be coded into the administration section of your site so that admins
can decide when to flush the caches. </p>
</blockquote>
<p><b>Attributes:</b></p>
<ul>
<li><b>scope</b> - [all] - This decides what scope will be flushed. Valid values
are "application", "session" and null. A null scope will
flush all caches, regardless of their scope. </li>
<li><b>key</b> - [] - When a key and a scope are both given, just that single cache
entry will be marked to be flushed. When it is next accessed, it will be refreshed.
It is not valid to specify a key without a scope.
<li><b>group</b> - [] - Specifying a group will cause all cache entries in the group
to be flushed. It is not valid to specify a group without a scope.
<li><b>pattern</b> - [] - Any keys that contain this string will be flushed from the
specified scope. It is not valid to specify a pattern without a scope. (Note:
pattern flushing has been deprecated - you are encouraged to use the grouping
functionality instead. It is more flexible and provides better performance.)
<li><b>language</b> - [] - The ISO-639 language code to distinguish different content cached
under an otherwise identical key. This is useful on a multilingual site where the same JSP
code is used to render content in different languages depending on the current user's
preferences.</li>
</ul>
<p><b>Example:</b></p>
<blockquote>
<p>This will flush the application scope.</p>
<p><code><cache:flush scope="application" /></code></p>
<p>This will flush the cache entry with key "foobar" in the session scope.</p>
<p><code><cache:flush scope="session" key="foobar" /></code></p>
<p>This will flush all cache entries in the "currencyData" group from the
application scope.</p>
<p><code><cache:flush scope="application" group="currencyData" /></code></p>
</blockquote>
<%@ include file="navpanel.jsp" %>
</body>
</html>
\ No newline at end of file
+<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.jsp">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><tag></tag> tags always have a body</li>
<li><tag /> does not have a body </li>
<li><tag /></tag> can have a body or not depending on the circumstances.</li>
</ul>
<h3><br>
<a name="cache"></a><cache></cache></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
keys - in this situation an index is appended to the key of subsequent tags. However this
usage is discouraged since if the flow of the page is inconsistent, or cache tags are nested,
the indicies will potentially change each time the page is executed, resulting in seemingly
jumbled cache entries.</li>
<li><b>scope</b> - [application] - The scope of this cache (valid values are
"application" and "session").</li>
<li><b>time</b> - [3600] The amount of time to cache this content for (in seconds).
(Default is 3600 seconds, one hour). Supplying a negative value for this attribute means
that the content never expires.</li>
<li><b>duration</b> - [] - The duration of this cache (this attribute is an
alternative to <b>time</b>). duration can be specified using Simple Date Format
or ISO-8601 date format.</li>
<li><b>cron</b> - [] - A cron expression that determines when this cached content will expire.
This allows content to be expired at particular dates and/or times, rather than once a cache
entry reaches a certain age. See <a href="cron.jsp">Cron Expressions</a> to read more about
this attribute.</li>
<li><b>refresh</b> - [false] - A boolean. If true, the cache will be refreshed regardless of
whether it is considered stale or not. This enables you to decide at runtime whether or not
to rebuild the content.</li>
<li><b>mode</b> - [] - Setting this to "silent" will prevent the body of the tag from
being written to the output stream. This may be useful if you want to preload the cache with
content without actually displaying that content to the user.</li>
<li><b>groups</b> - [] - A comma-delimited list of group names can be provided. This allows
cache entries to be grouped according to your needs. Grouping is useful when you have cached
content that depends on other parts of your application or data - when that dependency changes,
flushing the relevant group will cause all cache entries in that group to be expired.</li>
<li><b>language</b> - [] - The ISO-639 language code to distinguish different content cached
under an otherwise identical key. This is useful on a multilingual site where the same JSP
code is used to render content in different languages depending on the current user's
preferences.</li>
<li><b>refreshpolicyclass</b> - [] - A fully-qualified classname that extends
<code>com.opensymphony.oscache.web.WebEntryRefreshPolicy</code>. This allows you to
programmatically determine whether cached content should be exipired.</li>
<li><b>refreshpolicyparam</b> - [] - Any arbitrary parameters that you need to pass through to
the refreshpolicyclass. Specifying this attribute without specifying a refreshpolicyclass
will have no effect.</li>
</ul>
<p><b>Examples:</b></p>
<blockquote>
<p>This will cache the JSP content using the current URI as a key (which means this must be
the only cache tag on the page to work).</p>
<p><code><cache:cache><br>
... some jsp content ...<br>
</cache:cache> </code></p>
<p>This will cache the content with a constant key in the user's session scope.
Any page that uses this key will access one shared cache.</p>
<p><code><cache:cache key="foobar" scope="session"><br>
... some jsp content ...<br>
</cache:cache> </code></p>
<p>This will cache the content with a programmatic key (here a product ID) for
30 minutes. It will also refresh if the variable <code>needRefresh</code>
is true.</p>
<p><code><cache:cache key="<%= product.getId() %>" time="1800"
refresh="<%= needRefresh %>"><br>
... some jsp content ...<br>
</cache:cache> </code></p>
<p>This will cache the content with a programmatic key, expiring it every morning at 2am.
It will also refresh if the variable <code>needRefresh</code> is true.</p>
<p><code><cache:cache key="<%= product.getId() %>" cron="0 2 * * *"
refresh="<%= needRefresh %>"><br>
... some jsp content ...<br>
</cache:cache> </code></p>
<p>Suppose we had a dynamic list of categories that we pull from a database, and we also store
currency exchange rates that get updated occasionally by calling a webservice. Suppose also that
we have some content that displays information about both the categories and the current exchange
rate values. The following example caches the body content and assigns it to two cache groups,
"currencyData" and "categoryList". When the exchange rates or the category
list is updated, the appropriate group can be flushed causing this content (along with any other
content associated with that group) to be exipired and then rebuilt the next time the page
is processed:</p>
<p><code><cache:cache key="<%= product.getId() %>" time="-1"
group="currencyData, categories"><br>
... display category list ...<br>
... display currency information ...<br>
</cache:cache> </code></p>
</blockquote>
<h3><br>
<a name="usecached"></a><usecached /></h3>
<p><b>Description:</b></p>
<blockquote>
<p>This tag is nested within a <cache> tag and tells its parent whether
or not to use the cached version.</p>
</blockquote>
<p><b>Attributes:</b></p>
<ul>
<li><b>use</b> - [true] - A boolean that tells the tag whether or not to use the cached
version. (true = use cached version). This is useful for programmatic control of the cache.</li>
</ul>
<p><b>Example:</b></p>
<blockquote>
<p>This is a good example of error tolerance. If an exception occurs, the cached
version of this content will be output instead.</p>
<p><code><cache:cache></code><code><br>
<% try { %><br>
... some jsp content ...<br>
<% } catch (Exception e) { %><br>
<cache:usecached /><br>
<% } %><br>
</cache:cache> </code></p>
</blockquote>
<h3><br>
<a name="flush"></a><flush /></h3>
<p><b>Description:</b></p>
<blockquote>
<p>This tag is used to flush caches at runtime. It is especially useful because
it can be coded into the administration section of your site so that admins
can decide when to flush the caches. </p>
</blockquote>
<p><b>Attributes:</b></p>
<ul>
<li><b>scope</b> - [all] - This decides what scope will be flushed. Valid values
are "application", "session" and null. A null scope will
flush all caches, regardless of their scope. </li>
<li><b>key</b> - [] - When a key and a scope are both given, just that single cache
entry will be marked to be flushed. When it is next accessed, it will be refreshed.
It is not valid to specify a key without a scope.
<li><b>group</b> - [] - Specifying a group will cause all cache entries in the group
to be flushed. It is not valid to specify a group without a scope.
<li><b>pattern</b> - [] - Any keys that contain this string will be flushed from the
specified scope. It is not valid to specify a pattern without a scope. (Note:
pattern flushing has been deprecated - you are encouraged to use the grouping
functionality instead. It is more flexible and provides better performance.)
<li><b>language</b> - [] - The ISO-639 language code to distinguish different content cached
under an otherwise identical key. This is useful on a multilingual site where the same JSP
code is used to render content in different languages depending on the current user's
preferences.</li>
</ul>
<p><b>Example:</b></p>
<blockquote>
<p>This will flush the application scope.</p>
<p><code><cache:flush scope="application" /></code></p>
<p>This will flush the cache entry with key "foobar" in the session scope.</p>
<p><code><cache:flush scope="session" key="foobar" /></code></p>
<p>This will flush all cache entries in the "currencyData" group from the
application scope.</p>
<p><code><cache:flush scope="application" group="currencyData" /></code></p>
</blockquote>
<%@ include file="navpanel.jsp" %>
</body>
</html>
\ No newline at end of file
-------------------------------------------------------
This SF.Net email sponsored by: Free pre-built ASP.NET sites including
Data Reports, E-commerce, Portals, and Forums are available now.
Download today and enter to win an XBOX or Visual Studio .NET.
http://aspnet.click-url.com/go/psa00100003ave/direct;at.aspnet_072303_01/01
lmpx.com only provides a reader for public news (NNTP) servers. It is not
affiliated with the servers or forums shown here and is not responsible for
the content of articles, which is written by their respective authors.