CacheHandler

Package: MachII.framework
Holds configuration and cache data.

<!--- License: Copyright 2008 GreatBizTools, LLC Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Copyright: GreatBizTools, LLC Author: Kurt Wiersma (kurt@mach-ii.com) $Id: CacheHandler.cfc 595 2007-12-17 02:39:01Z kurtwiersma $ Created version: 1.6.0 Updated version: 1.6.0 Notes: --->

Method Summary
public CacheHandler init([string alias=""], [string cacheName=""], [string criteria=""], [string parentHandlerName=""], [string parentHandlerType=""])

Initializes the handler.

public void addCommand(Command command)

Adds a Command.

public void clearCache(Event event, [string criteria=""])

Clears the cache.

private struct computeDataToCache(struct preCommandDataSnapshot, struct postCommandDataSnapshot)

Computes event data to cache based on the pre-command and post-command event data snapshots.

private string createHandlerId()

Creates a random handler id. Does not use UUID for performance reasons.

public void disableCaching()

Disables caching.

public void enableCaching()

Enables caching.

public string getAlias()
public string getCacheName()
public AbstractCacheStrategy getCacheStrategy()
public boolean getCachingEnabled()

Gets the caching enabled.

public string getCriteria()

Returns an uppercase and sorted criteria list.

public string getHandlerId()

Returns the handler id.

private string getKeyFromCriteria(Event event, [string criteria=""])

Build a key from the cache handler criteria with data from the event object.

private Log getLog()

Gets the log.

public string getParentHandlerName()
public string getParentHandlerType()
public boolean handleCache(Event event, EventContext eventContext)

Handles a cache.

private array mergeStructKeys(struct struct1, struct struct2)

Returns an array of struct keys with duplicates deleted.

private void setAlias(string alias)
private void setCacheName(string cacheName)
public void setCacheStrategy(AbstractCacheStrategy cacheStrategy)
public void setCachingEnabled(boolean cachingEnabled)

Sets the caching enabled.

private void setCriteria(string criteria)

Automatically converts to uppercase and sorts the criteria list.

private void setHandlerId(string handlerId)
public void setLog(LogFactory logFactory)

Uses the log factory to create a log.

private void setParentHandlerName(string parentHandlerName)
private void setParentHandlerType(string parentHandlerType)
Method Detail
addCommand

public void addCommand( Command command )

Adds a Command.

Parameters:
Command command

Code:

	<cffunction name="addCommand" access="public" returntype="void" output="false"
		hint="Adds a Command.">
		<cfargument name="command" type="MachII.framework.Command" required="true" />
		<cfset ArrayAppend(variables.commands, arguments.command) />
	</cffunction> 

clearCache

public void clearCache( Event event, [string criteria=""] )

Clears the cache.

Parameters:
Event event
[string criteria=""]

Code:

	<cffunction name="clearCache" access="public" returntype="void" output="false"
		hint="Clears the cache.">
		<cfargument name="event" type="MachII.framework.Event" required="true" />
		<cfargument name="criteria" type="string" required="false" default="" />

		<cfset var key = getKeyFromCriteria(arguments.event, arguments.criteria) />
		
		<cfif log.isDebugEnabled()>
			<cfset log.debug("Cache-handler clearing data from cache using key '#key#'.") />
		</cfif>
		
		<cfif Len(key)>
			<cfset getCacheStrategy().remove(key) />
		<cfelse>
			<cfset getCacheStrategy().flush() />
		</cfif>
	</cffunction> 

computeDataToCache

private struct computeDataToCache( struct preCommandDataSnapshot, struct postCommandDataSnapshot )

Computes event data to cache based on the pre-command and post-command event data snapshots.

Parameters:
struct preCommandDataSnapshot
struct postCommandDataSnapshot

