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 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).
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; }