diff --git a/src/ts/@overflow/commons/application/application.ts b/src/ts/@overflow/commons/application/application.ts index 92984b2..5679b19 100644 --- a/src/ts/@overflow/commons/application/application.ts +++ b/src/ts/@overflow/commons/application/application.ts @@ -2,7 +2,7 @@ import { Class, Method, } from '@overflow/commons/core/reflect'; -import { ClassType } from '@overflow/commons/core/type'; +import { ClassType, PropertyKeyType } from '@overflow/commons/core/type'; import { ApplicationContext } from './context'; import { ConfigurationAnnotation, @@ -32,36 +32,34 @@ export class Application { */ public async run(): Promise { let runner = this.findRunner(); - if (null === runner) { + if (undefined === runner) { throw new Error(`There is not exist @Runner on Application[${this._primaryClass.name}]`); } let instanceFactory = this._applicationContext.instanceFactory; - let instance = instanceFactory.getInstance(null, this._primaryClass); + + let clazz: Class = Class.forClass(this._primaryClass); + let instance = clazz.getConstructor().newInstance(); + instanceFactory.applyInstance(this._primaryClass, instance); await runner.invoke(instance); return this._applicationContext; } - private findRunner(): Method { + private findRunner(): Method | undefined { let clazz: Class = Class.forClass(this._primaryClass); let methods = clazz.getOwnMethods(); - if (null === methods || 0 === methods.size) { - return null; - } - for (const key in methods.keys()) { - if (methods.hasOwnProperty(key)) { - const method = methods[key]; - let runnerAnnotation = method.getOwnAnnotation(RunnerAnnotation); - if (undefined === runnerAnnotation) { - continue; - } - return method; + for (let key of Array.from(methods.keys())) { + let method = methods.get(key); + let runnerAnnotation = method.getOwnAnnotation(RunnerAnnotation); + if (undefined === runnerAnnotation) { + continue; } + return method; } - return null; + return undefined; } private createContext(): ApplicationContext { @@ -105,7 +103,8 @@ export class Application { if (null === methods) { return; } - let instance = instanceFactory.getInstance(null, configurationType); + let instance = clazz.getConstructor().newInstance(); + instanceFactory.applyInstance(configurationType, instance); methods.forEach(method => { let instanceAnnotation = method.getOwnAnnotation(InstanceAnnotation); if (undefined === instanceAnnotation) { diff --git a/src/ts/@overflow/commons/core/reflect/class.ts b/src/ts/@overflow/commons/core/reflect/class.ts index 5b982ea..5671a53 100644 --- a/src/ts/@overflow/commons/core/reflect/class.ts +++ b/src/ts/@overflow/commons/core/reflect/class.ts @@ -52,7 +52,6 @@ export class Class extends AccessibleObject { this._clazzType = clazzType; this._fields = new Map(); this._methods = new Map(); - this._constructor = null; } /** @@ -96,6 +95,9 @@ export class Class extends AccessibleObject { } public getConstructor(): Constructor { + if (undefined === this._constructor) { + this._constructor = new Constructor(this, undefined); + } return this._constructor; } diff --git a/src/ts/@overflow/commons/core/reflect/constructor.ts b/src/ts/@overflow/commons/core/reflect/constructor.ts index f249987..e8dfb67 100644 --- a/src/ts/@overflow/commons/core/reflect/constructor.ts +++ b/src/ts/@overflow/commons/core/reflect/constructor.ts @@ -9,7 +9,7 @@ import {Executable} from './executable'; export class Constructor extends Executable { private _rawConstructor: Function; - public constructor(declaringClazz: Class, parameterTypes: any[]) { + public constructor(declaringClazz: Class, parameterTypes?: any[]) { super(declaringClazz, CONSTRUCTOR_NAME, parameterTypes); this._rawConstructor = TypeUtil.getPrototype(declaringClazz.getType())[CONSTRUCTOR_NAME]; } diff --git a/src/ts/@overflow/commons/core/reflect/executable.ts b/src/ts/@overflow/commons/core/reflect/executable.ts index b4516d1..16817a2 100644 --- a/src/ts/@overflow/commons/core/reflect/executable.ts +++ b/src/ts/@overflow/commons/core/reflect/executable.ts @@ -13,13 +13,13 @@ export abstract class Executable extends AccessibleObject implements Member { private _name: PropertyKeyType; private _parameters: Parameter[]; - protected constructor(declaringClazz: Class, name: PropertyKeyType, parameterTypes: any[]) { + protected constructor(declaringClazz: Class, name: PropertyKeyType, parameterTypes?: any[]) { super(); this._clazz = declaringClazz; this._name = name; - if (null === parameterTypes) { + if (undefined === parameterTypes) { return; } diff --git a/src/ts/@overflow/commons/di/decorators/inject.ts b/src/ts/@overflow/commons/di/decorators/inject.ts index f86158b..07a91ba 100644 --- a/src/ts/@overflow/commons/di/decorators/inject.ts +++ b/src/ts/@overflow/commons/di/decorators/inject.ts @@ -13,7 +13,7 @@ import { } from '@overflow/commons/di/type'; export interface InjectAnnotationAttributes { - name?: InstanceNameType[]; + name?: InstanceNameType; } export class InjectAnnotation implements Annotation { @@ -29,11 +29,7 @@ export class InjectAnnotation implements Annotation { if (TypeUtil.isString(name)) { this.attributes = { - name: [name], - }; - } else if (TypeUtil.isArray(name)) { - this.attributes = { - name: name, + name: name, }; } else { this.attributes = name; diff --git a/src/ts/@overflow/commons/di/decorators/resource.ts b/src/ts/@overflow/commons/di/decorators/resource.ts index befbab1..11a78b1 100644 --- a/src/ts/@overflow/commons/di/decorators/resource.ts +++ b/src/ts/@overflow/commons/di/decorators/resource.ts @@ -13,7 +13,7 @@ import { } from '@overflow/commons/di/type'; export interface ResourceAnnotationAttributes { - name: InstanceNameType[]; + name?: InstanceNameType; } export class ResourceAnnotation implements Annotation { @@ -22,12 +22,14 @@ export class ResourceAnnotation implements Annotation { public constructor(name: InstanceNameType | ResourceAnnotationAttributes) { if (undefined === name) { - throw new Error(`name attribute must be specified.`); + this.attributes = { + }; + return; } if (TypeUtil.isString(name)) { this.attributes = { - name: [name], + name: name, }; } else { this.attributes = name; diff --git a/src/ts/@overflow/commons/di/factory/instance_factory.ts b/src/ts/@overflow/commons/di/factory/instance_factory.ts index 6fcb245..d164637 100644 --- a/src/ts/@overflow/commons/di/factory/instance_factory.ts +++ b/src/ts/@overflow/commons/di/factory/instance_factory.ts @@ -1,27 +1,35 @@ import { - ClassType, + ClassType, PropertyKeyType, } from '@overflow/commons/core/type'; +import { + Class, Annotation, Field, +} from '@overflow/commons/core/reflect'; + +import { + ValueAnnotation, InjectAnnotation, ResourceAnnotation, +} from '@overflow/commons/di/decorators'; import { InstanceNameType, InstanceFactoryType, } from '@overflow/commons/di/type'; + import {InstanceDefinitionRegistry} from './instance_definition_registry'; import {InstanceDefinition} from './instance_definition'; export class InstanceFactory implements InstanceDefinitionRegistry { - private singletonObjects: Map = new Map(); - private singletonFactories: Map = new Map(); - private instanceDefinitionMap: Map = new Map(); - private instanceDefinitionNames: Set = new Set(); - + private _singletonObjects: Map = new Map(); + private _singletonFactories: Map = new Map(); + private _instanceDefinitionMap: Map = new Map(); + private _instanceDefinitionNames: Set = new Set(); + private _values: any; /** * getInstance */ - public getInstance(name: InstanceNameType, requiredType: ClassType, ...args: any[]): any { + public getInstance(name: InstanceNameType, requiredType: ClassType, ...args: any[]): any | undefined { if (null === name) { - return this.getInstanceByType(requiredType); + name = requiredType.name; } let sharedInstance = this.getSingleton(name); @@ -29,20 +37,74 @@ export class InstanceFactory implements InstanceDefinitionRegistry { return sharedInstance; } + let instanceDefinition = this.getInstanceDefinition(name); + let clazzType = instanceDefinition.instanceClass; + let clazz = Class.forClass(clazzType); + if (undefined === clazz) { + return undefined; + } + let ctor = clazz.getConstructor(); + let ctorParams = ctor.getParameters(); + let ctorArgs = []; + if (0 < ctorParams.length) { + // + } - return null; + let instance = ctor.newInstance(ctorArgs); + + this.applyInstance(clazzType, instance); + + return instance; } - private getInstanceByName(requiredType: ClassType): any { - + private getInstanceByName(requiredType: ClassType): any | undefined { + return undefined; } - private getInstanceByType(requiredType: ClassType): any { + private getInstanceByType(requiredType: ClassType): any | undefined { + return undefined; + } + /** + * applyInstance + */ + public applyInstance(clazzType: ClassType, instance: any): void { + let clazz: Class = Class.forClass(clazzType); + + let fields = clazz.getFields(); + + fields.forEach((field: Field, key: PropertyKeyType, map: Map): void => { + let fieldAnnotations = field.getAnnotations(); + fieldAnnotations.forEach((value: Annotation, annonType: ClassType, annonMap: Map): void => { + switch (annonType) { + case ValueAnnotation: + { + let annon = value; + instance[field.getName()] = this.getValue(annon.attributes.value); + } + break; + case InjectAnnotation: + { + let annon = value; + instance[field.getName()] = this.getInstance(annon.attributes.name, field.getType()); + } + break; + case ResourceAnnotation: + { + let annon = value; + instance[field.getName()] = this.getSingleton(annon.attributes.name || field.getName()); + } + break; + default: + break; + } + }); + + }); } private getSingleton(name: InstanceNameType): any | undefined { - let singletonObject = this.singletonObjects.get(name); + let singletonObject = this._singletonObjects.get(name); } /** @@ -53,44 +115,56 @@ export class InstanceFactory implements InstanceDefinitionRegistry { } public registerJSON(json: any): void { - // + this._values = json; + } + + /** + * getValue + */ + public getValue(keyPath: string): any { + let paths = keyPath.split('.'); + let result = this._values; + for (let i = 0, len = paths.length; i < len; i++) { + result = result[paths[i]]; + } + return result; } public registerSingleton(name: InstanceNameType, instanceType: any, instance: any): void { - // + this._singletonObjects.set(name, instance); } public registerInstanceDefinition(name: InstanceNameType, instanceDefinition: InstanceDefinition): void { - let oldInstanceDefinition = this.instanceDefinitionMap.get(name); + let oldInstanceDefinition = this._instanceDefinitionMap.get(name); if (undefined !== oldInstanceDefinition) { throw new Error(`InstanceDefinition[${name}] is already exist.`); } - this.instanceDefinitionNames.add(name); - this.instanceDefinitionMap.set(name, instanceDefinition); + this._instanceDefinitionNames.add(name); + this._instanceDefinitionMap.set(name, instanceDefinition); } public removeInstanceDefinition(name: InstanceNameType): void { - if (!this.instanceDefinitionMap.has(name)) { + if (!this._instanceDefinitionMap.has(name)) { throw new Error(`InstanceDefinition[${name}] is not exist.`); } - this.instanceDefinitionNames.delete(name); - this.instanceDefinitionMap.delete(name); + this._instanceDefinitionNames.delete(name); + this._instanceDefinitionMap.delete(name); } public getInstanceDefinition(name: InstanceNameType): InstanceDefinition | undefined { - return this.instanceDefinitionMap.get(name); + return this._instanceDefinitionMap.get(name); } public containsInstanceDefinition(name: InstanceNameType): boolean { - return this.instanceDefinitionMap.has(name); + return this._instanceDefinitionMap.has(name); } public getInstanceDefinitionNames(): Set { - return this.instanceDefinitionNames; + return this._instanceDefinitionNames; } public getInstanceDefinitionCount(): number { - return this.instanceDefinitionMap.size; + return this._instanceDefinitionMap.size; } public isInstanceNameInUse(name: InstanceNameType): boolean { diff --git a/src/ts/@overflow/webapp/index.tsx b/src/ts/@overflow/webapp/index.tsx index fc8bbf0..7e77315 100644 --- a/src/ts/@overflow/webapp/index.tsx +++ b/src/ts/@overflow/webapp/index.tsx @@ -83,7 +83,7 @@ class WebAppApplication extends B { private htmlContainerID: string; private container: HTMLElement; - @Inject() + @Resource() private store: Store; private history: History;