Code:

	<cffunction name="computeDataToCache" access="private" returntype="struct" output="false"
		hint="Computes event data to cache based on the pre-command and post-command event data snapshots.">
		<cfargument name="preCommandDataSnapshot" type="struct" required="true" />
		<cfargument name="postCommandDataSnapshot" type="struct" required="true" />
		
		<cfset var keys = mergeStructKeys(arguments.preCommandDataSnapshot, arguments.postCommandDataSnapshot) />
		<cfset var dataToCache = StructNew() />
		<cfset var pre = "" />
		<cfset var post = "" />
		<cfset var objTest = StructNew() />
		<cfset var keyName = "" />
		<cfset var i = "" />
				
		
		<cfloop from="1" to="#ArrayLen(keys)#" index="i">
			<cfset keyName = keys[i] />
			
			
			<cfif NOT StructKeyExists(arguments.preCommandDataSnapshot, keyName) AND StructKeyExists(arguments.postCommandDataSnapshot , keyName)>
				<cfset dataToCache[keyName] = arguments.postCommandDataSnapshot [keyName]>
			
			<cfelseif StructKeyExists(arguments.preCommandDataSnapshot, keyName) AND StructKeyExists(arguments.postCommandDataSnapshot , keyName)>
				<cfset pre = arguments.preCommandDataSnapshot[keyName] />
				<cfset post = arguments.postCommandDataSnapshot[keyName] />
				
				
				<cfif IsObject(pre) AND IsObject(post)>
					<cfset objTest = ArrayNew(1) />
					<cfset ArrayAppend(objTest, pre) />
					<cfif NOT objTest.contains(post)>
						<cfset dataToCache[keyName] = post />
					</cfif>
				
				<cfelseif IsQuery(pre) AND IsQuery(post)>
					
					<cfif pre.hashCode() NEQ post.hashCode()>
						<cfset dataToCache[keyName] = post />
					</cfif>
				
				<cfelseif (IsSimpleValue(pre) AND IsSimpleValue(post))
					OR (IsArray(pre) AND IsArray(post))
					OR (IsStruct(pre) AND IsStruct(post))>
					<cfif NOT pre.equals(post)>	
						<cfset dataToCache[keyName] = post />
					</cfif>
				
				<cfelse>
					<cfset dataToCache[keyName] = post />
				</cfif>
			</cfif>
		</cfloop>

		<cfreturn dataToCache />
	</cffunction> 

createHandlerId

private string createHandlerId( )

Creates a random handler id. Does not use UUID for performance reasons.

Parameters:

Code:

	<cffunction name="createHandlerId" access="private" returntype="string" output="false"
		hint="Creates a random handler id. Does not use UUID for performance reasons.">
		<cfreturn Hash(getTickCount() & RandRange(0, 100000) & RandRange(0, 100000)) />
	</cffunction> 

disableCaching

public void disableCaching( )

Disables caching.

Parameters:

Code:

	<cffunction name="disableCaching" access="public" returntype="void" output="false"
		hint="Disables caching.">
		<cfset setCachingEnabled(false) />
	</cffunction> 

enableCaching

public void enableCaching( )

Enables caching.

Parameters:

Code:

	<cffunction name="enableCaching" access="public" returntype="void" output="false"
		hint="Enables caching.">
		<cfset setCachingEnabled(true) />
	</cffunction> 

getAlias

public string getAlias( )

Parameters:

Code:

	<cffunction name="getAlias" access="public" returntype="string" output="false">
		<cfreturn variables.alias />
	</cffunction> 

getCacheName

public string getCacheName( )

Parameters:

Code:

	<cffunction name="getCacheName" access="public" returntype="string" output="false">
		<cfreturn variables.cacheName />
	</cffunction> 

getCacheStrategy

public AbstractCacheStrategy getCacheStrategy( )

Parameters:

Code:

	<cffunction name="getCacheStrategy" access="public" returntype="MachII.caching.strategies.AbstractCacheStrategy" output="false">
		<cfreturn variables.cacheStrategy />
	</cffunction> 

