forked from ariatemplates/ariatemplates
/
IOFiltersMgr.js
426 lines (413 loc) · 17.5 KB
/
IOFiltersMgr.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
/*
* Copyright 2012 Amadeus s.a.s.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
(function () {
var typeUtils = aria.utils.Type;
var arrayUtils = aria.utils.Array;
// Mechanism to find filters.
/**
* Filter found. Is an item of the _filters array.
* @type {MultiTypes}
* @private
*/
var findFilterRes;
/**
* Filter to be found. Can be of any type accepted for the parameter of isFilterPresent.
* @type {Object}
* @private
*/
var findFilterSearch;
/**
* Return false if the given value matches the search (and no other value matched it before), supposing
* findFilterSearch is a classpath.
* @param {Object} value An item in the _filters array.
* @return {Boolean} false if the value matches the search, true otherwise
* @private
*/
var findByClasspath = function (value) {
if (!findFilterRes && value.filterClasspath === findFilterSearch) {
findFilterRes = value;
return false;
}
return true;
};
/**
* Return false if the given value matches the search (and no other value matched it before), supposing
* findFilterSearch is a filter instance.
* @param {Object} value An item in the _filters array.
* @return {Boolean} false if the value matches the search, true otherwise
* @private
*/
var findByInstance = function (value) {
if (!findFilterRes && value.obj === findFilterSearch) {
findFilterRes = value;
return false;
}
return true;
};
/**
* Return false if the given value matches the search (and no other value matched it before), supposing
* findFilterSearch is an object with the classpath and initArgs properties.
* @param {Object} value An item in the _filters array.
* @return {Boolean} false if the value matches the search, true otherwise
* @private
*/
var findByClasspathAndInitArgs = function (value) {
if (!findFilterRes && value.filterClasspath === findFilterSearch.classpath && value.hasOwnProperty("initArgs")
&& value.initArgs === findFilterSearch.initArgs) {
findFilterRes = value;
return false;
}
return true;
};
/**
* Initialize the search and return one of the findByClasspath, findByInstance or findByClasspathAndInitArgs
* functions depending on the type of the search parameter.
* @param {MultiTypes} search Filter to be found. Can be of any type accepted for the parameter of isFilterPresent.
* @return {Function} either null (if the search parameter has an unexpected type), or a reference to one of the
* findByClasspath, findByInstance or findByClasspathAndInitArgs functions.
* @private
*/
var getFindFilterFunction = function (search) {
findFilterRes = null;
findFilterSearch = search;
if (typeUtils.isString(search)) {
return findByClasspath;
} else if (typeUtils.isInstanceOf(search, "aria.core.IOFilter")) {
return findByInstance;
} else if (typeUtils.isObject(search)) {
return findByClasspathAndInitArgs;
} else {
return null;
}
};
/**
* Remove closure reference to filter search. This method should be called when getFindFilterFunction has done its
* job.
*/
var clean = function () {
findFilterSearch = null;
};
/**
* Manages filters for IO.
*/
Aria.classDefinition({
$classpath : "aria.core.IOFiltersMgr",
$singleton : true,
$constructor : function () {
/**
* Array of filter descriptors, each containing three properties: filterClasspath, initArgs and obj.
* @type {Array}
* @private
*/
this._filters = null;
/**
* Number of filters which were specified by their classpath and were not yet loaded.
* @type {Number}
* @private
*/
this._filtersToBeLoaded = 0;
},
$destructor : function () {
var filters = this._filters, itm;
if (filters) {
for (var index = 0, l = filters.length; index < l; index++) {
itm = filters[index];
if (itm.obj) {
itm.obj.$dispose();
itm.obj = null;
}
itm.initArgs = null;
}
this._filters = null;
}
},
$statics : {
INVALID_PARAMETER_FOR_ADDFILTER : "Invalid parameter for addFilter.",
INVALID_PARAMETER_FOR_ISFILTERPRESENT : "Invalid parameter for isFilterPresent.",
INVALID_PARAMETER_FOR_REMOVEFILTER : "Invalid parameter for removeFilter.",
FILTER_INSTANCE_ALREADY_PRESENT : "The same instance of the filter was already added to the list of filters."
},
$prototype : {
/**
* Add an IO filter.
* @param {MultiTypes} newFilter It can be one of the following possibilities:
* <ul>
* <li>An instance of a filter class.</li>
* <li>An object containing two properties: classpath and initArgs. In this case, the filter class with the
* given classpath will be instantiated when needed. Its constructor will be called with the given initArgs
* parameter.</li>
* <li>The classpath of a filter class (equivalent to the previous case, but with a null initArgs
* parameter).</li>
* </ul>
* Note that a filter class must extend aria.core.IOFilter. Two different instances of the same filter class
* can be added at the same time. However, the same instance cannot be added twice (in that case, an error
* is logged and this method returns false).
* @return {Boolean} Return true if the filter was successfully added and false if there was an error (in
* this case, an error is logged).
*/
addFilter : function (newFilter) {
var filterInfo = {};
if (typeUtils.isString(newFilter)) {
filterInfo.filterClasspath = newFilter;
filterInfo.initArgs = null;
this._filtersToBeLoaded++;
} else if (typeUtils.isInstanceOf(newFilter, "aria.core.IOFilter")) {
if (this.isFilterPresent(newFilter)) {
this.$logError(this.FILTER_INSTANCE_ALREADY_PRESENT);
return false;
}
filterInfo.filterClasspath = newFilter.$classpath;
filterInfo.obj = newFilter;
} else if (typeUtils.isObject(newFilter)) {
filterInfo.filterClasspath = newFilter.classpath;
filterInfo.initArgs = newFilter.initArgs;
this._filtersToBeLoaded++;
} else {
this.$logError(this.INVALID_PARAMETER_FOR_ADDFILTER);
return false;
}
if (!this._filters) {
this._filters = [];
}
this._filters[this._filters.length] = filterInfo;
return true;
},
/**
* Find if a filter is present in the list of filters.
* @param {MultiTypes} filter It can be one of the following possibilities:
* <ul>
* <li>An instance of a filter class.</li>
* <li>An object containing two properties: classpath and initArgs.</li>
* <li>The classpath of a filter class.</li>
* </ul>
* @return {Boolean} return true if the filter was found, false if no filter matching the conditions was
* found.
*/
isFilterPresent : function (filterDef) {
var filters = this._filters;
// stop here if there are no filters
if (!filters) {
return false;
}
var isWrongFilter = getFindFilterFunction(filterDef);
if (isWrongFilter == null) {
this.$logError(this.INVALID_PARAMETER_FOR_ISFILTERPRESENT);
clean();
return false;
}
for (var i = 0, l = filters.length; i < l; i++) {
if (!isWrongFilter(filters[i])) {
clean();
return true;
}
}
clean();
return false;
},
/**
* Remove a filter added with addFilter, and dispose it.
* @param {MultiTypes} oldFilter It can be one of the following possibilities:
* <ul>
* <li>An instance of a filter class.</li>
* <li>An object containing two properties: classpath and initArgs.</li>
* <li>The classpath of a filter class.</li>
* </ul>
* @return {Boolean} return true if a filter was removed, false if no filter matching the conditions was
* found.
*/
removeFilter : function (oldFilter) {
var filters = this._filters;
// stop here if there are no filters
if (!filters) {
return false;
}
var selectionCallback = getFindFilterFunction(oldFilter);
if (selectionCallback == null) {
this.$logError(this.INVALID_PARAMETER_FOR_REMOVEFILTER);
clean();
return false;
}
var newFiltersArray = arrayUtils.filter(filters, selectionCallback, this);
clean();
var filterToRemove = findFilterRes;
if (filterToRemove) {
if (filterToRemove.obj) {
// already loaded, dispose it
filterToRemove.obj.$dispose();
filterToRemove.obj = null;
} else {
// not yet loaded, prevent it to be loaded
this._filtersToBeLoaded--;
}
filterToRemove.filterClasspath = null;
filterToRemove.initArgs = null;
if (newFiltersArray.length === 0) {
this._filters = null;
} else {
this._filters = newFiltersArray;
}
return true;
}
return false;
},
/**
* Call the onRequest method on all the registered filters (and load the ones which are not yet loaded if
* necessary, and the sender is not the FileLoader).
* @param {aria.core.CfgBeans.IOAsyncRequestCfg} req request object
* @param {aria.core.JsObject.Callback} cb callback
*/
callFiltersOnRequest : function (req, cb) {
this._callFilters(false, req, cb);
},
/**
* Call the onResponse method on all the registered filters (and load the ones which are not yet loaded if
* necessary, and the sender is not the FileLoader).
* @param {aria.core.CfgBeans.IOAsyncRequestCfg} req request object
* @param {aria.core.JsObject.Callback} cb callback
*/
callFiltersOnResponse : function (req, cb) {
this._callFilters(true, req, cb);
},
/**
* If there are filters to be loaded, load them, then call all the filters.
* @param {Boolean} isResponse
* @param {aria.core.CfgBeans.IOAsyncRequestCfg} req request object
* @param {aria.core.JsObject.Callback} cb callback
* @private
*/
_callFilters : function (isResponse, request, cb) {
if (!this._filters) {
this.$callback(cb);
return;
}
var args = {
isResponse : isResponse,
request : request,
cb : cb,
filters : this._filters,
nbFilters : this._filters.length
// store the number of filters so that we do not call filters which were added after the call
// to _callFilters
};
if (this._filtersToBeLoaded > 0
&& (request.sender == null || request.sender.classpath != "aria.core.FileLoader")) {
this._loadMissingFilters({
fn : this._continueCallingFilters,
args : args,
scope : this
});
} else {
this._continueCallingFilters(null, args);
}
},
/**
* Effectively call filters in the right order.
* @param {MultiTypes} unused
* @param {Object} args object containing the following properties: isResponse, request, cb, filters and
* nbFilters
* @private
*/
_continueCallingFilters : function (unused, args) {
var filters = args.filters;
var request = args.request;
var curFilter;
// initialize the delay
request.delay = 0;
if (args.isResponse) {
for (var i = args.nbFilters - 1; i >= 0; i--) {
curFilter = filters[i].obj;
if (curFilter) {
curFilter.__onResponse(request);
}
}
} else {
for (var i = 0, l = args.nbFilters; i < l; i++) {
curFilter = filters[i].obj;
if (curFilter) {
curFilter.__onRequest(request);
}
}
}
if (request.delay > 0) {
// wait for the specified delay
aria.core.Timer.addCallback({
fn : this._afterDelay,
args : args,
scope : this,
delay : request.delay
});
} else {
this._afterDelay(args);
}
},
/**
* Call the callback after the delay.
* @param {Object} args object containing the following properties: isResponse, request, cb, filters and
* nbFilters
* @private
*/
_afterDelay : function (args) {
var request = args.request;
delete request.delay;
this.$callback(args.cb);
},
/**
* Load the filters which were added but not yet loaded.
* @param {aria.core.JsObject.Callback} cb callback to be called when the load of filters is finished
* @private
*/
_loadMissingFilters : function (cb) {
var filters = this._filters;
var curFilter;
var classpathsToLoad = [];
for (var i = 0, l = filters.length; i < l; i++) {
curFilter = filters[i];
if (curFilter.obj == null) {
classpathsToLoad.push(curFilter.filterClasspath);
}
}
Aria.load({
classes : classpathsToLoad,
oncomplete : {
fn : this._continueLoadingMissingFilters,
scope : this,
args : {
cb : cb,
filters : filters,
nbFilters : filters.length
}
}
});
},
/**
* Create instances of each filter once they are loaded.
* @param {Object} args object containing the following properties: cb, filters, nbFilters
* @private
*/
_continueLoadingMissingFilters : function (args) {
var filters = args.filters;
for (var i = 0, l = args.nbFilters; i < l; i++) {
var curFilter = filters[i];
// not that filterClasspath can be null if the filter was removed in the meantime.
if (curFilter.filterClasspath != null && curFilter.obj == null) {
curFilter.obj = Aria.getClassInstance(curFilter.filterClasspath, curFilter.initArgs);
this._filtersToBeLoaded--;
}
}
this.$callback(args.cb);
}
}
});
})();