Apache » Cocoon »

  Cocoon Core
      2.2
   homepage

Cocoon Core 2.2

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:
public SourceValidity getValidity()
{
    return NOPValidity.SHARED_INSTANCE;
}

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:
SourceValidity validity = new TimeStampValidity(timestamp.getTime());

public SourceValidity getValidity()
{
    return validity;
}

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:
SourceValidity validity = new ExpiresValidity(System.currentTimeMillis() + (60 * 1000));

public SourceValidity getValidity()
{
    return validity;
}

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:
SourceValidity validity = new FileTimeStampValidity( sourceFile );

public SourceValidity getValidity()
{
    return validity;
}

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:
AggregatedValidity validity = new AggregatedValidity();
validity.add( fileSource.getValidity() );
validity.add( new ExpiresValidity( System.currentTimeMillis() + (60 * 1000) ) );

public SourceValidity getValidity()
{
    return validity;
}

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.