getCachingEnabled

public boolean getCachingEnabled( )

Gets the caching enabled.

Parameters:

Code:

	<cffunction name="getCachingEnabled" access="public" returntype="boolean" output="false"
		hint="Gets the caching enabled.">
		<cfreturn variables.cachingEnabled />
	</cffunction> 

getCriteria

public string getCriteria( )

Returns an uppercase and sorted criteria list.

Parameters:

Code:

	<cffunction name="getCriteria" access="public" returntype="string" output="false"
		hint="Returns an uppercase and sorted criteria list.">
		<cfreturn variables.criteria />
	</cffunction> 

getHandlerId

public string getHandlerId( )

Returns the handler id.

Parameters:

Code:

	<cffunction name="getHandlerId" access="public" returntype="string" output="false"
		hint="Returns the handler id.">
		<cfreturn variables.handlerId />
	</cffunction> 

getKeyFromCriteria

private string getKeyFromCriteria( Event event, [string criteria=""] )

Build a key from the cache handler criteria with data from the event object.

Parameters:
Event event
[string criteria=""]

Code:

	<cffunction name="getKeyFromCriteria" access="private" returntype="string" output="false"
		hint="Build a key from the cache handler criteria with data from the event object.">
		<cfargument name="event" type="MachII.framework.Event" required="true" />
		<cfargument name="criteria" type="string" required="false" default=""
			hint="If criteria is not passed in the criteria from the cache command will be used." />
		
		<cfset var criteriaToUse =  ""/>
		<cfset var item = "" />
		<cfset var arg = "" />
		<cfset var key = "handlerId=" & getHandlerId() />
		
		
		<cfif len(getAlias())>
			<cfset key = key & "&alias=" & getAlias() />
		</cfif>
		
		<cfif arguments.criteria eq "">
			<cfset criteriaToUse = getCriteria() />
		<cfelse>
			<cfset criteriaToUse = arguments.criteria />
		</cfif>

				
		<cfloop list="#criteriaToUse#" index="item">
			<cfif listLen(item, "=") eq 2>
				<cfset arg = arguments.event.getArg(listGetAt(item, 2, "="), "") />
				<cfset item = listGetAt(item, 1, "=") />
			<cfelse>
				<cfset arg = arguments.event.getArg(item, "") />	
			</cfif>

				
			<cfif IsSimpleValue(arg)>
				<cfset key = ListAppend(key, item & "=" & arg, "&") />
			<cfelse>
				<cfset key = ListAppend(key, item & "=", "&") />
			</cfif>
		</cfloop>
		
		<cfreturn key />
	</cffunction> 

getLog

private Log getLog( )

Gets the log.

Parameters:

Code:

	<cffunction name="getLog" access="private" returntype="MachII.logging.Log" output="false"
		hint="Gets the log.">
		<cfreturn variables.log />
	</cffunction> 

getParentHandlerName

public string getParentHandlerName( )

Parameters:

Code:

	<cffunction name="getParentHandlerName" access="public" returntype="string" output="false">
		<cfreturn variables.parentHandlerName />
	</cffunction> 

getParentHandlerType

public string getParentHandlerType( )

Parameters:

Code:

	<cffunction name="getParentHandlerType" access="public" returntype="string" output="false">
		<cfreturn variables.parentHandlerType />
	</cffunction> 

handleCache

public boolean handleCache( Event event, EventContext eventContext )

Handles a cache.

Parameters:
Event event
EventContext eventContext

Code:

	<cffunction name="handleCache" access="public" returntype="boolean" output="true"
		hint="Handles a cache.">
		<cfargument name="event" type="MachII.framework.Event" required="true" />
		<cfargument name="eventContext" type="MachII.framework.EventContext" required="true" />

		<cfset var preCommandEventDataSnapshot = StructNew() />
		<cfset var dataToCache = StructNew() />
		<cfset var key = getKeyFromCriteria(arguments.event) />
		<cfset var dataFromCache = "" />
		<cfset var command = "" />
		<cfset var continue = true />
		<cfset var i = 0 />
		<cfset var log = getLog() />
		
		<cfif log.isDebugEnabled()>
			<cfset log.debug("Looking for data in the cache for key '#key#'") />
		</cfif>
		
		<cfset dataFromCache = getCacheStrategy().get(key) />
		
		
		<cfif NOT IsDefined("dataFromCache") OR NOT getCachingEnabled()>

			
			<cfset StructAppend(preCommandEventDataSnapshot, arguments.event.getArgs()) />
		
			
			<cfsavecontent variable="dataToCache.output">
				<cfloop from="1" to="#ArrayLen(variables.commands)#" index="i">
					<cfset command = variables.commands[i] />
					<cfset continue = command.execute(arguments.event, arguments.eventContext) />
					<cfif continue IS false>
						<cfbreak />
					</cfif>
				</cfloop>
			</cfsavecontent>
			
			
			<cfif getCachingEnabled()>
				
				<cfset dataToCache.data = computeDataToCache(preCommandEventDataSnapshot, arguments.event.getArgs()) />

				
				<cfset getCacheStrategy().put(key, dataToCache) />
				
				
				<cfif log.isDebugEnabled()>
					<cfset log.debug("Creating cache with key '#key#'.") />
					<cfset log.debug("Set cache data with key names of '#StructKeyList(dataToCache.data)#'.") />
				</cfif>
			<cfelse>
				<cfif log.isDebugEnabled()>
					<cfset log.debug("Caching is curently disabled for this cache-handler.") />
				</cfif>
			</cfif>

			
			<cfoutput>#dataToCache.output#</cfoutput>
		<cfelse>
			
			<cfoutput>#dataFromCache.output#</cfoutput>
			<cfset arguments.event.setArgs(dataFromCache.data) />
			
			
			<cfif log.isDebugEnabled()>
				<cfset log.debug("Using data and output from cache with key '#key#'.") />
				<cfset log.debug("Using cache data with key names of '#StructKeyList(dataFromCache.data)#'.") />
			</cfif>
		</cfif>
		
		<cfreturn continue />
	</cffunction> 

init

public CacheHandler init( [string alias=""], [string cacheName=""], [string criteria=""], [string parentHandlerName=""], [string parentHandlerType=""] )

Initializes the handler.

Parameters:
[string alias=""]
[string cacheName=""]
[string criteria=""]
[string parentHandlerName=""]
[string parentHandlerType=""]

Code:

	<cffunction name="init" access="public" returntype="CacheHandler" output="false"
		hint="Initializes the handler.">
		<cfargument name="alias" type="string" required="false" default="" />
		<cfargument name="cacheName" type="string" required="false" default="" />
		<cfargument name="criteria" type="string" required="false" default="" />
		<cfargument name="parentHandlerName" type="string" required="false" default="" />
		<cfargument name="parentHandlerType" type="string" required="false" default="" />
	
		
		<cfset setAlias(arguments.alias) />
		<cfset setCacheName(arguments.cacheName) />
		<cfset setCriteria(arguments.criteria) />
		<cfset setParentHandlerName(arguments.parentHandlerName) />
		<cfset setParentHandlerType(arguments.parentHandlerType) />
		<cfset setHandlerId(createHandlerId()) />
		
		<cfreturn this />
	</cffunction> 

mergeStructKeys

private array mergeStructKeys( struct struct1, struct struct2 )

Returns an array of struct keys with duplicates deleted.

Parameters:
struct struct1
struct struct2

