@@ -8,6 +8,31 @@ module.exports = class ApplicationContext {
88
99 static DEFAULT_CONTEXT_NAME = 'default' ;
1010 static DEFAULT_CONFIG_CONTEXT_PATH = 'context' ;
11+
12+ static getGlobalRef ( ) {
13+ let $globalref = null ;
14+ if ( ApplicationContext . detectBrowser ( ) ) {
15+ $globalref = window ;
16+ } else {
17+ $globalref = global ;
18+ }
19+ return $globalref ;
20+ }
21+
22+ static getGlobalRoot ( key ) {
23+ const $globalref = ApplicationContext . getGlobalRef ( ) ;
24+ let $key = ( $globalref && $globalref . boot ) ;
25+ $key = $key && $key . contexts ;
26+ $key = $key && $key . root ;
27+ $key = $key && $key [ `${ key } ` ] ;
28+ return $key ;
29+ }
30+
31+ static detectBrowser ( ) {
32+ const browser = ! ( typeof window === 'undefined' ) ;
33+ return browser ;
34+ }
35+
1136 constructor ( options ) {
1237 let contexts = options ?. contexts || options ;
1338 this . contexts = _ . isArray ( contexts ) ? contexts : ( contexts ? [ contexts ] : [ ] ) ;
@@ -27,12 +52,14 @@ module.exports = class ApplicationContext {
2752 }
2853 }
2954
30- lifeCycle ( ) {
55+ async lifeCycle ( ) {
3156 logger . verbose ( `ApplicationContext (${ this . name } ) lifecycle started.` ) ;
32- this . parseContexts ( this . contexts , this . components , this . profiles , this . name ) ;
33- this . createSingletons ( this . components ) ;
34- this . injectSingletonDependencies ( this . components ) ;
35- logger . verbose ( `ApplicationContext (${ this . name } ) lifecycle completed.` ) ;
57+ this . parseContexts ( ) ;
58+ this . createSingletons ( ) ;
59+ this . injectSingletonDependencies ( ) ;
60+ this . initialiseSingletons ( ) ;
61+ this . registerSingletonDestroyers ( ) ;
62+ this . run ( ) ;
3663 }
3764
3865 detectConfigContext ( ) {
@@ -46,6 +73,39 @@ module.exports = class ApplicationContext {
4673 logger . verbose ( 'Detecting config contexts completed.' ) ;
4774 }
4875
76+ detectGlobalContextComponents ( ) {
77+ logger . verbose ( 'Detecting global context components started.' ) ;
78+
79+ if ( ! this . components [ 'config' ] && ApplicationContext . getGlobalRoot ( 'config' ) ) {
80+ this . deriveContextComponent ( {
81+ Reference :ApplicationContext . getGlobalRoot ( 'config' ) ,
82+ name :'config' } )
83+ }
84+ if ( ! this . components [ 'loggerFactory' ] && ApplicationContext . getGlobalRoot ( 'loggerFactory' ) ) {
85+ this . deriveContextComponent ( {
86+ Reference :ApplicationContext . getGlobalRoot ( 'loggerFactory' ) ,
87+ name :'loggerFactory' } )
88+ }
89+ if ( ! this . components [ 'loggerCategoryCache' ] && ApplicationContext . getGlobalRoot ( 'loggerCategoryCache' ) ) {
90+ this . deriveContextComponent ( {
91+ Reference :ApplicationContext . getGlobalRoot ( 'loggerCategoryCache' ) ,
92+ name :'loggerCategoryCache' } )
93+ }
94+ if ( ! this . components [ 'logger' ] ) {
95+ this . deriveContextComponent ( {
96+ scope : Scopes . PROTOTYPE ,
97+ wireFactory :'loggerFactory' ,
98+ name :'logger' } )
99+ }
100+ if ( ! this . components [ 'fetch' ] && ApplicationContext . getGlobalRoot ( 'fetch' ) ) {
101+ this . deriveContextComponent ( {
102+ Reference :ApplicationContext . getGlobalRoot ( 'fetch' ) ,
103+ name :'fetch' } )
104+ }
105+
106+ logger . verbose ( 'Detecting global context components completed.' ) ;
107+ }
108+
49109 parseContexts ( ) {
50110 logger . verbose ( 'Parsing configured contexts started.' ) ;
51111 this . detectConfigContext ( ) ;
@@ -62,6 +122,7 @@ module.exports = class ApplicationContext {
62122 throw msg ;
63123 }
64124 }
125+ this . detectGlobalContextComponents ( ) ;
65126 logger . verbose ( 'Parsing configured contexts completed.' ) ;
66127 }
67128
@@ -78,6 +139,7 @@ module.exports = class ApplicationContext {
78139 }
79140 }
80141 }
142+
81143 parseContextComponents ( context ) {
82144 logger . verbose ( 'Processing context components started' ) ;
83145 if ( context . components ) {
@@ -159,6 +221,12 @@ module.exports = class ApplicationContext {
159221 if ( component . scope === Scopes . SINGLETON ) {
160222 if ( component . isClass ) {
161223 component . instance = new component . Reference ( ) ;
224+ } else if ( typeof component . factory === 'function' ) {
225+ let args = component . factoryArgs ;
226+ if ( ! Array . isArray ( args ) ) {
227+ args = [ args ] ;
228+ }
229+ component . instance = new component . factory ( ...args ) ;
162230 } else {
163231 component . instance = component . Reference ;
164232 }
@@ -182,10 +250,10 @@ module.exports = class ApplicationContext {
182250 const property = instance [ insKeys [ j ] ] ;
183251 const autowire = property ?. name === 'Autowired' || _ . lowerCase ( property ) === 'autowired' ;
184252 if ( autowire ) {
185- instance [ insKeys [ j ] ] = this . get ( insKeys [ j ] ) ;
253+ instance [ insKeys [ j ] ] = this . get ( insKeys [ j ] , undefined , component ) ;
186254 logger . verbose ( `Explicitly autowired component (${ component . name } ) property (${ insKeys [ j ] } ) from context.` ) ;
187255 } else if ( instance [ insKeys [ j ] ] == null ) {
188- instance [ insKeys [ j ] ] = this . get ( insKeys [ j ] , instance [ insKeys [ j ] ] ) ;
256+ instance [ insKeys [ j ] ] = this . get ( insKeys [ j ] , instance [ insKeys [ j ] ] , component ) ;
189257 if ( instance [ insKeys [ j ] ] != null ) {
190258 logger . verbose ( `Implicitly autowired null component (${ component . name } ) property (${ insKeys [ j ] } ) from context.` ) ;
191259 }
@@ -212,7 +280,7 @@ module.exports = class ApplicationContext {
212280 }
213281 if ( typeof property . name === 'string' ) {
214282 if ( typeof property . reference ) {
215- component . instance [ property . name ] = this . get ( property . reference ) ;
283+ component . instance [ property . name ] = this . get ( property . reference , undefined , component ) ;
216284 logger . verbose ( `Explicitly wired component (${ component . name } ) property (${ property . name } ) with context reference (${ property . reference } ).` ) ;
217285 }
218286 if ( property . value ) {
@@ -223,10 +291,6 @@ module.exports = class ApplicationContext {
223291 component . instance [ property . name ] = this . config . get ( property . path , property . defaultValue ) ;
224292 logger . verbose ( `Explicitly wired component (${ component . name } ) property (${ property . name } ) from config path (${ property . path } ).` ) ;
225293 }
226- if ( property . factory && property . function ) {
227- component . instance [ property . name ] = this . get ( property . path ) [ property . method ] ( property . args ) ;
228- logger . verbose ( `Explicitly wired component (${ component . name } ) property (${ property . name } ) from context factory function (${ property . function } .${ factory . function } ).` ) ;
229- }
230294 }
231295 }
232296
@@ -254,7 +318,71 @@ module.exports = class ApplicationContext {
254318 logger . verbose ( 'Injecting singleton dependencies completed' ) ;
255319 }
256320
257- get ( reference , defaultValue ) {
321+ initialiseSingletons ( ) {
322+ logger . verbose ( 'Initialising singletons started' ) ;
323+ const keys = Object . keys ( this . components ) ;
324+ for ( let i = 0 ; i < keys . length ; i ++ ) {
325+ const component = this . components [ keys [ i ] ] ;
326+ if ( component . scope === Scopes . SINGLETON ) {
327+ if ( typeof component . instance . init === 'function' ) {
328+ component . instance . init ( ) ;
329+ } else if ( typeof component . init === 'string' ) {
330+ component . instance [ component . init ] ( ) ;
331+ }
332+ logger . verbose ( `Initialised singleton (${ component . name } )` ) ;
333+ }
334+ }
335+ logger . verbose ( 'Initialising singletons completed' ) ;
336+ }
337+
338+ registerDestroyer ( ) {
339+ process . on ( 'exit' , destroyer . bind ( ) ) ;
340+ //catches ctrl+c event
341+ process . on ( 'SIGINT' , destroyer . bind ( ) ) ;
342+ // catches "kill pid" (for example: nodemon restart)
343+ process . on ( 'SIGUSR1' , destroyer . bind ( ) ) ;
344+ process . on ( 'SIGUSR2' , destroyer . bind ( ) ) ;
345+ //catches uncaught exceptions
346+ process . on ( 'uncaughtException' , destroyer . bind ( ) ) ;
347+ }
348+ async registerSingletonDestroyers ( ) {
349+ logger . verbose ( 'Registering singleton destroyers started' ) ;
350+ const keys = Object . keys ( this . components ) ;
351+ for ( let i = 0 ; i < keys . length ; i ++ ) {
352+ const component = this . components [ keys [ i ] ] ;
353+ if ( component . scope === Scopes . SINGLETON ) {
354+ let destroyer = null ;
355+ if ( typeof component . instance . destroy === 'function' ) {
356+ destroyer = component . instance . destroy ;
357+ } else if ( typeof component . destroy === 'string' ) {
358+ destroyer = component . instance [ component . destroy ] ( ) ;
359+ }
360+ this . registerDestroyer ( destroyer ) ;
361+ this . registerDestroyer ( ( ) => {
362+ logger . verbose ( `ApplicationContext (${ this . name } ) lifecycle completed.` ) ;
363+ } ) ;
364+
365+ logger . verbose ( `Registering singleton (${ component . name } ) destroyer` ) ;
366+ }
367+ }
368+
369+ logger . verbose ( 'Registering singleton destroyers completed' ) ;
370+ }
371+ async run ( ) {
372+ const keys = Object . keys ( this . components ) ;
373+ for ( let i = 0 ; i < keys . length ; i ++ ) {
374+ const component = this . components [ keys [ i ] ] ;
375+ if ( component . scope === Scopes . SINGLETON ) {
376+ if ( typeof component . instance . run === 'function' ) {
377+ component . instance . run ( ) ;
378+ } else if ( typeof component . run === 'string' ) {
379+ component . instance [ component . run ] ( ) ;
380+ }
381+ }
382+ }
383+ logger . verbose ( 'Application context started' ) ;
384+ }
385+ get ( reference , defaultValue , targetArgs ) {
258386 if ( this . components [ reference ] ) {
259387 logger . verbose ( `Found component (${ reference } )` ) ;
260388 if ( this . components [ reference ] . scope === Scopes . SINGLETON ) {
@@ -265,7 +393,38 @@ module.exports = class ApplicationContext {
265393 if ( this . components [ reference ] . isClass ) {
266394 logger . verbose ( `Component (${ reference } ) is scoped as (${ Scopes . PROTOTYPE } ), returning new instance.` ) ;
267395 prototype = new this . components [ reference ] . Reference ( ) ;
268- } else {
396+ } else if ( typeof this . components [ reference ] === 'function' ) {
397+ let args = targetArgs || this . components [ reference ] . factoryArgs ;
398+ if ( ! Array . isArray ( args ) ) {
399+ args = [ args ] ;
400+ }
401+ prototype = new this . components [ reference ] ( ...args ) ;
402+ } else if ( typeof this . components [ 'factory' ] === 'function' ) {
403+ let args = this . components [ reference ] . factoryArgs ;
404+ if ( ! Array . isArray ( args ) ) {
405+ args = [ args ] ;
406+ }
407+ prototype = this . components [ reference ] ( ...args ) ;
408+ } else if ( typeof this . components [ 'factory' ] === 'string' && typeof this . components [ 'factoryFunction' ] === 'string' ) {
409+ let args = this . components [ reference ] [ 'factoryArgs' ] ;
410+ if ( ! Array . isArray ( args ) ) {
411+ args = [ args ] ;
412+ }
413+ prototype = this . get ( this . components [ 'factory' ] ) [ this . components [ 'factoryFunction' ] ] ( ...args ) ;
414+ } else if ( typeof this . components [ 'wireFactory' ] === 'function' ) {
415+ let args = targetArgs ;
416+ if ( ! Array . isArray ( args ) ) {
417+ args = [ args ] ;
418+ }
419+ prototype = this . components [ 'wireFactory' ] ( ...args ) ;
420+ } else if ( typeof this . components [ 'wireFactory' ] === 'string' ) {
421+ let args = targetArgs ;
422+ if ( ! Array . isArray ( args ) ) {
423+ args = [ args ] ;
424+ }
425+ prototype = this . get ( this . components [ 'wireFactory' ] ) ( ...args ) ;
426+ }
427+ else {
269428 logger . verbose ( `Component (${ reference } ) is scoped as (${ Scopes . PROTOTYPE } ), returning deep clone.` ) ;
270429 prototype = _ . cloneDeep ( this . components [ reference ] . Reference ) ;
271430 }
0 commit comments