Dashboard sipadu mbip
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

cache-base-debug.js 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444
  1. /*
  2. Copyright (c) 2010, Yahoo! Inc. All rights reserved.
  3. Code licensed under the BSD License:
  4. http://developer.yahoo.com/yui/license.html
  5. version: 3.4.0
  6. build: nightly
  7. */
  8. YUI.add('cache-base', function(Y) {
  9. /**
  10. * The Cache utility provides a common configurable interface for components to
  11. * cache and retrieve data from a local JavaScript struct.
  12. *
  13. * @module cache
  14. * @main
  15. */
  16. /**
  17. * Provides the base class for the YUI Cache utility.
  18. *
  19. * @submodule cache-base
  20. */
  21. var LANG = Y.Lang,
  22. isDate = Y.Lang.isDate,
  23. /**
  24. * Base class for the YUI Cache utility.
  25. * @class Cache
  26. * @extends Base
  27. * @constructor
  28. */
  29. Cache = function() {
  30. Cache.superclass.constructor.apply(this, arguments);
  31. };
  32. /////////////////////////////////////////////////////////////////////////////
  33. //
  34. // Cache static properties
  35. //
  36. /////////////////////////////////////////////////////////////////////////////
  37. Y.mix(Cache, {
  38. /**
  39. * Class name.
  40. *
  41. * @property NAME
  42. * @type String
  43. * @static
  44. * @final
  45. * @value "cache"
  46. */
  47. NAME: "cache",
  48. ATTRS: {
  49. /////////////////////////////////////////////////////////////////////////////
  50. //
  51. // Cache Attributes
  52. //
  53. /////////////////////////////////////////////////////////////////////////////
  54. /**
  55. * @attribute max
  56. * @description Maximum number of entries the Cache can hold.
  57. * Set to 0 to turn off caching.
  58. * @type Number
  59. * @default 0
  60. */
  61. max: {
  62. value: 0,
  63. setter: "_setMax"
  64. },
  65. /**
  66. * @attribute size
  67. * @description Number of entries currently cached.
  68. * @type Number
  69. */
  70. size: {
  71. readOnly: true,
  72. getter: "_getSize"
  73. },
  74. /**
  75. * @attribute uniqueKeys
  76. * @description Validate uniqueness of stored keys. Default is false and
  77. * is more performant.
  78. * @type Boolean
  79. */
  80. uniqueKeys: {
  81. value: false
  82. },
  83. /**
  84. * @attribute expires
  85. * @description Absolute Date when data expires or
  86. * relative number of milliseconds. Zero disables expiration.
  87. * @type Date | Number
  88. * @default 0
  89. */
  90. expires: {
  91. value: 0,
  92. validator: function(v) {
  93. return Y.Lang.isDate(v) || (Y.Lang.isNumber(v) && v >= 0);
  94. }
  95. },
  96. /**
  97. * @attribute entries
  98. * @description Cached entries.
  99. * @type Array
  100. */
  101. entries: {
  102. readOnly: true,
  103. getter: "_getEntries"
  104. }
  105. }
  106. });
  107. Y.extend(Cache, Y.Base, {
  108. /////////////////////////////////////////////////////////////////////////////
  109. //
  110. // Cache private properties
  111. //
  112. /////////////////////////////////////////////////////////////////////////////
  113. /**
  114. * Array of request/response objects indexed chronologically.
  115. *
  116. * @property _entries
  117. * @type Object[]
  118. * @private
  119. */
  120. _entries: null,
  121. /////////////////////////////////////////////////////////////////////////////
  122. //
  123. // Cache private methods
  124. //
  125. /////////////////////////////////////////////////////////////////////////////
  126. /**
  127. * @method initializer
  128. * @description Internal init() handler.
  129. * @param config {Object} Config object.
  130. * @private
  131. */
  132. initializer: function(config) {
  133. /**
  134. * @event add
  135. * @description Fired when an entry is added.
  136. * @param e {Event.Facade} Event Facade with the following properties:
  137. * <dl>
  138. * <dt>entry (Object)</dt> <dd>The cached entry.</dd>
  139. * </dl>
  140. * @preventable _defAddFn
  141. */
  142. this.publish("add", {defaultFn: this._defAddFn});
  143. /**
  144. * @event flush
  145. * @description Fired when the cache is flushed.
  146. * @param e {Event.Facade} Event Facade object.
  147. * @preventable _defFlushFn
  148. */
  149. this.publish("flush", {defaultFn: this._defFlushFn});
  150. /**
  151. * @event request
  152. * @description Fired when an entry is requested from the cache.
  153. * @param e {Event.Facade} Event Facade with the following properties:
  154. * <dl>
  155. * <dt>request (Object)</dt> <dd>The request object.</dd>
  156. * </dl>
  157. */
  158. /**
  159. * @event retrieve
  160. * @description Fired when an entry is retrieved from the cache.
  161. * @param e {Event.Facade} Event Facade with the following properties:
  162. * <dl>
  163. * <dt>entry (Object)</dt> <dd>The retrieved entry.</dd>
  164. * </dl>
  165. */
  166. // Initialize internal values
  167. this._entries = [];
  168. Y.log("Cache initialized", "info", "cache");
  169. },
  170. /**
  171. * @method destructor
  172. * @description Internal destroy() handler.
  173. * @private
  174. */
  175. destructor: function() {
  176. this._entries = [];
  177. Y.log("Cache destroyed", "info", "cache");
  178. },
  179. /////////////////////////////////////////////////////////////////////////////
  180. //
  181. // Cache protected methods
  182. //
  183. /////////////////////////////////////////////////////////////////////////////
  184. /**
  185. * Sets max.
  186. *
  187. * @method _setMax
  188. * @protected
  189. */
  190. _setMax: function(value) {
  191. // If the cache is full, make room by removing stalest element (index=0)
  192. var entries = this._entries;
  193. if(value > 0) {
  194. if(entries) {
  195. while(entries.length > value) {
  196. entries.shift();
  197. }
  198. }
  199. }
  200. else {
  201. value = 0;
  202. this._entries = [];
  203. }
  204. return value;
  205. },
  206. /**
  207. * Gets size.
  208. *
  209. * @method _getSize
  210. * @protected
  211. */
  212. _getSize: function() {
  213. return this._entries.length;
  214. },
  215. /**
  216. * Gets all entries.
  217. *
  218. * @method _getEntries
  219. * @protected
  220. */
  221. _getEntries: function() {
  222. return this._entries;
  223. },
  224. /**
  225. * Adds entry to cache.
  226. *
  227. * @method _defAddFn
  228. * @param e {Event.Facade} Event Facade with the following properties:
  229. * <dl>
  230. * <dt>entry (Object)</dt> <dd>The cached entry.</dd>
  231. * </dl>
  232. * @protected
  233. */
  234. _defAddFn: function(e) {
  235. var entries = this._entries,
  236. max = this.get("max"),
  237. entry = e.entry;
  238. if(this.get("uniqueKeys") && (this.retrieve(e.entry.request))) {
  239. entries.shift();
  240. }
  241. // If the cache at or over capacity, make room by removing stalest element (index=0)
  242. while(max && entries.length>=max) {
  243. entries.shift();
  244. }
  245. // Add entry to cache in the newest position, at the end of the array
  246. entries[entries.length] = entry;
  247. Y.log("Cached entry: " + Y.dump(entry), "info", "cache");
  248. },
  249. /**
  250. * Flushes cache.
  251. *
  252. * @method _defFlushFn
  253. * @param e {Event.Facade} Event Facade object.
  254. * @protected
  255. */
  256. _defFlushFn: function(e) {
  257. var entries = this._entries,
  258. details = e.details[0],
  259. pos;
  260. //passed an item, flush only that
  261. if(details && LANG.isValue(details.request)) {
  262. pos = this._position(details.request);
  263. if(LANG.isValue(pos)) {
  264. entries.splice(pos,1);
  265. Y.log("Flushed cache item " + Y.dump(details.request), "info", "cache");
  266. }
  267. }
  268. //no item, flush everything
  269. else {
  270. this._entries = [];
  271. Y.log("Cache flushed", "info", "cache");
  272. }
  273. },
  274. /**
  275. * Default overridable method compares current request with given cache entry.
  276. * Returns true if current request matches the cached request, otherwise
  277. * false. Implementers should override this method to customize the
  278. * cache-matching algorithm.
  279. *
  280. * @method _isMatch
  281. * @param request {Object} Request object.
  282. * @param entry {Object} Cached entry.
  283. * @return {Boolean} True if current request matches given cached request, false otherwise.
  284. * @protected
  285. */
  286. _isMatch: function(request, entry) {
  287. if(!entry.expires || new Date() < entry.expires) {
  288. return (request === entry.request);
  289. }
  290. return false;
  291. },
  292. /**
  293. * Returns position of a request in the entries array, otherwise null.
  294. *
  295. * @method _position
  296. * @param request {Object} Request object.
  297. * @return {Number} Array position if found, null otherwise.
  298. * @protected
  299. */
  300. _position: function(request) {
  301. // If cache is enabled...
  302. var entries = this._entries,
  303. length = entries.length,
  304. i = length-1;
  305. if((this.get("max") === null) || this.get("max") > 0) {
  306. // Loop through each cached entry starting from the newest
  307. for(; i >= 0; i--) {
  308. // Execute matching function
  309. if(this._isMatch(request, entries[i])) {
  310. return i;
  311. }
  312. }
  313. }
  314. return null;
  315. },
  316. /////////////////////////////////////////////////////////////////////////////
  317. //
  318. // Cache public methods
  319. //
  320. /////////////////////////////////////////////////////////////////////////////
  321. /**
  322. * Adds a new entry to the cache of the format
  323. * {request:request, response:response, cached:cached, expires:expires}.
  324. * If cache is full, evicts the stalest entry before adding the new one.
  325. *
  326. * @method add
  327. * @param request {Object} Request value.
  328. * @param response {Object} Response value.
  329. */
  330. add: function(request, response) {
  331. var expires = this.get("expires");
  332. if(this.get("initialized") && ((this.get("max") === null) || this.get("max") > 0) &&
  333. (LANG.isValue(request) || LANG.isNull(request) || LANG.isUndefined(request))) {
  334. this.fire("add", {entry: {
  335. request:request,
  336. response:response,
  337. cached: new Date(),
  338. expires: isDate(expires) ? expires :
  339. (expires ? new Date(new Date().getTime() + this.get("expires")) : null)
  340. }});
  341. }
  342. else {
  343. Y.log("Could not add " + Y.dump(response) + " to cache for " + Y.dump(request), "info", "cache");
  344. }
  345. },
  346. /**
  347. * Flushes cache.
  348. *
  349. * @method flush
  350. */
  351. flush: function(request) {
  352. this.fire("flush", { request: (LANG.isValue(request) ? request : null) });
  353. },
  354. /**
  355. * Retrieves cached object for given request, if available, and refreshes
  356. * entry in the cache. Returns null if there is no cache match.
  357. *
  358. * @method retrieve
  359. * @param request {Object} Request object.
  360. * @return {Object} Cached object with the properties request and response, or null.
  361. */
  362. retrieve: function(request) {
  363. // If cache is enabled...
  364. var entries = this._entries,
  365. length = entries.length,
  366. entry = null,
  367. pos;
  368. if((length > 0) && ((this.get("max") === null) || (this.get("max") > 0))) {
  369. this.fire("request", {request: request});
  370. pos = this._position(request);
  371. if(LANG.isValue(pos)) {
  372. entry = entries[pos];
  373. this.fire("retrieve", {entry: entry});
  374. // Refresh the position of the cache hit
  375. if(pos < length-1) {
  376. // Remove element from its original location
  377. entries.splice(pos,1);
  378. // Add as newest
  379. entries[entries.length] = entry;
  380. Y.log("Refreshed cache entry: " + Y.dump(entry) +
  381. " for request: " + Y.dump(request), "info", "cache");
  382. }
  383. Y.log("Retrieved cached response: " + Y.dump(entry) +
  384. " for request: " + Y.dump(request), "info", "cache");
  385. return entry;
  386. }
  387. }
  388. return null;
  389. }
  390. });
  391. Y.Cache = Cache;
  392. }, '3.4.0' ,{requires:['base']});