Code:

	<cffunction name="mergeStructKeys" access="private" returntype="array" output="false"
		hint="Returns an array of struct keys with duplicates deleted.">
		<cfargument name="struct1" type="struct" required="true" />
		<cfargument name="struct2" type="struct" required="true" />

		<cfset var mergedKeys = StructKeyList(arguments.struct1) & "," & StructKeyList(arguments.struct2) />
		<cfset var cleanedKeys = "" />
		<cfset var item = "" />
		
		
		<cfloop list="#mergedKeys#" index="item">
			<cfif NOT ListFindNoCase(cleanedKeys, item)>
				<cfset cleanedKeys = ListAppend(cleanedKeys, item) />
			</cfif>
		</cfloop>

		<cfreturn ListToArray(cleanedKeys) />
	</cffunction> 

setAlias

private void setAlias( string alias )

Parameters:
string alias

Code:

	<cffunction name="setAlias" access="private" returntype="void" output="false">
		<cfargument name="alias" type="string" required="true" />
		<cfset variables.alias = arguments.alias />
	</cffunction> 

setCacheName

private void setCacheName( string cacheName )

Parameters:
string cacheName

Code:

	<cffunction name="setCacheName" access="private" returntype="void" output="false">
		<cfargument name="cacheName" type="string" required="true" />
		<cfset variables.cacheName = arguments.cacheName />
	</cffunction> 

setCacheStrategy

public void setCacheStrategy( AbstractCacheStrategy cacheStrategy )

Parameters:
AbstractCacheStrategy cacheStrategy

Code:

	<cffunction name="setCacheStrategy" access="public" returntype="void" output="false">
		<cfargument name="cacheStrategy" type="MachII.caching.strategies.AbstractCacheStrategy" required="true" />
		<cfset variables.cacheStrategy = arguments.cacheStrategy />
	</cffunction> 

setCachingEnabled

public void setCachingEnabled( boolean cachingEnabled )

Sets the caching enabled.

Parameters:
boolean cachingEnabled

Code:

	<cffunction name="setCachingEnabled" access="public" returntype="void" output="false"
		hint="Sets the caching enabled.">
		<cfargument name="cachingEnabled" type="boolean" required="true" />
		<cfset variables.cachingEnabled = arguments.cachingEnabled />
	</cffunction> 

setCriteria

private void setCriteria( string criteria )

Automatically converts to uppercase and sorts the criteria list.

Parameters:
string criteria

Code:

	<cffunction name="setCriteria" access="private" returntype="void" output="false"
		hint="Automatically converts to uppercase and sorts the criteria list.">
		<cfargument name="criteria" type="string" required="true" />
		<cfset variables.criteria = ListSort(UCase(arguments.criteria), "text") />
	</cffunction> 

setHandlerId

private void setHandlerId( string handlerId )

Parameters:
string handlerId

Code:

	<cffunction name="setHandlerId" access="private" returntype="void" output="false">
		<cfargument name="handlerId" type="string" required="true" />
		<cfset variables.handlerId = arguments.handlerId />
	</cffunction> 

setLog

public void setLog( LogFactory logFactory )

Uses the log factory to create a log.

Parameters:
LogFactory logFactory

Code:

	<cffunction name="setLog" access="public" returntype="void" output="false"
		hint="Uses the log factory to create a log.">
		<cfargument name="logFactory" type="MachII.logging.LogFactory" required="true" />
		<cfset variables.log = arguments.logFactory.getLog(getMetadata(this).name) />
	</cffunction> 

setParentHandlerName

private void setParentHandlerName( string parentHandlerName )

Parameters:
string parentHandlerName

Code:

	<cffunction name="setParentHandlerName" access="private" returntype="void" output="false">
		<cfargument name="parentHandlerName" type="string" required="true" />
		<cfset variables.parentHandlerName = arguments.parentHandlerName />
	</cffunction> 

setParentHandlerType

private void setParentHandlerType( string parentHandlerType )

Parameters:
string parentHandlerType

Code:

	<cffunction name="setParentHandlerType" access="private" returntype="void" output="false">
		<cfargument name="parentHandlerType" type="string" required="true" />
		<cfset variables.parentHandlerType = arguments.parentHandlerType />
	</cffunction>