PageRenderTime 97ms CodeModel.GetById 0ms RepoModel.GetById 0ms app.codeStats 0ms

/wheels/vendor/memcached/com/Memcached.cfc

http://cfwheels.googlecode.com/
ColdFusion CFScript | 553 lines | 459 code | 42 blank | 52 comment | 34 complexity | 4755f7d879609a3be7da2a2ac0c5f506 MD5 | raw file
Possible License(s): Apache-2.0, CPL-1.0
  1. <cfcomponent extends="_base" output="false">
  2. <!-----------
  3. This memcached client uses the java memcached client written by Dustin Sallings found at:
  4. http://bleu.west.spy.net/~dustin/projects/memcached/
  5. it also borrows from the javaloader project put together by mark mandel
  6. http://www.transfer-orm.com/?action=javaloader.index
  7. This project was also inspired by the previous memcached client put together by shayne sweeney
  8. http://memcached.riaforge.org/
  9. you can find this project at
  10. http://cfmemcached.riaforge.org/
  11. And if you feel like visiting my personal blog (Jon Hirschi), it can be found at:
  12. http://www.flexablecoder.com
  13. Wow, that's a mouthful...
  14. ------------->
  15. <cfset variables.memcached = "">
  16. <cfset variables.timeUnit = "">
  17. <cfset variables.FutureTask = "">
  18. <cfset variables.transcoder = "">
  19. <cfset variables.addrUtil = "">
  20. <cffunction name="init" displayname="init" hint="init function" access="public" output="false" returntype="any">
  21. <cfargument name="servers" type="string" required="true" />
  22. <cfscript>
  23. /*
  24. if you want to use the java loader you don't have to do anything, just put this into a location under
  25. your web root and it will load all the classes for you. if you don't want to use the java loader,
  26. just comment out the classes below and comment in the lines that are commented out. if you don't want
  27. to use the java loader, then you will need to put the classes somewhere on the class path.
  28. generally an easy place to put this is in the <cfroot>/lib directory.
  29. */
  30. // if you are having problems loading the memcached client or
  31. // if it is giving you errors saying that it can't find one of
  32. // the java classes, then you can change this value here to point to the directory
  33. // where the java classes are located. in this case they are in the lib directory,
  34. // just below the directory where this memcached client is placed. if you have
  35. // copied the java libs into the java class path, then you can change this to
  36. // an empty directory.
  37. var MemcachedClientJavaJarDir = "#GetDirectoryFromPath(GetCurrentTemplatePath())#lib";
  38. // these lines to use if you want to use the java loader
  39. var facadeFactory = createObject("component", "facade.FacadeFactory").init();
  40. var javaLoader = createObject("component", "util.JavaLoader").init(facadeFactory.getServerFacade(),MemcachedClientJavaJarDir);
  41. variables.addrUtil = javaLoader.create("net.spy.memcached.AddrUtil").init();
  42. variables.memcached = javaLoader.create("net.spy.memcached.MemcachedClient").init(addrUtil.getAddresses(arguments.servers));
  43. /*
  44. // these lines to use if you don't want to use the java loader
  45. variables.addrUtil = createObject("java","net.spy.memcached.AddrUtil").init();
  46. variables.memcached = createObject("java","net.spy.memcached.MemcachedClient").init(addrUtil.getAddresses(arguments.servers));
  47. variables.timeUnit = createObject("java","java.util.concurrent.TimeUnit");
  48. */
  49. variables.transcoder = variables.memcached.getTranscoder();
  50. /****************************
  51. some methods return a future object (especially asyncronous sets and gets)
  52. these let you check back in on the result. they don't require that you wait around for
  53. a response
  54. future object methods:
  55. Cancel() - returns a boolean - allows you to cancel the operation
  56. get( int, variables.timeunit ) - returns object - when an interger is sent in, you can
  57. get the result in that amount of time.
  58. get() - returns an object - get the result when it is available.
  59. isCancelled() - returns boolean - lets you know if the operation was cancelled
  60. isDone() - returns boolean - returns true when the operation has finished.
  61. Just a little caveat here. keys are case sensitive, so make sure that you have the right case...
  62. */
  63. super.init();
  64. </cfscript>
  65. <cfreturn this>
  66. </cffunction>
  67. <cffunction name="add" displayname="add" access="public" output="false" returntype="any"
  68. hint="Add an object to the cache iff it does not exist already.
  69. Add an object to the cache iff it does not exist already.
  70. The exp value is passed along to memcached exactly as given, and will be processed per
  71. the memcached protocol specification:
  72. The actual value sent may either be Unix time
  73. (number of seconds since January 1, 1970, as a 32-bit value),
  74. or a number of seconds starting from current time.
  75. In the latter case, this number of seconds may not
  76. exceed 60*60*24*30 (number of seconds in 30 days);
  77. if the number sent by a client is larger than that, the server will consider it to be
  78. real Unix time value rather than an offset from current time.
  79. RETURNS: a future representing the processing of this operation
  80. " >
  81. <cfargument name="key" type="string" hint="a single key to add" required="true" />
  82. <cfargument name="value" type="any" hint="the value to set" required="true" />
  83. <cfargument name="expiry" type="numeric" hint="number of seconds until expire" default="0" required="true" />
  84. <cfscript>
  85. var futureTask = "";
  86. var ret = "";
  87. try {
  88. ret = variables.memcached.add(arguments.key, arguments.expiry, serialize(arguments.value) );
  89. } catch (Any e) {
  90. // failing gracefully
  91. }
  92. futureTask = createObject("component","FutureTask").init(ret);
  93. </cfscript>
  94. <cfreturn futureTask/>
  95. </cffunction>
  96. <cffunction name="asyncGet" access="public" output="false" returntype="Any"
  97. hint="Get the given key asynchronously. returns the future value of those keys
  98. what you get back wht you use this function is an object that has the future value
  99. of the key you asked to retrieve. You can check at anytime to see if the value has been
  100. retrieved by using the ret.isDone() method. once you get a true from that value, you
  101. need to then call the ret.get() function.
  102. ">
  103. <cfargument name="key" type="string" hint="given a key, get the key asnycronously" required="true" />
  104. <cfscript>
  105. var ret = "";
  106. var futureTask ="";
  107. // gotta go through all this to catch the nulls.
  108. try {
  109. ret = variables.memcached.asyncGet(arguments.key);
  110. // additional processing might be required.
  111. } catch(Any e) {
  112. // failing gracefully
  113. }
  114. futureTask = createObject("component","FutureTask").init(ret);
  115. </cfscript>
  116. <cfreturn futureTask/>
  117. </cffunction>
  118. <cffunction name="asyncGetBulk" access="public" output="false" returntype="any"
  119. hint="Asynchronously get a bunch of objects from the cache. returns the future value of those keys.
  120. " >
  121. <cfargument name="keys" type="array" hint="given a struct of keys, get the keys asnycronously" required="true" />
  122. <cfscript>
  123. var ret = "";
  124. var futureTask = "";
  125. // gotta go through all this to catch the nulls.
  126. try {
  127. ret = variables.memcached.asyncGetBulk(arguments.keys);
  128. // additional processing might be required.
  129. } catch(Any e) {
  130. // catch is here to fail gracefully
  131. }
  132. futureTask = createObject("component","FutureTask").init(ret);
  133. </cfscript>
  134. <cfreturn futureTask/>
  135. </cffunction>
  136. <cffunction name="decr" displayname="decr" access="public" output="false" returntype="Numeric"
  137. hint="Decrement the given key by the given value. returns the new value, or -1 if we were unable to decrement or add" >
  138. <cfargument name="key" type="string" hint="a single key to add" required="true" />
  139. <cfargument name="by" type="numeric" hint="amount to decrement by" default="0" required="false" />
  140. <cfargument name="value" type="numeric" hint="the value to set" required="false" default="0"/>
  141. <cfscript>
  142. var ret = -1;
  143. try {
  144. if ( structkeyExists(arguments,"value") ) {
  145. ret = variables.memcached.decr(arguments.key,arguments.by,arguments.value);
  146. } else {
  147. ret = variables.memcached.decr(arguments.key,arguments.by);
  148. }
  149. } catch (Any e) {
  150. // catch is here to fail gracefully
  151. ret = -1;
  152. }
  153. </cfscript>
  154. <cfreturn ret/>
  155. </cffunction>
  156. <cffunction name="delete" access="public" output="true" returntype="any"
  157. hint="Shortcut to delete that will immediately delete the item from the cache.
  158. or in the delay specified. returns a future object that allows you to
  159. check back on the processing further if you choose." >
  160. <cfargument name="deletekey" type="string" required="true" hint="the key to delete"/>
  161. <cfargument name="delay" type="numeric" required="false" default="0" hint="when to delete the key - time in seconds" />
  162. <Cfscript>
  163. var ret = false;
  164. var futureTask = "";
  165. try {
  166. if (arguments.delay gt 0) {
  167. ret = variables.memcached.delete(arguments.deletekey,arguments.delay);
  168. } else {
  169. ret = variables.memcached.delete(arguments.deletekey);
  170. }
  171. } catch (Any e) {
  172. // failing gracefully
  173. ret = "";
  174. }
  175. if (isdefined("ret")) {
  176. futureTask = createobject("component","FutureTask").init(ret);
  177. } else {
  178. futureTask = createobject("component","FutureTask").init();
  179. }
  180. </Cfscript>
  181. <cfreturn futureTask/>
  182. </cffunction>
  183. <cffunction name="get" access="public" output="false" returntype="Any"
  184. hint=" Get with a single key. waits for a return value" >
  185. <cfargument name="key" type="string" required="true" hint="given a key, get the key asnycronously" />
  186. <cfargument name="timeout" type="numeric" required="false" default="#variables.defaultRequestTimeout#"
  187. hint="the number of milliseconds to wait until for the response.
  188. a timeout setting of 0 will wait forever for a response from the server"/>
  189. <cfargument name="timeoutUnit" type="numeric" required="false" default="#variables.defaultTimeoutUnit#"
  190. hint="The timeout unit to use for the timeout"/>
  191. <cfscript>
  192. var ret = "";
  193. var futureTask = "";
  194. // gotta go through all this to catch the nulls.
  195. try {
  196. ret = variables.memcached.asyncGet(arguments.key);
  197. if (not isdefined("ret") ) {
  198. ret = "";
  199. } else {
  200. futureTask = createObject("component","FutureTask").init(ret);
  201. ret = futureTask.get(arguments.timeout,arguments.timeoutUnit);
  202. }
  203. } catch (Any e) {
  204. // failing gracefully
  205. }
  206. </cfscript>
  207. <cfreturn ret/>
  208. </cffunction>
  209. <cffunction name="getBulk" access="public" output="false" returntype="any"
  210. hint="Get the values for multiple keys from the cache. waits for a return value" >
  211. <cfargument name="keys" type="array" hint="given a key, get the key asnycronously" required="true" />
  212. <cfargument name="timeout" type="numeric" required="false" default="#variables.defaultRequestTimeout#"
  213. hint="the number of milliseconds to wait until for the response.
  214. a timeout setting of 0 will wait forever for a response from the server"/>
  215. <cfargument name="timeoutUnit" type="numeric" required="false" default="#variables.defaultTimeoutUnit#"
  216. hint="The timeout unit to use for the timeout"/>
  217. <cfscript>
  218. var ret = "";
  219. var futureTask = "";
  220. // gotta go through all this to catch the nulls.
  221. try {
  222. ret = variables.memcached.asyncGetBulk(arguments.keys);
  223. if (not isdefined("ret") ) {
  224. ret = "";
  225. } else {
  226. futureTask = createObject("component","FutureTask").init(ret);
  227. ret = futureTask.get(arguments.timeout,arguments.timeoutUnit);
  228. }
  229. } catch (Any e) {
  230. // failing gracefully
  231. ret = "";
  232. }
  233. </cfscript>
  234. <cfreturn ret/>
  235. </cffunction>
  236. <cffunction name="incr" access="public" output="false" returntype="Numeric"
  237. hint="Increment the given key by the given amount. returns -1 if string cannot be incremented">
  238. <cfargument name="key" type="string" hint="a single key to add" required="true" />
  239. <cfargument name="by" type="numeric" hint="amount to increment by" default="0" required="false" />
  240. <cfargument name="value" type="numeric" hint="the default value used if null" required="false"/>
  241. <cfscript>
  242. var ret = -1;
  243. try {
  244. if ( structkeyExists(arguments,"value") ) {
  245. ret = variables.memcached.incr(arguments.key,arguments.by,arguments.value);
  246. } else {
  247. ret = variables.memcached.incr(arguments.key,arguments.by);
  248. }
  249. } catch (Any e) {
  250. // failing gracefully here
  251. ret = -1;
  252. }
  253. </cfscript>
  254. <cfreturn ret/>
  255. </cffunction>
  256. <cffunction name="doReplace" access="public" output="false" returntype="any"
  257. hint="Replace an object with the given value iff there is already a value for the given key.
  258. The exp value is passed along to memcached exactly as given,
  259. and will be processed per the memcached protocol specification:
  260. The actual value sent may either be Unix time (number of seconds since January 1, 1970,
  261. as a 32-bit value), or a number of seconds starting from current time.
  262. In the latter case, this number of seconds may not exceed 60*60*24*30
  263. (number of seconds in 30 days); if the number sent by a client is larger than that,
  264. the server will consider it to be real Unix time value rather than an offset from current time.
  265. RETURNS: a future representing the processing of the operation
  266. " >
  267. <cfargument name="key" type="string" hint="a single key to add" required="true" />
  268. <cfargument name="value" type="any" hint="the value to set" required="true" />
  269. <cfargument name="expiry" type="numeric" hint="number of seconds until expire" default="0" required="true"/>
  270. <cfscript>
  271. var futureTask = "";
  272. var ret = "";
  273. try {
  274. ret = variables.memcached.replace(arguments.key,arguments.expiry,serialize(arguments.value));
  275. } catch (Any e) {
  276. // failing gracefully
  277. ret = "";
  278. }
  279. futureTask = createObject("component","FutureTask").init(ret);
  280. </cfscript>
  281. <cfreturn futureTask/>
  282. </cffunction>
  283. <cffunction name="set" access="public" output="false" returntype="any"
  284. hint="Set an object in the cache regardless of any existing value.
  285. Set an object in the cache regardless of any existing value.
  286. The exp value is passed along to memcached exactly as given,
  287. and will be processed per the memcached protocol specification:
  288. The actual value sent may either be Unix time (number of seconds since January 1, 1970,
  289. as a 32-bit value), or a number of seconds starting from current time.
  290. In the latter case, this number of seconds may not exceed 60*60*24*30
  291. (number of seconds in 30 days); if the number sent by a client is larger than that,
  292. the server will consider it to be real Unix time value rather than an offset from current time.
  293. RETURNS: a future Task representing the processing of the operation
  294. " >
  295. <cfargument name="key" type="string" hint="a single key to add" required="true" />
  296. <cfargument name="value" type="any" hint="the value to set" required="true" />
  297. <cfargument name="expiry" type="numeric" hint="number of seconds until expire" default="0" required="true"/>
  298. <cfscript>
  299. var futureTask = "";
  300. var ret = "";
  301. try {
  302. ret = variables.memcached.set(arguments.key,arguments.expiry,serialize(arguments.value));
  303. } catch (Any e) {
  304. // failing gracefully
  305. ret = "";
  306. }
  307. futureTask = createObject("component","FutureTask").init(ret);
  308. </cfscript>
  309. <cfreturn futureTask/>
  310. </cffunction>
  311. <!------------------ public util functions ------------------>
  312. <cffunction name="concatArrayQueries" access="public" returntype="any" output="false"
  313. hint="this will return either full query or an empty string if no queries are found.
  314. in the case of sending in an array full of null values, it will return an empty string" >
  315. <cfargument name="arrQueries" required="true" type="array">
  316. <cfscript>
  317. var mainQuery = "";
  318. var arrColumns = "";
  319. var ColumnLength = "";
  320. var i = 1;
  321. var j = 1;
  322. var currentRow = 1;
  323. for (i=1;i lte arrayLen(arrQueries);i=i+1) {
  324. if (isQuery(arrQueries[i]) and isQuery(mainQuery)) {
  325. currentRow = queryAddRow(mainQuery,1);
  326. for (j=1; j lte columnLength;j=j+1) {
  327. mainQuery[arrColumns[j]][currentRow] = arrQueries[i][arrColumns[j]][1];
  328. }
  329. } else if ( isQuery(arrQueries[i]) ) {
  330. mainQuery = duplicate(arrQueries[i]);
  331. arrColumns = listToArray(mainQuery.columnList);
  332. ColumnLength = arrayLen(arrColumns);
  333. }
  334. }
  335. </cfscript>
  336. <cfreturn mainQuery>
  337. </cffunction>
  338. <cffunction name="concatStructQueries" access="public" returntype="any" output="false"
  339. hint="this will return either full query or an empty string if no queries are found.
  340. in the case of sending in an array full of null values, it will return an empty string" >
  341. <cfargument name="structQueries" required="true" type="struct">
  342. <cfscript>
  343. var arrKeys = listtoarray(structKeyList(structQueries));
  344. var mainQuery = "";
  345. var arrColumns = "";
  346. var ColumnLength = "";
  347. var i = 1;
  348. var j = 1;
  349. var currentRow = 1;
  350. for (i=1;i lte arrayLen(arrKeys);i=i+1) {
  351. if (isQuery(structQueries[arrKeys[i]]) and isQuery(mainQuery)) {
  352. currentRow = queryAddRow(mainQuery,1);
  353. for (j=1; j lte columnLength;j=j+1) {
  354. mainQuery[arrColumns[j]][currentRow] = structQueries[arrKeys[i]][arrColumns[j]][1];
  355. }
  356. } else if ( isQuery(structQueries[arrKeys[i]]) ) {
  357. mainQuery = duplicate(structQueries[arrKeys[i]]);
  358. arrColumns = listToArray(mainQuery.columnList);
  359. ColumnLength = arrayLen(arrColumns);
  360. }
  361. }
  362. </cfscript>
  363. <cfreturn mainQuery>
  364. </cffunction>
  365. <Cffunction name="concatQueries" access="public" output="false" returntype="query"
  366. hint="queries need to be exactly the same">
  367. <cfargument name="query1" type="query" required="true">
  368. <cfargument name="query2" type="query" required="true">
  369. <cfargument name="arrColumns" type="array" required="false" default="#listToArray(Query1.columnList)#">
  370. <Cfscript>
  371. var columnLength = arrayLen(arrColumns);
  372. var currentRow = queryAddRow(query1,1);
  373. for (i=1; i lte query2.recordcount;i=i+1) {
  374. for (j=1; j lte columnLength;j=j+1) {
  375. query1[arrColumns[j]][currentRow] = query2[arrColumns[j]][i];
  376. }
  377. }
  378. </Cfscript>
  379. <cfreturn query1>
  380. </Cffunction>
  381. <cffunction name="createMemcachedKey" returnType="string" output="no" access="public"
  382. hint="create a key from a struct of input arguments">
  383. <cfargument name="keyStruct" type="struct" required="true">
  384. <cfargument name="prefix" type="string" required="false" default="">
  385. <cfset var cacheKey = "">
  386. <cfset var arrKeys = structkeyArray(arguments.keyStruct)>
  387. <cfset arraySort(arrKeys,"textnocase")>
  388. <cfloop from="1" to="#arrayLen(arrKeys)#" index="i">
  389. <cfset cacheKey = cacheKey.concat("#arrKeys[i]#=#arguments.keyStruct[arrKeys[i]]#")>
  390. </cfloop>
  391. <cfreturn arguments.prefix.concat(hash(cacheKey))>
  392. </cffunction>
  393. <!-------------------- admin functions ----------------------->
  394. <cffunction name="getTranscoder" access="public" output="false" returntype="Any"
  395. hint="Get the current transcoder that's in use." >
  396. <cfreturn variables.memcached.getTranscoder()/>
  397. </cffunction>
  398. <cffunction name="setTranscoder" access="public" output="false" returntype="void"
  399. hint="Set the transcoder for managing the cache representations of objects going in and out of the cache." >
  400. <cfargument name="transcoder" required="true" type="any" hint="Must be a transcoder object">
  401. <cfset variables.memcached.setTranscoder(arguments.transcoder)>
  402. </cffunction>
  403. <cffunction name="flush" access="public" output="false" returntype="any"
  404. hint="Flush all caches from all servers immediately or with a delay which is provided." >
  405. <cfargument name="delay" type="numeric" required="false" default="0" hint="Integer value - time in seconds to delay flushing cache">
  406. <cfscript>
  407. var ret = true;
  408. if (arguments.delay gt 0) {
  409. ret = variables.memcached.flush(arguments.delay);
  410. } else {
  411. ret = variables.memcached.flush();
  412. }
  413. </cfscript>
  414. <cfreturn ret/>
  415. </cffunction>
  416. <cffunction name="run" access="public" output="true" returntype="void"
  417. hint="Infinitely loop processing IO. what can we use this for?" >
  418. <cfreturn variables.memcached.run()/>
  419. </cffunction>
  420. <cffunction name="shutdown" access="public" output="false" returntype="boolean"
  421. hint="Shut down this client.">
  422. <cfargument name="timeout" required="false" type="numeric" default="0" hint="Integer number of units which to wait for the queue to die down">
  423. <cfargument name="timeUnit" required="false" type="any" hint="a time unit object - java.util.concurrent.TimeUnit">
  424. <cfscript>
  425. var ret = true;
  426. if (arguments.timeout gt 0) {
  427. ret = variables.memcached.shutdown(arguments.timeout,arguments.timeUnit);
  428. } else {
  429. ret = variables.memcached.shutdown();
  430. }
  431. </cfscript>
  432. <cfreturn ret/>
  433. </cffunction>
  434. <cffunction name="waitForQueues" access="public" output="false" returntype="boolean"
  435. hint="Wait for the queues to die down." >
  436. <cfargument name="timeout" required="true" type="numeric" default="0" hint="Integer number of units which to wait for the queue to die down">
  437. <cfargument name="timeUnit" required="true" type="any" default="#variables.timeUnit#" hint="a time unit object ">
  438. <cfscript>
  439. var ret = true;
  440. ret = variables.memcached.waitForQueues(arguments.timeout,arguments.timeUnit);
  441. </cfscript>
  442. <cfreturn ret/>
  443. </cffunction>
  444. <cffunction name="getVersions" access="public" output="false" returntype="struct"
  445. hint="Get the versions of all of the connected memcacheds. struct comes back as ">
  446. <!----------- there is a problem in here that if memcached is not running, this will hang
  447. this is a known problem with the underlying java client - which should be addressed soon.
  448. ------>
  449. <cfset var myVersions = variables.memcached.getVersions()>
  450. <cfset var ret = StructNew()>
  451. <cfif isdefined("myVersions")>
  452. <!------- checking isdefined here, just incase we get a java null back ---->
  453. <cfset ret = toStruct(myVersions)>
  454. </cfif>
  455. <cfreturn ret/>
  456. </cffunction>
  457. <cffunction name="getStats" access="public" output="false" returntype="any"
  458. hint="get all of the stats from all of the connections">
  459. <!----------- there is a problem in here that if memcached is not running, this will hang
  460. this is a known problem with the underlying java client which should be addressed soon.
  461. ------>
  462. <cfset var myStats = variables.memcached.getStats()>
  463. <cfset var ret = StructNew()>
  464. <cfif isdefined("myStats")>
  465. <!------- checking isdefined here, just incase we get a java null back ---->
  466. <cfset ret = toStruct(myStats)>
  467. </cfif>
  468. <cfreturn ret/>
  469. </cffunction>
  470. <cffunction name="stats" access="public" output="false" returntype="any"
  471. hint="get all of the stats from all of the connections">
  472. <!----------- there is a problem in here that if memcached is not running, this will hang
  473. this is a known problem with the underlying java client which should be addressed soon.
  474. this function here for compatability with other memcached client.
  475. ------>
  476. <cfreturn getStats()/>
  477. </cffunction>
  478. <!------------------ private util functions ------------------>
  479. <cffunction name="dateAddSeconds" access="private" output="false" returntype="date"
  480. hint="Converts a given number (seconds) to a future date-time.">
  481. <cfargument name="seconds" required="true" />
  482. <cfreturn DateAdd("s", arguments.seconds, Now()) />
  483. </cffunction>
  484. <cffunction name="toStruct" returntype="struct" access="private" output="false" hint="converts a java hashmap into a usable struct">
  485. <cfargument name="hashMap" type="Any" required="true">
  486. <!------- thanks to Ken Kolodziej for this snippet of code. it works great! -------->
  487. <cfscript>
  488. var theStruct = structNew();
  489. var key = "";
  490. var newStructKey = "";
  491. var keys = arguments.hashMap.keySet();
  492. var iter = keys.Iterator();
  493. while(iter.HasNext()) {
  494. key = iter.Next();
  495. newStructKey = key.toString();
  496. theStruct[newStructKey] = arguments.hashMap.get(key);
  497. }
  498. </cfscript>
  499. <cfreturn theStruct>
  500. </cffunction>
  501. </cfcomponent>