1:<!---
   2:    $Id$
   3:
   4:    CachedQueryManager: Utility methods for manipulating ColdFusion's cached-queries store
   5:    
   6:    This component uses the following Coldfusion classes:
   7:    
   8:    coldfusion.util.LruCache
   9:    coldfusion.server.ServiceFactory
  10:    coldfusion.server.DataSourceService
  11:    coldfusion.sql.Executive
  12:    coldfusion.tagext.sql.CachedQuery
  13:    
  14:    ====================================================================
  15:    
  16:    Copyright (c) 2006 Asif Tamuri.  All rights reserved.
  17:    
  18:    Redistribution and use in source and binary forms, with or without
  19:    modification, are permitted provided that the following conditions
  20:    are met:
  21:    
  22:    1. Redistributions of source code must retain the above copyright
  23:       notice, this list of conditions and the following disclaimer.
  24:    
  25:    2. Redistributions in binary form must reproduce the above copyright
  26:       notice, this list of conditions and the following disclaimer in
  27:       the documentation and/or other materials provided with the
  28:       distribution.
  29:    
  30:    THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  31:    WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  32:    OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  33:    DISCLAIMED.  IN NO EVENT SHALL THE SOFTWARE'S AUTHORS OR ITS 
  34:    CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  35:    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  36:    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  37:    USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  38:    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  39:    OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  40:    OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  41:    SUCH DAMAGE.
  42:    
  43:    ====================================================================
  44:--->
  45:<cfcomponent displayname="CachedQueryManager" 
  46:    hint="Utility methods for manipulating ColdFusion's cached-queries store">
  47:
  48:    <!--- PROPERTIES --->
  49:    <cfset variables.KEY_FIELD = "key" />
  50:    <cfset variables.HITS_FIELD = "hits" />
  51:    <cfset variables.PENALTY_FIELD = "penalty" />
  52:    <cfset variables.RANK_FIELD = "rank" />
  53:    <cfset variables.CREATION_TIME_FIELD = "creation_time" />
  54:    <cfset variables.NEWEST_ENTRY_FIELD = "newest" />
  55:    <cfset variables.OLDER_FIELD = "older" />
  56:    <cfset variables.VALUE_FIELD = "value" />
  57:    <cfset variables.QUERY_CACHE_FIELD = "query_cache" />
  58:    
  59:    <cfset variables.LruCacheClassName = "coldfusion.util.LruCache" />
  60:    <cfset variables.ServiceFactoryClassName = "coldfusion.server.ServiceFactory" />
  61:    
  62:    <!--- CONSTRUCTOR --->
  63:    <cffunction name="init" access="public" returntype="CachedQueryManager" output="no" hint="Returns instance">
  64:        <cfreturn this />
  65:    </cffunction>
  66:
  67:    <!--- PUBLIC METHODS --->
  68:    <cffunction name="getAll" access="public" returntype="query" output="no" hint="Returns all queries currently cached by Coldfusion">
  69:        <!--- Create a query in which to store results --->
  70:        <cfset var cachedQueries = queryNew("#variables.KEY_FIELD#,#variables.HITS_FIELD#,#variables.RANK_FIELD#,#variables.PENALTY_FIELD#,#variables.CREATION_TIME_FIELD#") />
  71:        <!--- Query is filled by reference --->
  72:        <cfset populateEntriesQuery(cachedQueries) />
  73:        <cfreturn cachedQueries />
  74:    </cffunction>
  75:    
  76:    <cffunction name="remove" access="public" returntype="void" output="no" hint="Removes a query from ColdFusion's cache">
  77:        <cfargument name="key" required="yes" type="string" hint="The cached-query's key. Use getAll() to get full list of keys." />
  78:        <cfset getLruCache().remove(arguments.key) />
  79:    </cffunction>
  80:    
  81:    <cffunction name="clear" access="public" returntype="void" output="no" hint="Calls cfobjectcache tag">
  82:        <cfobjectcache action="clear" />
  83:    </cffunction>
  84:    
  85:    <!--- PRIVATE METHODS --->
  86:    <cffunction name="populateEntriesQuery" access="private" returntype="void" output="no">
  87:        <cfargument name="entries" required="yes" type="query" />
  88:        
  89:        <cfset var tmp = arrayNew(1) />
  90:        <cfset var newestEntry = 0 />
  91:        <cfset var lruClass = tmp.getClass().forName(variables.LruCacheClassName) />
  92:        <cfset var query_cache = getLruCache() />
  93:        
  94:        <cfset var newestEntryField = lruClass.getDeclaredField(variables.NEWEST_ENTRY_FIELD) />
  95:        <cfset newestEntryField.setAccessible(javaCast("boolean", true)) />
  96:        <cfset newestEntry = newestEntryField.get(query_cache) />
  97:        
  98:        <cfif isDefined("newestEntry")>
  99:            <cfset addEntryFieldsToQuery(newestEntry, arguments.entries) />
 100:        </cfif>
 101:    </cffunction>
 102:    
 103:    <cffunction name="addEntryFieldsToQuery" access="private" returntype="void" output="no">
 104:        <cfargument name="entry" required="yes" />
 105:        <cfargument name="entries" required="yes" type="query" />
 106:        
 107:        <cfset var keyField = arguments.entry.getClass().getDeclaredField(variables.KEY_FIELD) />
 108:        <cfset var hitsField = arguments.entry.getClass().getDeclaredField(variables.HITS_FIELD) />
 109:        <cfset var olderEntryField = arguments.entry.getClass().getDeclaredField(variables.OLDER_FIELD) />
 110:        <cfset var penaltyField = arguments.entry.getClass().getDeclaredField(variables.PENALTY_FIELD) />
 111:        <cfset var valueField = arguments.entry.getClass().getDeclaredField(variables.VALUE_FIELD) />
 112:        
 113:        <cfset var rowCount = queryAddRow(arguments.entries) />
 114:        
 115:        <cfset keyField.setAccessible(javaCast("boolean", true)) />
 116:        <cfset hitsField.setAccessible(javaCast("boolean", true)) />
 117:        <cfset olderEntryField.setAccessible(javaCast("boolean", true)) />
 118:        <cfset penaltyField.setAccessible(javaCast("boolean", true)) />
 119:        <cfset valueField.setAccessible(javaCast("boolean", true)) />
 120:        
 121:        <cfset querySetCell(arguments.entries, variables.KEY_FIELD, keyField.get(arguments.entry).toString()) />
 122:        <cfset querySetCell(arguments.entries, variables.HITS_FIELD, hitsField.get(arguments.entry).toString()) />
 123:        <cfset querySetCell(arguments.entries, variables.PENALTY_FIELD, penaltyField.get(arguments.entry).toString()) />
 124:        <cfset querySetCell(arguments.entries, variables.RANK_FIELD, rowCount) />
 125:        <cfset querySetCell(arguments.entries, variables.CREATION_TIME_FIELD, valueField.get(arguments.entry).getCreationTime()) />
 126:        
 127:        <cfif olderEntryField.get(arguments.entry) neq "">
 128:            <cfset addEntryFieldsToQuery(olderEntryField.get(arguments.entry), arguments.entries) />
 129:        </cfif>
 130:    </cffunction>
 131:    
 132:    <cffunction name="getLruCache" access="private" returntype="any" output="no">
 133:        <cfset var factory = CreateObject("java", variables.ServiceFactoryClassName) />
 134:        <cfset var dss = factory.getDataSourceService() />
 135:        <cfset var queryCacheField = dss.getClass().getDeclaredField(variables.QUERY_CACHE_FIELD) />
 136:        <cfset queryCacheField.setAccessible(true) />
 137:        <cfreturn queryCacheField.get(dss)  />
 138:    </cffunction>
 139:    
 140:</cfcomponent>
 141: