This commit is contained in:
crusader 2017-12-29 16:15:10 +09:00
parent b3189213e5
commit 046ea0e6f2
8 changed files with 129 additions and 56 deletions

View File

@ -2,7 +2,7 @@ import {
Class, Class,
Method, Method,
} from '@overflow/commons/core/reflect'; } 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 { ApplicationContext } from './context';
import { import {
ConfigurationAnnotation, ConfigurationAnnotation,
@ -32,36 +32,34 @@ export class Application {
*/ */
public async run(): Promise<ApplicationContext> { public async run(): Promise<ApplicationContext> {
let runner = this.findRunner(); let runner = this.findRunner();
if (null === runner) { if (undefined === runner) {
throw new Error(`There is not exist @Runner on Application[${this._primaryClass.name}]`); throw new Error(`There is not exist @Runner on Application[${this._primaryClass.name}]`);
} }
let instanceFactory = this._applicationContext.instanceFactory; 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); await runner.invoke(instance);
return this._applicationContext; return this._applicationContext;
} }
private findRunner(): Method { private findRunner(): Method | undefined {
let clazz: Class = Class.forClass(this._primaryClass); let clazz: Class = Class.forClass(this._primaryClass);
let methods = clazz.getOwnMethods(); let methods = clazz.getOwnMethods();
if (null === methods || 0 === methods.size) {
return null;
}
for (const key in methods.keys()) { for (let key of Array.from(methods.keys())) {
if (methods.hasOwnProperty(key)) { let method = methods.get(key);
const method = methods[key]; let runnerAnnotation = method.getOwnAnnotation(RunnerAnnotation);
let runnerAnnotation = method.getOwnAnnotation(RunnerAnnotation); if (undefined === runnerAnnotation) {
if (undefined === runnerAnnotation) { continue;
continue;
}
return method;
} }
return method;
} }
return null; return undefined;
} }
private createContext(): ApplicationContext { private createContext(): ApplicationContext {
@ -105,7 +103,8 @@ export class Application {
if (null === methods) { if (null === methods) {
return; return;
} }
let instance = instanceFactory.getInstance(null, configurationType); let instance = clazz.getConstructor().newInstance();
instanceFactory.applyInstance(configurationType, instance);
methods.forEach(method => { methods.forEach(method => {
let instanceAnnotation = method.getOwnAnnotation(InstanceAnnotation); let instanceAnnotation = method.getOwnAnnotation(InstanceAnnotation);
if (undefined === instanceAnnotation) { if (undefined === instanceAnnotation) {

View File

@ -52,7 +52,6 @@ export class Class extends AccessibleObject {
this._clazzType = clazzType; this._clazzType = clazzType;
this._fields = new Map(); this._fields = new Map();
this._methods = new Map(); this._methods = new Map();
this._constructor = null;
} }
/** /**
@ -96,6 +95,9 @@ export class Class extends AccessibleObject {
} }
public getConstructor(): Constructor { public getConstructor(): Constructor {
if (undefined === this._constructor) {
this._constructor = new Constructor(this, undefined);
}
return this._constructor; return this._constructor;
} }

View File

@ -9,7 +9,7 @@ import {Executable} from './executable';
export class Constructor extends Executable { export class Constructor extends Executable {
private _rawConstructor: Function; private _rawConstructor: Function;
public constructor(declaringClazz: Class, parameterTypes: any[]) { public constructor(declaringClazz: Class, parameterTypes?: any[]) {
super(declaringClazz, CONSTRUCTOR_NAME, parameterTypes); super(declaringClazz, CONSTRUCTOR_NAME, parameterTypes);
this._rawConstructor = TypeUtil.getPrototype(declaringClazz.getType())[CONSTRUCTOR_NAME]; this._rawConstructor = TypeUtil.getPrototype(declaringClazz.getType())[CONSTRUCTOR_NAME];
} }

View File

@ -13,13 +13,13 @@ export abstract class Executable extends AccessibleObject implements Member {
private _name: PropertyKeyType; private _name: PropertyKeyType;
private _parameters: Parameter[]; private _parameters: Parameter[];
protected constructor(declaringClazz: Class, name: PropertyKeyType, parameterTypes: any[]) { protected constructor(declaringClazz: Class, name: PropertyKeyType, parameterTypes?: any[]) {
super(); super();
this._clazz = declaringClazz; this._clazz = declaringClazz;
this._name = name; this._name = name;
if (null === parameterTypes) { if (undefined === parameterTypes) {
return; return;
} }

View File

@ -13,7 +13,7 @@ import {
} from '@overflow/commons/di/type'; } from '@overflow/commons/di/type';
export interface InjectAnnotationAttributes { export interface InjectAnnotationAttributes {
name?: InstanceNameType[]; name?: InstanceNameType;
} }
export class InjectAnnotation implements Annotation { export class InjectAnnotation implements Annotation {
@ -29,11 +29,7 @@ export class InjectAnnotation implements Annotation {
if (TypeUtil.isString(name)) { if (TypeUtil.isString(name)) {
this.attributes = { this.attributes = {
name: [<InstanceNameType>name], name: <InstanceNameType>name,
};
} else if (TypeUtil.isArray(name)) {
this.attributes = {
name: <InstanceNameType[]>name,
}; };
} else { } else {
this.attributes = <InjectAnnotationAttributes>name; this.attributes = <InjectAnnotationAttributes>name;

View File

@ -13,7 +13,7 @@ import {
} from '@overflow/commons/di/type'; } from '@overflow/commons/di/type';
export interface ResourceAnnotationAttributes { export interface ResourceAnnotationAttributes {
name: InstanceNameType[]; name?: InstanceNameType;
} }
export class ResourceAnnotation implements Annotation { export class ResourceAnnotation implements Annotation {
@ -22,12 +22,14 @@ export class ResourceAnnotation implements Annotation {
public constructor(name: InstanceNameType | ResourceAnnotationAttributes) { public constructor(name: InstanceNameType | ResourceAnnotationAttributes) {
if (undefined === name) { if (undefined === name) {
throw new Error(`name attribute must be specified.`); this.attributes = {
};
return;
} }
if (TypeUtil.isString(name)) { if (TypeUtil.isString(name)) {
this.attributes = { this.attributes = {
name: [<InstanceNameType>name], name: <InstanceNameType>name,
}; };
} else { } else {
this.attributes = <ResourceAnnotationAttributes>name; this.attributes = <ResourceAnnotationAttributes>name;

View File

@ -1,27 +1,35 @@
import { import {
ClassType, ClassType, PropertyKeyType,
} from '@overflow/commons/core/type'; } from '@overflow/commons/core/type';
import {
Class, Annotation, Field,
} from '@overflow/commons/core/reflect';
import {
ValueAnnotation, InjectAnnotation, ResourceAnnotation,
} from '@overflow/commons/di/decorators';
import { import {
InstanceNameType, InstanceNameType,
InstanceFactoryType, InstanceFactoryType,
} from '@overflow/commons/di/type'; } from '@overflow/commons/di/type';
import {InstanceDefinitionRegistry} from './instance_definition_registry'; import {InstanceDefinitionRegistry} from './instance_definition_registry';
import {InstanceDefinition} from './instance_definition'; import {InstanceDefinition} from './instance_definition';
export class InstanceFactory implements InstanceDefinitionRegistry { export class InstanceFactory implements InstanceDefinitionRegistry {
private singletonObjects: Map<InstanceNameType, any> = new Map(); private _singletonObjects: Map<InstanceNameType, any> = new Map();
private singletonFactories: Map<InstanceNameType, InstanceFactoryType> = new Map(); private _singletonFactories: Map<InstanceNameType, InstanceFactoryType> = new Map();
private instanceDefinitionMap: Map<InstanceNameType, InstanceDefinition> = new Map(); private _instanceDefinitionMap: Map<InstanceNameType, InstanceDefinition> = new Map();
private instanceDefinitionNames: Set<InstanceNameType> = new Set(); private _instanceDefinitionNames: Set<InstanceNameType> = new Set();
private _values: any;
/** /**
* getInstance * getInstance
*/ */
public getInstance(name: InstanceNameType, requiredType: ClassType, ...args: any[]): any { public getInstance(name: InstanceNameType, requiredType: ClassType, ...args: any[]): any | undefined {
if (null === name) { if (null === name) {
return this.getInstanceByType(requiredType); name = requiredType.name;
} }
let sharedInstance = this.getSingleton(name); let sharedInstance = this.getSingleton(name);
@ -29,20 +37,74 @@ export class InstanceFactory implements InstanceDefinitionRegistry {
return sharedInstance; 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<PropertyKeyType, Field>): void => {
let fieldAnnotations = field.getAnnotations();
fieldAnnotations.forEach((value: Annotation, annonType: ClassType, annonMap: Map<ClassType, Annotation>): void => {
switch (annonType) {
case ValueAnnotation:
{
let annon = <ValueAnnotation>value;
instance[field.getName()] = this.getValue(annon.attributes.value);
}
break;
case InjectAnnotation:
{
let annon = <InjectAnnotation>value;
instance[field.getName()] = this.getInstance(annon.attributes.name, field.getType());
}
break;
case ResourceAnnotation:
{
let annon = <ResourceAnnotation>value;
instance[field.getName()] = this.getSingleton(annon.attributes.name || field.getName());
}
break;
default:
break;
}
});
});
} }
private getSingleton(name: InstanceNameType): any | undefined { 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 { 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 { public registerSingleton(name: InstanceNameType, instanceType: any, instance: any): void {
// this._singletonObjects.set(name, instance);
} }
public registerInstanceDefinition(name: InstanceNameType, instanceDefinition: InstanceDefinition): void { public registerInstanceDefinition(name: InstanceNameType, instanceDefinition: InstanceDefinition): void {
let oldInstanceDefinition = this.instanceDefinitionMap.get(name); let oldInstanceDefinition = this._instanceDefinitionMap.get(name);
if (undefined !== oldInstanceDefinition) { if (undefined !== oldInstanceDefinition) {
throw new Error(`InstanceDefinition[${name}] is already exist.`); throw new Error(`InstanceDefinition[${name}] is already exist.`);
} }
this.instanceDefinitionNames.add(name); this._instanceDefinitionNames.add(name);
this.instanceDefinitionMap.set(name, instanceDefinition); this._instanceDefinitionMap.set(name, instanceDefinition);
} }
public removeInstanceDefinition(name: InstanceNameType): void { public removeInstanceDefinition(name: InstanceNameType): void {
if (!this.instanceDefinitionMap.has(name)) { if (!this._instanceDefinitionMap.has(name)) {
throw new Error(`InstanceDefinition[${name}] is not exist.`); throw new Error(`InstanceDefinition[${name}] is not exist.`);
} }
this.instanceDefinitionNames.delete(name); this._instanceDefinitionNames.delete(name);
this.instanceDefinitionMap.delete(name); this._instanceDefinitionMap.delete(name);
} }
public getInstanceDefinition(name: InstanceNameType): InstanceDefinition | undefined { public getInstanceDefinition(name: InstanceNameType): InstanceDefinition | undefined {
return this.instanceDefinitionMap.get(name); return this._instanceDefinitionMap.get(name);
} }
public containsInstanceDefinition(name: InstanceNameType): boolean { public containsInstanceDefinition(name: InstanceNameType): boolean {
return this.instanceDefinitionMap.has(name); return this._instanceDefinitionMap.has(name);
} }
public getInstanceDefinitionNames(): Set<InstanceNameType> { public getInstanceDefinitionNames(): Set<InstanceNameType> {
return this.instanceDefinitionNames; return this._instanceDefinitionNames;
} }
public getInstanceDefinitionCount(): number { public getInstanceDefinitionCount(): number {
return this.instanceDefinitionMap.size; return this._instanceDefinitionMap.size;
} }
public isInstanceNameInUse(name: InstanceNameType): boolean { public isInstanceNameInUse(name: InstanceNameType): boolean {

View File

@ -83,7 +83,7 @@ class WebAppApplication extends B {
private htmlContainerID: string; private htmlContainerID: string;
private container: HTMLElement; private container: HTMLElement;
@Inject() @Resource()
private store: Store<any>; private store: Store<any>;
private history: History; private history: History;