2
Copyright (c) 2010, Yahoo! Inc. All rights reserved.
3
Code licensed under the BSD License:
4
http://developer.yahoo.com/yui/license.html
8
YUI.add('cache-base', function(Y) {
11
* The Cache utility provides a common configurable interface for components to
12
* cache and retrieve data from a local JavaScript struct.
17
isDate = Y.Lang.isDate,
20
* Base class for the YUI Cache utility.
26
Cache.superclass.constructor.apply(this, arguments);
29
/////////////////////////////////////////////////////////////////////////////
31
// Cache static properties
33
/////////////////////////////////////////////////////////////////////////////
48
/////////////////////////////////////////////////////////////////////////////
52
/////////////////////////////////////////////////////////////////////////////
56
* @description Maximum number of entries the Cache can hold.
57
* Set to 0 to turn off caching.
68
* @description Number of entries currently cached.
77
* @attribute uniqueKeys
78
* @description Validate uniqueness of stored keys. Default is false and
88
* @description Absolute Date when data expires or
89
* relative number of milliseconds. Zero disables expiration.
95
validator: function(v) {
96
return Y.Lang.isDate(v) || (Y.Lang.isNumber(v) && v >= 0);
102
* @description Cached entries.
107
getter: "_getEntries"
112
Y.extend(Cache, Y.Base, {
113
/////////////////////////////////////////////////////////////////////////////
115
// Cache private properties
117
/////////////////////////////////////////////////////////////////////////////
120
* Array of request/response objects indexed chronologically.
128
/////////////////////////////////////////////////////////////////////////////
130
// Cache private methods
132
/////////////////////////////////////////////////////////////////////////////
135
* @method initializer
136
* @description Internal init() handler.
137
* @param config {Object} Config object.
140
initializer: function(config) {
144
* @description Fired when an entry is added.
145
* @param e {Event.Facade} Event Facade with the following properties:
147
* <dt>entry (Object)</dt> <dd>The cached entry.</dd>
149
* @preventable _defAddFn
151
this.publish("add", {defaultFn: this._defAddFn});
155
* @description Fired when the cache is flushed.
156
* @param e {Event.Facade} Event Facade object.
157
* @preventable _defFlushFn
159
this.publish("flush", {defaultFn: this._defFlushFn});
163
* @description Fired when an entry is requested from the cache.
164
* @param e {Event.Facade} Event Facade with the following properties:
166
* <dt>request (Object)</dt> <dd>The request object.</dd>
172
* @description Fired when an entry is retrieved from the cache.
173
* @param e {Event.Facade} Event Facade with the following properties:
175
* <dt>entry (Object)</dt> <dd>The retrieved entry.</dd>
179
// Initialize internal values
181
Y.log("Cache initialized", "info", "cache");
186
* @description Internal destroy() handler.
189
destructor: function() {
191
Y.log("Cache destroyed", "info", "cache");
194
/////////////////////////////////////////////////////////////////////////////
196
// Cache protected methods
198
/////////////////////////////////////////////////////////////////////////////
206
_setMax: function(value) {
207
// If the cache is full, make room by removing stalest element (index=0)
208
var entries = this._entries;
211
while(entries.length > value) {
229
_getSize: function() {
230
return this._entries.length;
236
* @method _getEntries
239
_getEntries: function() {
240
return this._entries;
245
* Adds entry to cache.
248
* @param e {Event.Facade} Event Facade with the following properties:
250
* <dt>entry (Object)</dt> <dd>The cached entry.</dd>
254
_defAddFn: function(e) {
255
var entries = this._entries,
256
max = this.get("max"),
259
if(this.get("uniqueKeys") && (this.retrieve(e.entry.request))) {
264
// If the cache at or over capacity, make room by removing stalest element (index=0)
265
while(max && entries.length>=max) {
269
// Add entry to cache in the newest position, at the end of the array
270
entries[entries.length] = entry;
271
Y.log("Cached entry: " + Y.dump(entry), "info", "cache");
277
* @method _defFlushFn
278
* @param e {Event.Facade} Event Facade object.
281
_defFlushFn: function(e) {
283
Y.log("Cache flushed", "info", "cache");
287
* Default overridable method compares current request with given cache entry.
288
* Returns true if current request matches the cached request, otherwise
289
* false. Implementers should override this method to customize the
290
* cache-matching algorithm.
293
* @param request {Object} Request object.
294
* @param entry {Object} Cached entry.
295
* @return {Boolean} True if current request matches given cached request, false otherwise.
298
_isMatch: function(request, entry) {
299
if(!entry.expires || new Date() < entry.expires) {
300
return (request === entry.request);
305
/////////////////////////////////////////////////////////////////////////////
307
// Cache public methods
309
/////////////////////////////////////////////////////////////////////////////
312
* Adds a new entry to the cache of the format
313
* {request:request, response:response, cached:cached, expires:expires}.
314
* If cache is full, evicts the stalest entry before adding the new one.
317
* @param request {Object} Request value.
318
* @param response {Object} Response value.
320
add: function(request, response) {
321
var expires = this.get("expires");
322
if(this.get("initialized") && ((this.get("max") === null) || this.get("max") > 0) &&
323
(LANG.isValue(request) || LANG.isNull(request) || LANG.isUndefined(request))) {
324
this.fire("add", {entry: {
328
expires: isDate(expires) ? expires :
329
(expires ? new Date(new Date().getTime() + this.get("expires")) : null)
333
Y.log("Could not add " + Y.dump(response) + " to cache for " + Y.dump(request), "info", "cache");
347
* Retrieves cached object for given request, if available, and refreshes
348
* entry in the cache. Returns null if there is no cache match.
351
* @param request {Object} Request object.
352
* @return {Object} Cached object with the properties request and response, or null.
354
retrieve: function(request) {
355
// If cache is enabled...
356
var entries = this._entries,
357
length = entries.length,
361
if((length > 0) && ((this.get("max") === null) || (this.get("max") > 0))) {
362
this.fire("request", {request: request});
364
// Loop through each cached entry starting from the newest
368
// Execute matching function
369
if(this._isMatch(request, entry)) {
370
this.fire("retrieve", {entry: entry});
372
// Refresh the position of the cache hit
374
// Remove element from its original location
377
entries[entries.length] = entry;
378
Y.log("Refreshed cache entry: " + Y.dump(entry) +
379
" for request: " + Y.dump(request), "info", "cache");
382
Y.log("Retrieved cached response: " + Y.dump(entry) +
383
" for request: " + Y.dump(request), "info", "cache");
396
}, '3.2.0' ,{requires:['base']});