import ApplicationConfig from '../config/ApplicationConfig'; import Singleton from "../patterns/Singleton"; import {BEAN_MAP, BEAN_OPTION, COMPONENT_TYPE, CTX_OPTIONS, PATH_INFO, SCAN_TYPE} from "../@types/types"; import path from "path"; import {__approot, __node_modules_path} from "../config/ApplicationEnvironment"; import RequestUtil from "../utils/RequestUtil"; import BeansTarget from "../patterns/BeansTarget"; import {beanScanner} from "../reflect/ComponentScan"; type Constructor = new (...args: any[]) => T; export default class ApplicationContext extends Singleton{ public applicationConfig?: ApplicationConfig; public beans:BEAN_MAP = {}; public processer:BEAN_MAP = {}; public components:SCAN_TYPE[]=[]; public scanBase:string[] = [ __approot||"./", path.resolve(__node_modules_path, "biflow-core/lib"), path.resolve(__node_modules_path, "biflow-desktop-core/lib") ]; private serviceBase:string[] = [ path.resolve(__node_modules_path, "biflow-core/lib"), path.resolve(__node_modules_path, "biflow-desktop-core/lib") ]; constructor() { super(); } public init(options?:CTX_OPTIONS){ //글로벌 환경설정 로드 if(options){ this.applicationConfig = ApplicationConfig.load(options.CONFIG); if(options.BASE) this.addScanBase(options.BASE); }else{ this.applicationConfig = ApplicationConfig.loadDefault(); } } public addScanBase(scanBase:string[]){ if (scanBase) { this.scanBase = this.scanBase.filter((element)=>{ return scanBase?.indexOf(element) == -1; }).concat(scanBase); } } public setComponents(components:SCAN_TYPE[]){ if (components) { components.forEach((el)=>{ if(!this.beans[el.CLASS_NAME]){ this.beans[el.CLASS_NAME] = el; this.components.push(el); } }) } } public addScanBean(module:any, componentType:COMPONENT_TYPE, option?:BEAN_OPTION | any):SCAN_TYPE|undefined{ if(!module) return; let name = !option.MODULE_NAME ? module.name : option.MODULE_NAME; let info:SCAN_TYPE|undefined = this.beans[name]; if(info) return info; let path:string = "added"; const pi:PATH_INFO = beanScanner.getPathInfo(name); if(pi) path = pi.BIZ_PATH if(path == "") path = name; let scanType:SCAN_TYPE = { TYPE:componentType, PATH:path, CLASS_NAME:name, CLASS:module, // BEAN:this.prototypeScan(new module()), OPTION:option }; //prototype은 빈에서 부를때 생성되므로 뭔가 할 필요없음 if (option.SCOPE !== "singleton") { try{ scanType.BEAN = module; }catch(e){}; } else //(componentType === COMPONENT_TYPE.MIDDLEWARE || (option && option.SCOPE === "request")) { scanType = this.mixedIndSingleton(module, scanType); } this.beans[name] = scanType; this.components.push(scanType); if(componentType == COMPONENT_TYPE.TRANSACTION_PROCESSOR){ this.processer[path] = scanType; } } private mixedIndSingleton(module:any, scanType:SCAN_TYPE) { if(!module['getInstance']) { //singleton이 아니면 singleton으로 만들어준다 module['instance'] = undefined; Object.defineProperty(module,"getInstance", Object.getOwnPropertyDescriptor(Singleton, "getInstance")!) scanType.CLASS = module; } scanType.BEAN = module.getInstance(); return scanType; } public prototypeScan(obj:any) { const protos = [obj.prototype, Object.getPrototypeOf(obj)]; protos.forEach((proto)=>{ if(!proto) return; Object.keys(proto).forEach((item) => { if(item.indexOf("__") == 0 && item.lastIndexOf("__") == item.length-2){ proto[item].INVOKE(); } }); }); return obj; } public getTransactionProcessors():SCAN_TYPE[]{ // let comp:SCAN_TYPE[] = []; // if (this.components) { // comp = this.components.filter((element)=>{ // return element.TYPE == COMPONENT_TYPE.TRANSACTION_PROCESSOR; // }); // } // return Object.entries(this.processer).map((elem:[string, SCAN_TYPE])=>elem[1]); } public getTransactionProcessor(req:any):SCAN_TYPE{ const url:string = RequestUtil.getRequestService(req); return this.processer[url]; } public getViewProcessor(url:string):SCAN_TYPE{ url = RequestUtil.getRequestService(url); return this.processer[url]; } public getResolvers():SCAN_TYPE[]{ let comp:SCAN_TYPE[] = []; if (this.components) { comp = this.components.filter((element)=>{ return element.TYPE == COMPONENT_TYPE.RESOLVER; }); } return comp; } public getSubtypeBeans(subtype:string):SCAN_TYPE[] { let ret:SCAN_TYPE[]=[]; if (this.components) { ret = this.components.filter((el)=>{ return (el.OPTION && el.OPTION.SUBTYPE == subtype); }); } return ret; } public getBeanWithClass(cls: abstract new()=>T, scope?: BEAN_OPTION) { let ret:SCAN_TYPE[]=[]; if (this.components) { ret = this.components.filter((el)=>{ return (el.BEAN instanceof cls); }); } return ret; } public findBean(className:string):SCAN_TYPE|undefined { let info:SCAN_TYPE|undefined = this.beans[className]; if(!info) { info = beanScanner.scanFromFile(applicationContext.scanBase, className); } return info; } public getBean(className: string, scope?: BEAN_OPTION) { if (!scope || scope?.SCOPE == "singleton") { let info:SCAN_TYPE|undefined = this.findBean(className); let bean = info?.BEAN; if(!bean){ try{ if(!info?.CLASS.default) { bean = info!.CLASS.getInstance(); } else { bean = info.CLASS.default.getInstance(); } }catch(e){ console.log(e); } this.beans[className].BEAN = bean; } // scanType.BEAN = module.getInstance(); return bean; }else if (scope?.SCOPE == "prototype") { let info:SCAN_TYPE|undefined = this.findBean(className); try{ if(!info?.CLASS.default) { return new info!.CLASS(); } else { return new info.CLASS.default(); } }catch(e){} } // else if (scope?.SCOPE == "request") { // let info:SCAN_TYPE|undefined = this.beans[className]; // if (info) { // if(info.CLASS && info.CLASS.name) // { // return new info.CLASS(); // } // else if(info.CLASS.default && info.CLASS.default.name) // { // return new info.CLASS.default(); // } // else // return undefined; // }else{ // info = ComponentScan.scanFromFile(applicationContext.scanBase, className); // if (info) { // let bean = info.BEAN; // try{bean = info.CLASS.default();}catch(e){} // this.beans[className] = info; // return bean; // } // } // } } } export const applicationContext:ApplicationContext = ApplicationContext.getInstance();