UNPKG

27.5 kBJavaScriptView Raw
1/*!
2 * Pomelo -- proto
3 * Copyright(c) 2012 xiechengchao <xiecc@163.com>
4 * MIT Licensed
5 */
6
7/**
8 * Module dependencies.
9 */
10var utils = require('./util/utils');
11var logger = require('myhero-logger').getLogger('myhero', __filename);
12var EventEmitter = require('events').EventEmitter;
13var events = require('./util/events');
14var appUtil = require('./util/appUtil');
15var Constants = require('./util/constants');
16var appManager = require('./common/manager/appManager');
17var fs = require('fs');
18var path = require('path');
19
20/**
21 * Application prototype.
22 *
23 * @module
24 */
25var Application = module.exports = {};
26
27/**
28 * Application states
29 */
30var STATE_INITED = 1; // app has inited
31var STATE_START = 2; // app start
32var STATE_STARTED = 3; // app has started
33var STATE_STOPED = 4; // app has stoped
34
35/**
36 * Initialize the server.
37 *
38 * - setup default configuration
39 */
40Application.init = function (opts) {
41 opts = opts || {};
42 this.loaded = []; // loaded component list
43 this.components = {}; // name -> component map
44 this.settings = {}; // collection keep set/get
45 var base = opts.base || path.dirname(require.main.filename);
46 this.set(Constants.RESERVED.BASE, base, true);
47 this.event = new EventEmitter(); // event object to sub/pub events
48
49 // current server info
50 this.serverId = null; // current server id
51 this.serverType = null; // current server type
52 this.curServer = null; // current server info
53 this.startTime = null; // current server start time
54
55 // global server infos
56 this.master = null; // master server info
57 this.servers = {}; // current global server info maps, id -> info
58 this.serverTypeMaps = {}; // current global type maps, type -> [info]
59 this.serverTypes = []; // current global server type list
60 this.lifecycleCbs = {}; // current server custom lifecycle callbacks
61 this.clusterSeq = {}; // cluster id seqence
62
63 appUtil.defaultConfiguration(this);
64
65 this.state = STATE_INITED;
66 logger.info('application inited: %j', this.getServerId());
67};
68
69/**
70 * Get application base path
71 *
72 * // cwd: /home/game/
73 * pomelo start
74 * // app.getBase() -> /home/game
75 *
76 * @return {String} application base path
77 *
78 * @memberOf Application
79 */
80Application.getBase = function () {
81 return this.get(Constants.RESERVED.BASE);
82};
83
84/**
85 * Override require method in application
86 *
87 * @param {String} relative path of file
88 *
89 * @memberOf Application
90 */
91Application.require = function (ph) {
92 return require(path.join(Application.getBase(), ph));
93};
94
95/**
96 * Configure logger with {$base}/config/log4js.json
97 *
98 * @param {Object} logger pomelo-logger instance without configuration
99 *
100 * @memberOf Application
101 */
102Application.configureLogger = function (logger) {
103 if (process.env.POMELO_LOGGER !== 'off') {
104 var base = this.getBase();
105 var env = this.get(Constants.RESERVED.ENV);
106 var originPath = path.join(base, Constants.FILEPATH.LOG);
107 var presentPath = path.join(base, Constants.FILEPATH.CONFIG_DIR, env, path.basename(Constants.FILEPATH.LOG));
108 if (fs.existsSync(originPath)) {
109 logger.configure(originPath, {serverId: this.serverId, base: base});
110 } else if (fs.existsSync(presentPath)) {
111 logger.configure(presentPath, {serverId: this.serverId, base: base});
112 } else {
113 logger.error('logger file path configuration is error.');
114 }
115 }
116};
117
118/**
119 * add a filter to before and after filter
120 *
121 * @param {Object} filter provide before and after filter method.
122 * A filter should have two methods: before and after.
123 * @memberOf Application
124 */
125Application.filter = function (filter) {
126 this.before(filter);
127 this.after(filter);
128};
129
130/**
131 * Add before filter.
132 *
133 * @param {Object|Function} bf before fileter, bf(msg, session, next)
134 * @memberOf Application
135 */
136Application.before = function (bf) {
137 addFilter(this, Constants.KEYWORDS.BEFORE_FILTER, bf);
138};
139
140/**
141 * Add after filter.
142 *
143 * @param {Object|Function} af after filter, `af(err, msg, session, resp, next)`
144 * @memberOf Application
145 */
146Application.after = function (af) {
147 addFilter(this, Constants.KEYWORDS.AFTER_FILTER, af);
148};
149
150/**
151 * add a global filter to before and after global filter
152 *
153 * @param {Object} filter provide before and after filter method.
154 * A filter should have two methods: before and after.
155 * @memberOf Application
156 */
157Application.globalFilter = function (filter) {
158 this.globalBefore(filter);
159 this.globalAfter(filter);
160};
161
162/**
163 * Add global before filter.
164 *
165 * @param {Object|Function} bf before fileter, bf(msg, session, next)
166 * @memberOf Application
167 */
168Application.globalBefore = function (bf) {
169 addFilter(this, Constants.KEYWORDS.GLOBAL_BEFORE_FILTER, bf);
170};
171
172/**
173 * Add global after filter.
174 *
175 * @param {Object|Function} af after filter, `af(err, msg, session, resp, next)`
176 * @memberOf Application
177 */
178Application.globalAfter = function (af) {
179 addFilter(this, Constants.KEYWORDS.GLOBAL_AFTER_FILTER, af);
180};
181
182/**
183 * Add rpc before filter.
184 *
185 * @param {Object|Function} bf before fileter, bf(serverId, msg, opts, next)
186 * @memberOf Application
187 */
188Application.rpcBefore = function (bf) {
189 addFilter(this, Constants.KEYWORDS.RPC_BEFORE_FILTER, bf);
190};
191
192/**
193 * Add rpc after filter.
194 *
195 * @param {Object|Function} af after filter, `af(serverId, msg, opts, next)`
196 * @memberOf Application
197 */
198Application.rpcAfter = function (af) {
199 addFilter(this, Constants.KEYWORDS.RPC_AFTER_FILTER, af);
200};
201
202/**
203 * add a rpc filter to before and after rpc filter
204 *
205 * @param {Object} filter provide before and after filter method.
206 * A filter should have two methods: before and after.
207 * @memberOf Application
208 */
209Application.rpcFilter = function (filter) {
210 this.rpcBefore(filter);
211 this.rpcAfter(filter);
212};
213
214/**
215 * Load component
216 *
217 * @param {String} name (optional) name of the component
218 * @param {Object} component component instance or factory function of the component
219 * @param {[type]} opts (optional) construct parameters for the factory function
220 * @return {Object} app instance for chain invoke
221 * @memberOf Application
222 */
223Application.load = function (name, component, opts) {
224 if (typeof name !== 'string') {
225 opts = component;
226 component = name;
227 name = null;
228 if (typeof component.name === 'string') {
229 name = component.name;
230 }
231 }
232
233 if (typeof component === 'function') {
234 component = component(this, opts);
235 }
236
237 if (!name && typeof component.name === 'string') {
238 name = component.name;
239 }
240
241 if (name && this.components[name]) {
242 // ignore duplicat component
243 logger.warn('ignore duplicate component: %j', name);
244 return;
245 }
246
247 this.loaded.push(component);
248 if (name) {
249 // components with a name would get by name throught app.components later.
250 this.components[name] = component;
251 }
252
253 return this;
254};
255
256/**
257 * Load Configure json file to settings.(support different enviroment directory & compatible for old path)
258 *
259 * @param {String} key environment key
260 * @param {String} val environment value
261 * @param {Boolean} reload whether reload after change default false
262 * @return {Server|Mixed} for chaining, or the setting value
263 * @memberOf Application
264 */
265Application.loadConfigBaseApp = function (key, val, reload) {
266 var self = this;
267 var env = this.get(Constants.RESERVED.ENV);
268 var originPath = path.join(Application.getBase(), val);
269 var presentPath = path.join(Application.getBase(), Constants.FILEPATH.CONFIG_DIR, env, path.basename(val));
270 var realPath;
271 if (fs.existsSync(originPath)) {
272 realPath = originPath;
273 var file = require(originPath);
274 if (file[env]) {
275 file = file[env];
276 }
277 this.set(key, file);
278 } else if (fs.existsSync(presentPath)) {
279 realPath = presentPath;
280 var pfile = require(presentPath);
281 this.set(key, pfile);
282 } else {
283 logger.error('invalid configuration with file path: %s', key);
284 }
285
286 if (!!realPath && !!reload) {
287 fs.watch(realPath, function (event, filename) {
288 if (event === 'change') {
289 delete require.cache[require.resolve(realPath)];
290 self.loadConfigBaseApp(key, val);
291 }
292 });
293 }
294};
295
296/**
297 * Load Configure json file to settings.
298 *
299 * @param {String} key environment key
300 * @param {String} val environment value
301 * @return {Server|Mixed} for chaining, or the setting value
302 * @memberOf Application
303 */
304Application.loadConfig = function (key, val) {
305 var env = this.get(Constants.RESERVED.ENV);
306 val = require(val);
307 if (val[env]) {
308 val = val[env];
309 }
310 this.set(key, val);
311};
312
313/**
314 * Set the route function for the specified server type.
315 *
316 * Examples:
317 *
318 * app.route('area', routeFunc);
319 *
320 * var routeFunc = function(session, msg, app, cb) {
321 * // all request to area would be route to the first area server
322 * var areas = app.getServersByType('area');
323 * cb(null, areas[0].id);
324 * };
325 *
326 * @param {String} serverType server type string
327 * @param {Function} routeFunc route function. routeFunc(session, msg, app, cb)
328 * @return {Object} current application instance for chain invoking
329 * @memberOf Application
330 */
331Application.route = function (serverType, routeFunc) {
332 var routes = this.get(Constants.KEYWORDS.ROUTE);
333 if (!routes) {
334 routes = {};
335 this.set(Constants.KEYWORDS.ROUTE, routes);
336 }
337 routes[serverType] = routeFunc;
338 return this;
339};
340
341/**
342 * Set before stop function. It would perform before servers stop.
343 *
344 * @param {Function} fun before close function
345 * @return {Void}
346 * @memberOf Application
347 */
348Application.beforeStopHook = function (fun) {
349 logger.warn('this method was deprecated in pomelo 0.8');
350 if (!!fun && typeof fun === 'function') {
351 this.set(Constants.KEYWORDS.BEFORE_STOP_HOOK, fun);
352 }
353};
354
355/**
356 * Start application. It would load the default components and start all the loaded components.
357 *
358 * @param {Function} cb callback function
359 * @memberOf Application
360 */
361Application.start = function (cb) {
362 this.startTime = Date.now();
363 if (this.state > STATE_INITED) {
364 utils.invokeCallback(cb, new Error('application has already start.'));
365 return;
366 }
367
368 var self = this;
369 appUtil.startByType(self, function () {
370 appUtil.loadDefaultComponents(self);
371 var startUp = function () {
372 appUtil.optComponents(self.loaded, Constants.RESERVED.START, function (err) {
373 self.state = STATE_START;
374 if (err) {
375 utils.invokeCallback(cb, err);
376 } else {
377 logger.info('%j enter after start...', self.getServerId());
378 self.afterStart(cb);
379 }
380 });
381 };
382 var beforeFun = self.lifecycleCbs[Constants.LIFECYCLE.BEFORE_STARTUP];
383 if (!!beforeFun) {
384 beforeFun.call(null, self, startUp);
385 } else {
386 startUp();
387 }
388 });
389};
390
391/**
392 * Lifecycle callback for after start.
393 *
394 * @param {Function} cb callback function
395 * @return {Void}
396 */
397Application.afterStart = function (cb) {
398 if (this.state !== STATE_START) {
399 utils.invokeCallback(cb, new Error('application is not running now.'));
400 return;
401 }
402
403 var afterFun = this.lifecycleCbs[Constants.LIFECYCLE.AFTER_STARTUP];
404 var self = this;
405 appUtil.optComponents(this.loaded, Constants.RESERVED.AFTER_START, function (err) {
406 self.state = STATE_STARTED;
407 var id = self.getServerId();
408 if (!err) {
409 logger.info('%j finish start', id);
410 }
411 if (!!afterFun) {
412 afterFun.call(null, self, function () {
413 utils.invokeCallback(cb, err);
414 });
415 } else {
416 utils.invokeCallback(cb, err);
417 }
418 var usedTime = Date.now() - self.startTime;
419 logger.info('%j startup in %s ms', id, usedTime);
420 self.event.emit(events.START_SERVER, id);
421 });
422};
423
424/**
425 * Stop components.
426 *
427 * @param {Boolean} force whether stop the app immediately
428 */
429Application.stop = function (force) {
430 if (this.state > STATE_STARTED) {
431 logger.warn('[pomelo application] application is not running now.');
432 return;
433 }
434 this.state = STATE_STOPED;
435 var self = this;
436
437 this.stopTimer = setTimeout(function () {
438 process.exit(0);
439 }, Constants.TIME.TIME_WAIT_STOP);
440
441 var cancelShutDownTimer = function () {
442 if (!!self.stopTimer) {
443 clearTimeout(self.stopTimer);
444 }
445 };
446 var shutDown = function () {
447 appUtil.stopComps(self.loaded, 0, force, function () {
448 cancelShutDownTimer();
449 if (force) {
450 process.exit(0);
451 }
452 });
453 };
454 var fun = this.get(Constants.KEYWORDS.BEFORE_STOP_HOOK);
455 var stopFun = this.lifecycleCbs[Constants.LIFECYCLE.BEFORE_SHUTDOWN];
456 if (!!stopFun) {
457 stopFun.call(null, this, shutDown, cancelShutDownTimer);
458 } else if (!!fun) {
459 utils.invokeCallback(fun, self, shutDown, cancelShutDownTimer);
460 } else {
461 shutDown();
462 }
463};
464
465/**
466 * Assign `setting` to `val`, or return `setting`'s value.
467 *
468 * Example:
469 *
470 * app.set('key1', 'value1');
471 * app.get('key1'); // 'value1'
472 * app.key1; // undefined
473 *
474 * app.set('key2', 'value2', true);
475 * app.get('key2'); // 'value2'
476 * app.key2; // 'value2'
477 *
478 * @param {String} setting the setting of application
479 * @param {String} val the setting's value
480 * @param {Boolean} attach whether attach the settings to application
481 * @return {Server|Mixed} for chaining, or the setting value
482 * @memberOf Application
483 */
484Application.set = function (setting, val, attach) {
485 if (arguments.length === 1) {
486 return this.settings[setting];
487 }
488 this.settings[setting] = val;
489 if (attach) {
490 this[setting] = val;
491 }
492 return this;
493};
494
495/**
496 * Get property from setting
497 *
498 * @param {String} setting application setting
499 * @return {String} val
500 * @memberOf Application
501 */
502Application.get = function (setting) {
503 return this.settings[setting];
504};
505
506/**
507 * Check if `setting` is enabled.
508 *
509 * @param {String} setting application setting
510 * @return {Boolean}
511 * @memberOf Application
512 */
513Application.enabled = function (setting) {
514 return !!this.get(setting);
515};
516
517/**
518 * Check if `setting` is disabled.
519 *
520 * @param {String} setting application setting
521 * @return {Boolean}
522 * @memberOf Application
523 */
524Application.disabled = function (setting) {
525 return !this.get(setting);
526};
527
528/**
529 * Enable `setting`.
530 *
531 * @param {String} setting application setting
532 * @return {app} for chaining
533 * @memberOf Application
534 */
535Application.enable = function (setting) {
536 return this.set(setting, true);
537};
538
539/**
540 * Disable `setting`.
541 *
542 * @param {String} setting application setting
543 * @return {app} for chaining
544 * @memberOf Application
545 */
546Application.disable = function (setting) {
547 return this.set(setting, false);
548};
549
550/**
551 * Configure callback for the specified env and server type.
552 * When no env is specified that callback will
553 * be invoked for all environments and when no type is specified
554 * that callback will be invoked for all server types.
555 *
556 * Examples:
557 *
558 * app.configure(function(){
559 * // executed for all envs and server types
560 * });
561 *
562 * app.configure('development', function(){
563 * // executed development env
564 * });
565 *
566 * app.configure('development', 'connector', function(){
567 * // executed for development env and connector server type
568 * });
569 *
570 * @param {String} env application environment
571 * @param {Function} fn callback function
572 * @param {String} type server type
573 * @return {Application} for chaining
574 * @memberOf Application
575 */
576Application.configure = function (env, type, fn) {
577 var args = [].slice.call(arguments);
578 fn = args.pop();
579 env = type = Constants.RESERVED.ALL;
580
581 if (args.length > 0) {
582 env = args[0];
583 }
584 if (args.length > 1) {
585 type = args[1];
586 }
587
588 if (env === Constants.RESERVED.ALL || contains(this.settings.env, env)) {
589 if (type === Constants.RESERVED.ALL || contains(this.settings.serverType, type)) {
590 fn.call(this);
591 }
592 }
593 return this;
594};
595
596/**
597 * Register admin modules. Admin modules is the extends point of the monitor system.
598 *
599 * @param {String} module (optional) module id or provoided by module.moduleId
600 * @param {Object} module module object or factory function for module
601 * @param {Object} opts construct parameter for module
602 * @memberOf Application
603 */
604Application.registerAdmin = function (moduleId, module, opts) {
605 var modules = this.get(Constants.KEYWORDS.MODULE);
606 if (!modules) {
607 modules = {};
608 this.set(Constants.KEYWORDS.MODULE, modules);
609 }
610
611 if (typeof moduleId !== 'string') {
612 opts = module;
613 module = moduleId;
614 if (module) {
615 moduleId = module.moduleId;
616 }
617 }
618
619 if (!moduleId) {
620 return;
621 }
622
623 modules[moduleId] = {
624 moduleId: moduleId,
625 module: module,
626 opts: opts
627 };
628};
629
630/**
631 * Use plugin.
632 *
633 * @param {Object} plugin plugin instance
634 * @param {[type]} opts (optional) construct parameters for the factory function
635 * @memberOf Application
636 */
637Application.use = function (plugin, opts) {
638 if (!plugin.components) {
639 logger.error('invalid components, no components exist');
640 return;
641 }
642
643 var self = this;
644 opts = opts || {};
645 var dir = path.dirname(plugin.components);
646
647 if (!fs.existsSync(plugin.components)) {
648 logger.error('fail to find components, find path: %s', plugin.components);
649 return;
650 }
651
652 fs.readdirSync(plugin.components).forEach(function (filename) {
653 if (!/\.js$/.test(filename)) {
654 return;
655 }
656 var name = path.basename(filename, '.js');
657 var param = opts[name] || {};
658 var absolutePath = path.join(dir, Constants.DIR.COMPONENT, filename);
659 if (!fs.existsSync(absolutePath)) {
660 logger.error('component %s not exist at %s', name, absolutePath);
661 } else {
662 self.load(require(absolutePath), param);
663 }
664 });
665
666 // load events
667 if (!plugin.events) {
668 return;
669 } else {
670 if (!fs.existsSync(plugin.events)) {
671 logger.error('fail to find events, find path: %s', plugin.events);
672 return;
673 }
674
675 fs.readdirSync(plugin.events).forEach(function (filename) {
676 if (!/\.js$/.test(filename)) {
677 return;
678 }
679 var absolutePath = path.join(dir, Constants.DIR.EVENT, filename);
680 if (!fs.existsSync(absolutePath)) {
681 logger.error('events %s not exist at %s', filename, absolutePath);
682 } else {
683 bindEvents(require(absolutePath), self);
684 }
685 });
686 }
687};
688
689/**
690 * Application transaction. Transcation includes conditions and handlers, if conditions are satisfied, handlers would be executed.
691 * And you can set retry times to execute handlers. The transaction log is in file logs/transaction.log.
692 *
693 * @param {String} name transaction name
694 * @param {Object} conditions functions which are called before transaction
695 * @param {Object} handlers functions which are called during transaction
696 * @param {Number} retry retry times to execute handlers if conditions are successfully executed
697 * @memberOf Application
698 */
699Application.transaction = function (name, conditions, handlers, retry) {
700 appManager.transaction(name, conditions, handlers, retry);
701};
702
703/**
704 * Get master server info.
705 *
706 * @return {Object} master server info, {id, host, port}
707 * @memberOf Application
708 */
709Application.getMaster = function () {
710 return this.master;
711};
712
713/**
714 * Get current server info.
715 *
716 * @return {Object} current server info, {id, serverType, host, port}
717 * @memberOf Application
718 */
719Application.getCurServer = function () {
720 return this.curServer;
721};
722
723/**
724 * Get current server id.
725 *
726 * @return {String|Number} current server id from servers.json
727 * @memberOf Application
728 */
729Application.getServerId = function () {
730 return this.serverId;
731};
732
733/**
734 * Get current server type.
735 *
736 * @return {String|Number} current server type from servers.json
737 * @memberOf Application
738 */
739Application.getServerType = function () {
740 return this.serverType;
741};
742
743/**
744 * Get all the current server infos.
745 *
746 * @return {Object} server info map, key: server id, value: server info
747 * @memberOf Application
748 */
749Application.getServers = function () {
750 return this.servers;
751};
752
753/**
754 * Get all server infos from servers.json.
755 *
756 * @return {Object} server info map, key: server id, value: server info
757 * @memberOf Application
758 */
759Application.getServersFromConfig = function () {
760 return this.get(Constants.KEYWORDS.SERVER_MAP);
761};
762
763/**
764 * Get all the server type.
765 *
766 * @return {Array} server type list
767 * @memberOf Application
768 */
769Application.getServerTypes = function () {
770 return this.serverTypes;
771};
772
773/**
774 * Get server info by server id from current server cluster.
775 *
776 * @param {String} serverId server id
777 * @return {Object} server info or undefined
778 * @memberOf Application
779 */
780Application.getServerById = function (serverId) {
781 return this.servers[serverId];
782};
783
784/**
785 * Get server info by server id from servers.json.
786 *
787 * @param {String} serverId server id
788 * @return {Object} server info or undefined
789 * @memberOf Application
790 */
791
792Application.getServerFromConfig = function (serverId) {
793 return this.get(Constants.KEYWORDS.SERVER_MAP)[serverId];
794};
795
796/**
797 * Get server infos by server type.
798 *
799 * @param {String} serverType server type
800 * @return {Array} server info list
801 * @memberOf Application
802 */
803Application.getServersByType = function (serverType) {
804 return this.serverTypeMaps[serverType];
805};
806
807/**
808 * Check the server whether is a frontend server
809 *
810 * @param {server} server server info. it would check current server
811 * if server not specified
812 * @return {Boolean}
813 *
814 * @memberOf Application
815 */
816Application.isFrontend = function (server) {
817 server = server || this.getCurServer();
818 return !!server && server.frontend === 'true';
819};
820
821/**
822 * Check the server whether is a backend server
823 *
824 * @param {server} server server info. it would check current server
825 * if server not specified
826 * @return {Boolean}
827 * @memberOf Application
828 */
829Application.isBackend = function (server) {
830 server = server || this.getCurServer();
831 return !!server && !server.frontend;
832};
833
834/**
835 * Check whether current server is a master server
836 *
837 * @return {Boolean}
838 * @memberOf Application
839 */
840Application.isMaster = function () {
841 return this.serverType === Constants.RESERVED.MASTER;
842};
843
844/**
845 * Add new server info to current application in runtime.
846 *
847 * @param {Array} servers new server info list
848 * @memberOf Application
849 */
850Application.addServers = function (servers) {
851 if (!servers || !servers.length) {
852 return;
853 }
854
855 var item, slist;
856 for (var i = 0, l = servers.length; i < l; i++) {
857 item = servers[i];
858 // update global server map
859 this.servers[item.id] = item;
860
861 // update global server type map
862 slist = this.serverTypeMaps[item.serverType];
863 if (!slist) {
864 this.serverTypeMaps[item.serverType] = slist = [];
865 }
866 replaceServer(slist, item);
867
868 // update global server type list
869 if (this.serverTypes.indexOf(item.serverType) < 0) {
870 this.serverTypes.push(item.serverType);
871 }
872 }
873 this.event.emit(events.ADD_SERVERS, servers);
874};
875
876/**
877 * Remove server info from current application at runtime.
878 *
879 * @param {Array} ids server id list
880 * @memberOf Application
881 */
882Application.removeServers = function (ids) {
883 if (!ids || !ids.length) {
884 return;
885 }
886
887 var id, item, slist;
888 for (var i = 0, l = ids.length; i < l; i++) {
889 id = ids[i];
890 item = this.servers[id];
891 if (!item) {
892 continue;
893 }
894 // clean global server map
895 delete this.servers[id];
896
897 // clean global server type map
898 slist = this.serverTypeMaps[item.serverType];
899 removeServer(slist, id);
900 // TODO: should remove the server type if the slist is empty?
901 }
902 this.event.emit(events.REMOVE_SERVERS, ids);
903};
904
905/**
906 * Replace server info from current application at runtime.
907 *
908 * @param {Object} server id map
909 * @memberOf Application
910 */
911Application.replaceServers = function (servers) {
912 if (!servers) {
913 return;
914 }
915
916 this.servers = servers;
917 this.serverTypeMaps = {};
918 this.serverTypes = [];
919 var serverArray = [];
920 for (var id in servers) {
921 var server = servers[id];
922 var serverType = server[Constants.RESERVED.SERVER_TYPE];
923 var slist = this.serverTypeMaps[serverType];
924 if (!slist) {
925 this.serverTypeMaps[serverType] = slist = [];
926 }
927 this.serverTypeMaps[serverType].push(server);
928 // update global server type list
929 if (this.serverTypes.indexOf(serverType) < 0) {
930 this.serverTypes.push(serverType);
931 }
932 serverArray.push(server);
933 }
934 this.event.emit(events.REPLACE_SERVERS, serverArray);
935};
936
937/**
938 * Add crons from current application at runtime.
939 *
940 * @param {Array} crons new crons would be added in application
941 * @memberOf Application
942 */
943Application.addCrons = function (crons) {
944 if (!crons || !crons.length) {
945 logger.warn('crons is not defined.');
946 return;
947 }
948 this.event.emit(events.ADD_CRONS, crons);
949};
950
951/**
952 * Remove crons from current application at runtime.
953 *
954 * @param {Array} crons old crons would be removed in application
955 * @memberOf Application
956 */
957Application.removeCrons = function (crons) {
958 if (!crons || !crons.length) {
959 logger.warn('ids is not defined.');
960 return;
961 }
962 this.event.emit(events.REMOVE_CRONS, crons);
963};
964
965var replaceServer = function (slist, serverInfo) {
966 for (var i = 0, l = slist.length; i < l; i++) {
967 if (slist[i].id === serverInfo.id) {
968 slist[i] = serverInfo;
969 return;
970 }
971 }
972 slist.push(serverInfo);
973};
974
975var removeServer = function (slist, id) {
976 if (!slist || !slist.length) {
977 return;
978 }
979
980 for (var i = 0, l = slist.length; i < l; i++) {
981 if (slist[i].id === id) {
982 slist.splice(i, 1);
983 return;
984 }
985 }
986};
987
988var contains = function (str, settings) {
989 if (!settings) {
990 return false;
991 }
992
993 var ts = settings.split("|");
994 for (var i = 0, l = ts.length; i < l; i++) {
995 if (str === ts[i]) {
996 return true;
997 }
998 }
999 return false;
1000};
1001
1002var bindEvents = function (Event, app) {
1003 var emethods = new Event(app);
1004 for (var m in emethods) {
1005 if (typeof emethods[m] === 'function') {
1006 app.event.on(m, emethods[m].bind(emethods));
1007 }
1008 }
1009};
1010
1011var addFilter = function (app, type, filter) {
1012 var filters = app.get(type);
1013 if (!filters) {
1014 filters = [];
1015 app.set(type, filters);
1016 }
1017 filters.push(filter);
1018};