CacheableProcessingComponent Contracts

CacheableProcessingComponent Contracts

Just about everything can be cached, so it makes sense to provide some
controls to make sure that the user always gets valid results. There are two
aspects to a cacheable component: the key and the validition. The key is used to
determine within the component's scheme of things whether a result is unique.
For example, if your generator provides dynamic information based on an ID and a
user, you want to combine the two elements into one key. That way Cocoon can
determine whether to use the cached information for the given ID/User
combination or create it from scratch.

The CachingPipeline will check the component's key to see if it even has the
information cached to begin with. Next, it will check the validity of the cached
value if there is one. If the cache has the resource and it is valid, the
CachingPipeline will return the cached results. If either condition is false,
then the CachingPipeline will generate the results and cache it for later use.
It is important to realize that only the CachingPipeline will respect the
contracts outlined in this document.

The Cache Key

The cache key is the single most important part of the caching
implementation. If you don't get it right, you can introduce more load on the
caching engine than is necessary. It is important that the cache key has the
following attributes:

It must be Serializable (part of the contract of the getKey()
method).

It must be Immutable--the key is used as a lookup value.

It must be Unique within the space of the component (i.e. the key "1" for
MyCacheableComponent must be for the same resource every time, but we
don't have to worry about the key "1" for YourCacheableComponent).

The equals() and hashCode() methods must
be consistent (i.e. if two keys are equal, the hashCode must also be equal).

Thankfully there is a perfectly suitable object that satisfies these
obligations from Java's core: java.lang.String. You can also use your
own specific key objects provided they respect those contracts.If the cache key is null then your component will not be cached at
all. You can use this to your advantage to cache some things but not others.

The Source Validity

The caching contracts use the Excalibur SourceValidity interface to determine
whether a resource is valid or not. The validity can be a compound check that
incorporates time since creation, parameter values, etc. As long as the sitemap
can determine whether the cached resource is valid or not. More information is
available on the
Apache Excalibur
site. Alternatively you can use the built in CacheValidity objects in the
org.apache.cocoon.caching package and then use the
CacheValidityToSourceValidity
adaptor object.The SourceValidity interface provides two isValid() methods, which
are used to check the validity of a source. The first call is to the version
without parameters, which the SourceValidity will return
SourceValidity.VALID, SourceValidity.UNKNOWN, or
SourceValidity.INVALID. If the first call responds with
SourceValidity.UNKNOWN, then a new SourceValidity object is obtained
from the CacheableProcessingComponent and that is passed into the
isValid(SourceValidity) method. That can return the same set of
responses. At this point, if the second comparison returns
SourceValidity.UNKNOWN the action taken depends largely on the cache's
algorithm. It may play conservative and invalidate the entry, or it may play
loose and use it anyway. The general contract is that the new SourceValidity
object is considered unusable. The contract is that a SourceValidity object will
only be able to validate against another object of the same type. For example, a
TimestampValidity object can validate against another TimestampValidity object
but not a NOPValidity object.

The available SourceValidity objects provided by the Excalibur SourceResolver
component are (in the order of commonality):

NOPValidity--always valid

TimeStampValidity--valid until a newer timestamp is found
(System.currentTimeMillis())

ExpiresValidity--valid until the expiration date is reached
(System.currentTimeMillis() + time)

FileTimestampValidity--valid until the referenced file changes

AggregatedValidity--a compound validity object that is valid as
long as all the encapsulated validity objects are valid

DeferredAggregatedValidity--a compound validity object that only
gets validity objects if they are needed.

NOPValidity

Use the NOPValidity if you want to manually invalidate the cache entry for an
item, or if you have an object that is created once and simply reused. It has
limited use, but it is the easiest to set up. Just implement the
getValidity() method like this:

TimeStampValidity

The TimeStampValidity object is most commonly used with blobs retrieved from
the database, or some other information that only needs to be refreshed when a
newer version exists. The TimeStampValidity will always return
SourceValidity.UNKNOWN until it is compared against a new
TimeStampValidity object so that it can compare the dates. You can use this
validity object like this:

ExpiresValidity

The ExpiresValidity object is used for items you want to keep around for a
while, but you know they will change within a certain amount of time. One
example would be a clock snippet generator for your site. The clock is not going
to change for the granularity that you are displaying. If the clock is
displaying the hour and minute, then you could set the expiration time to
System.currentTimeMillis() plus one minute. All calls during that minute would
reuse the same information. While I doubt we would have a component that only
generates the time of day, you get the general idea. You would set it up like
this:

FileTimeStampValidity

The FileTimeStampValidity is used most often by components that depend on an
external file to produce its output. The most common examples would be your
FileGenerator and the XSLTransformer components. The FileTimeStampValidity
always checks the source file itself and uses the file system's timestamp to
verify if the entry is still valid. You have three ways of setting it up:
passing in the File reference, passing in the filename as a string, and passing
in a combination of the File and the original timestamp. The
FileTimeStampValidity is commonly used by the FileSource object. Below is an
example of using the validity object:

AggregatedValidity

The AggregatedValidity is the mechanism that you would usually use to combine
any of the above validity types together and validate against all of them. For
example, let's assume your Generator depends on a source file, but it also
depends on some time dependant information that needs to be calculated every
minute. We would set it up like this:

DefferedAggregatedValidity

We usually don't use this validity object directly for Sitemap components,
but it is referenced for the sake of completeness. It is used just like the
AggregatedValidity object, only it adds an additional method to add
DeferredValidity objects. The purpose is presumably to perform lazy
initialization on some expensive validity objects so that the normal validity
objects are evaluated first, and the other validity objects are created on
demand. There are no stock DeferredValidity object implementations that I know
of, so this is of little more than academic value for Cocoon components.

Apache Cocoon, Apache, the Apache feather logo, and the Apache Cocoon project logos are trademarks of The Apache Software Foundation.
All other marks mentioned may be trademarks or registered trademarks of their respective owners.