Custom cache plugin – How to implement it

Introduction to Custom cache plugin

As discussed in previous blog we have introduced new caching engines in ColdFusion and we are not tightly bound to ehcache now. But even after adding 3 more engines, customers might have a requirement to plugin some another caching engine or perhaps write their own custom caching logic which might suit their applications more than any of the supported engines. So we have added a way for customers to add integration with any caching engine as a plugin.

 

Custom Cache Interface

We have introduced an interface at the location CFIDE.cache.ICustomCache.cfc which developers need to implement and put the implemented folder(interface implementation and other files) at the location CFIDE/cache/FOLDER_NAME. Here FOLDER_NAME will become the name of this new cache engine.

 

This is how interface looks like :

/**

 * Interface for implementing custom cache

 */

Interface

{     /**

       * Put key-value in the cache. 'throwOnError' - If cache does not exist, throw an error. Struct contains id,value,appname,eternal,objecttype,region,timetolive,timetoidle. If eternal is true, element should never expire. Objecttype can be query,object or template.

       */

                public void function put(Struct cacheObj, boolean throwOnError);

               

    /**

     * For a given key, return the value. lastModified will tell the last modified time of the the template if objecttype is template

     */

                public Any function get(Struct cacheObj,boolean throwOnError, Numeric lastModified);

 

   /**

     * Return the metadata of the given key. Metadata should have cachehits,cachemisses, key hits, key misses, timespan, idletime,size, cachename

     */

                public Struct function getMetadata(Struct cacheObj);

 

                /**

     *Set key-value cache properties for given cache region

     */

                public void function setCacheProperties(Struct props, String region);


                /**

     *Get key-value cache properties of given cache region

     */

                public    Array function getCacheProperties( String region);

 

                /**

     *Create a cache

     */

                public boolean function createCache( String cachename, String objType);

                /**

     *Whether a given cache region exists or not

     */

                public boolean function cacheExists(  String region);

 

                /**

     *Get all keys of the cache. If accurate is false, you can return expired keys also

     */

                public Array function getAllCacheIds(Struct cacheObj, boolean accurate);

 

 

                /**

     *Set max elements for a given cache

     */

                public void function setMaxElementsInMemory(String cacheName, Numeric cap);

 

                /**

     *Remove a given cache element

     */

                public boolean function remove(Struct cacheObj);

 

                /**

     *Clear all elements of given cache

     */

                public void function clear(String cachename);

 

 

     /**

     *Clear all elements of given cache and delete the cache

     */

                public void function removeCache(String cachename);

 

 

                 /**

     *Get all cache names

     */

                public Array function getAllCacheNames();

 

                /**

     *Get cache statistics which can be shown in server monitoring

     */

                public Array function getAllCacheMetadataForMonitoring();

 

                /**

     *Called when user switches cache engine.

     */

                public void function reset();

}

Few key methods are :

  • put(Struct cacheObj) – insert a new key value pair in the cache
  • get(Struct cacheObj) –  For a given key return the corresponding value
  • remove(Struct object) –  Remove the given key from the cache

 

Struct object which will be passed to these methods will contains  id,value,appname,eternal,objecttype,region,timetolive,timetoidle.

Appname would be the name of the application. If eternal is true, element should never expire. Objecttype can be query,object or template

 

These are the primary methods which you need to implement. Few methods like getMetadata can be implemented if you want that feature. For example if you do not want to maintain the statistics related the cache entries, you need not to implement this method.

Once you complete the implementation you need to specify the FOLDER_NAME(which is basically the cache engine name) in this.cache.engine property inside application.cfc

 

Now any caching logic written inside this application will be delegated to the custom implementation which you would have just written.

 

Sample Implementation

This is the sample implementation. It is a pretty basic implementation which basically maintains a struct object and adds key-value pairs into it

component implements="ICustomCache" {

 

        cache =StructNew();

   

                public void function put(Struct obj, boolean throwOnError){

                  //writedump('put called - ' & obj.id ,'console');

                  cache[obj.id] = obj.value;

               

                }

 

               

   

                public Any function get(Struct obj,boolean throwOnError, Numeric lastModified){

                     //writedump('get called - ' & obj.id & '-' & lastModified,'console');

              return cache[obj.id];

                }

 

  

                public Struct function getMetadata(Struct obj){

                 writedump('getmetadata called','console');

                     s= {'hitcount':'10','size' : '100'};

             return s;

                }

 

 

                /**

     *Set key-value cache properties for given cache region

     */

                public void function setCacheProperties(Struct props, String region){

                 writedump('setcacheproperties called','console');

         writedump(props,'console');

                }

 

                /**

     *Get key-value cache properties of given cache region. If region is not specified return properties for each objecttype - object,template and query. It should return a Array

     */

                public Array function getCacheProperties( String region){

                 writedump('getcacheproperties called - ' & region,'console');

            a = [{'func' :'getCacheProperties','h' :'j'}];

             return a;

                }

 

                /**

     *Create a cache

     */

                public boolean function createCache( String cachename, String objType){

                 writedump('createcache called ------------ ' & cacheName,'console');

                 return true;

                }

 

                /**

     *Whether a given cache region exists or not

     */

                public boolean function cacheExists(  String region){

                 writedump('cacheexists called - ' & region,'console');

                 return false;

                }

 

               

 

               

 

                /**

     *Get all keys of the cache. If accurate is false, you can return expired keys also

     */

                public Array function getAllCacheIds(Struct cacheObj, boolean accurate){

           writedump('getAllCacheIds called ' ,'console');

                   return Listtoarray(structkeylist(cache));

                }

 

 

                /**

     *Set max elements for a given cache

     */

                public void function setMaxElementsInMemory(String cacheName, Numeric cap){

             writedump('setMaxElementsInMemory called - ' & cacheName & cap,'console');

                }

 

                /**

     *Remove a given cache element

     */

                public boolean function remove(Struct cacheObj){

           writedump('remove called --- ' ,'console');

                   if(isdefined('cacheObj.id'))

                    return cache.delete(cacheObj.id);

                    else{

             clear('dummy');

                     return true;

                    }

                }

 

                /**

     *Clear all elements of given cache

     */

                public void function clear(String cachename){

            writedump('clear called','console');

                    cache = {};

                }

 

 

     /**

     *Clear all elements of given cache and delete the cache

     */

                public void function removeCache(String cachename){

            writedump('removeCache called ---- ' & cachename,'console');

                }

 

 

                 /**

     *Get all cache names

     */

                public Array function getAllCacheNames(){

             writedump('getAllCacheNames called','console');

                      a = ['cache1','cache2'];

             return a;

                }

 

                /**

     *Get cache statistics which can be shown in server monitoring

     */

                public Array function getAllCacheMetadataForMonitoring(){

             writedump('getAllCacheMetadataForMonitoring called','console');

                     ary = [{'APPLICATIONNAME'='jcsudayOBJECT222222','CACHE_HITCOUNT'=1,'NUMBER'=5,'CACHESIZE'=549,'HITRATIO'=0.25,'CACHE_MISSCOUNT'=0}];

                     return ary;

                }

 

                /**

     *Called when user switches cache engine.

     */

                public void function reset(){

                 writedump('reset called','console');

                }

 

}

 

Leave a reply

Related