~ted/lazr-js/annoying-debug-message

« back to all changes in this revision

Viewing changes to src-js/lazrjs/yui/cache/cache-base-debug.js

  • Committer: Launchpad Patch Queue Manager
  • Date: 2010-09-09 14:20:30 UTC
  • mfrom: (182.1.3 yui-3.2)
  • Revision ID: launchpad@pqm.canonical.com-20100909142030-13w6vo0ixfysxc15
[r=beuno] Update lazr-js to yui-3.2

Show diffs side-by-side

added added

removed removed

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