ing
This commit is contained in:
parent
b7f366be76
commit
81fe770489
|
@ -32,7 +32,7 @@ export class Application {
|
|||
/**
|
||||
* run
|
||||
*/
|
||||
public async run(): Promise<ApplicationContext> {
|
||||
public run(): ApplicationContext {
|
||||
let runner = this.findRunner();
|
||||
if (undefined === runner) {
|
||||
throw new Error(`There is not exist @Runner on Application[${this._primaryClass.name}]`);
|
||||
|
@ -43,7 +43,7 @@ export class Application {
|
|||
let instance = clazz.getConstructor().newInstance();
|
||||
instanceFactory.applyInstance(this._primaryClass, instance);
|
||||
|
||||
await runner.invoke(instance);
|
||||
runner.invoke(instance);
|
||||
|
||||
return this._applicationContext;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
import {
|
||||
ClassType,
|
||||
} from '@overflow/commons/core/type';
|
||||
|
||||
import {
|
||||
Class,
|
||||
} from '@overflow/commons/core/reflect';
|
||||
|
||||
import {
|
||||
InstanceDefinition,
|
||||
InstanceFactory,
|
||||
} from '@overflow/commons/di/factory';
|
||||
|
||||
import { InstanceDefinitionReader } from './instance_definition_reader';
|
||||
|
||||
export class ApplicationContext {
|
||||
private _instanceFactory: InstanceFactory;
|
||||
private _instanceDefinitionReader: InstanceDefinitionReader;
|
||||
|
||||
public constructor(injectables: ClassType[]) {
|
||||
this._instanceFactory = new InstanceFactory();
|
||||
this._instanceDefinitionReader = new InstanceDefinitionReader();
|
||||
|
||||
this.initializeInjectables(injectables);
|
||||
}
|
||||
|
||||
private initializeInjectables(injectables: ClassType[]): void {
|
||||
if (undefined === injectables) {
|
||||
return;
|
||||
}
|
||||
injectables.forEach(injectable => {
|
||||
let name = injectable.name;
|
||||
let definition: InstanceDefinition = new InstanceDefinition(injectable);
|
||||
this._instanceFactory.registerInstanceDefinition(name, definition);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* instanceFactory
|
||||
*/
|
||||
public get instanceFactory(): InstanceFactory {
|
||||
return this._instanceFactory;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,41 +1,86 @@
|
|||
import {
|
||||
ClassType,
|
||||
} from '@overflow/commons/core/type';
|
||||
|
||||
import {
|
||||
Class,
|
||||
} from '@overflow/commons/core/reflect';
|
||||
|
||||
import {
|
||||
InstanceDefinition,
|
||||
InstanceFactory,
|
||||
} from '@overflow/commons/di/factory';
|
||||
|
||||
import { ApplicationContextIDType } from '@overflow/commons/application/type';
|
||||
|
||||
import { MessageSource } from './message_source';
|
||||
import { InstanceDefinitionReader } from './instance_definition_reader';
|
||||
|
||||
export class ApplicationContext {
|
||||
private _instanceFactory: InstanceFactory;
|
||||
public static readonly MESSAGE_SOURCE_INSTANCE_NAME: string = 'messageSource';
|
||||
|
||||
public constructor(injectables: ClassType[]) {
|
||||
this._instanceFactory = new InstanceFactory();
|
||||
this.initializeInjectables(injectables);
|
||||
private readonly instanceFactoryPostProcessors: InstanceFactoryPostProcessor[] = [];
|
||||
|
||||
private id: ApplicationContextIDType;
|
||||
private parent: ApplicationContext;
|
||||
private messageSource: MessageSource;
|
||||
private instanceFactory: InstanceFactory;
|
||||
private instanceDefinitionReader: InstanceDefinitionReader;
|
||||
|
||||
public constructor(parent?: ApplicationContext) {
|
||||
this.setParent(parent);
|
||||
}
|
||||
|
||||
private initializeInjectables(injectables: ClassType[]): void {
|
||||
if (undefined === injectables) {
|
||||
return;
|
||||
// Context
|
||||
|
||||
public getID(): ApplicationContextIDType {
|
||||
return this.id;
|
||||
}
|
||||
injectables.forEach(injectable => {
|
||||
let name = injectable.name;
|
||||
let definition: InstanceDefinition = new InstanceDefinition(injectable);
|
||||
this._instanceFactory.registerInstanceDefinition(name, definition);
|
||||
});
|
||||
public setID(id: ApplicationContextIDType): void {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* instanceFactory
|
||||
*/
|
||||
public get instanceFactory(): InstanceFactory {
|
||||
return this._instanceFactory;
|
||||
public getApplicationName(): string {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
|
||||
public getParent(): ApplicationContext {
|
||||
return this.parent;
|
||||
}
|
||||
public setParent(parent: ApplicationContext): void {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
public getInstanceFactory(): InstanceFactory {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// Configuration
|
||||
|
||||
public addInstanceFactoryPostProcessor(instanceFactoryPostProcessor: InstanceFactoryPostProcessor): void {
|
||||
this.instanceFactoryPostProcessors.push(instanceFactoryPostProcessor);
|
||||
}
|
||||
public getInstanceFactoryPostProcessor(): InstanceFactoryPostProcessor[] {
|
||||
return this.instanceFactoryPostProcessors;
|
||||
}
|
||||
|
||||
public addApplicationListener(listener: ApplicationListener): void {
|
||||
//
|
||||
}
|
||||
|
||||
public registerShutdownHook(): void {
|
||||
//
|
||||
}
|
||||
|
||||
public initMessageSource(): void {
|
||||
//
|
||||
}
|
||||
|
||||
// MessageSource
|
||||
public getMessageSource(): MessageSource {
|
||||
return this.messageSource;
|
||||
}
|
||||
|
||||
// Lifecycle
|
||||
|
||||
public start(): void {
|
||||
//
|
||||
}
|
||||
public stop(): void {
|
||||
//
|
||||
}
|
||||
public isRunning(): boolean {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
export * from './application_context';
|
||||
export * from './instance_definition_reader';
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
import {
|
||||
ClassType,
|
||||
} from '@overflow/commons/core/type';
|
||||
|
||||
import {
|
||||
InstanceDefinitionRegistry, InstanceNameGenerator,
|
||||
} from '@overflow/commons/di/factory';
|
||||
|
||||
export class InstanceDefinitionReader {
|
||||
private instanceDefinitionRegistry: InstanceDefinitionRegistry;
|
||||
private instanceNameGenerator: InstanceNameGenerator;
|
||||
|
||||
public constructor(registry: InstanceDefinitionRegistry) {
|
||||
//
|
||||
}
|
||||
|
||||
public register(...injectables: ClassType[]): void {
|
||||
//
|
||||
}
|
||||
|
||||
public registerInstance(injectable: ClassType): void {
|
||||
//
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
import { Locale } from '@overflow/commons/core/util';
|
||||
|
||||
export class MessageSource {
|
||||
public getMessage(code: string, args: any[], defaultMessage: string | undefined, locale: Locale): string {
|
||||
return undefined;
|
||||
}
|
||||
}
|
|
@ -1,3 +1,7 @@
|
|||
import { IdentityType } from '@overflow/commons/core/type';
|
||||
|
||||
export type ApplicationContextIDType = IdentityType<string>;
|
||||
|
||||
// import {
|
||||
// ClassType,
|
||||
// } from '@overflow/commons/core/type';
|
||||
|
@ -20,3 +24,4 @@
|
|||
// }
|
||||
|
||||
// export type InjectablesType = ClassType | InjectableClass | InjectableFactory | InjectableValue;
|
||||
|
||||
|
|
|
@ -1,6 +1,15 @@
|
|||
export class IllegalArgumentError extends Error {
|
||||
public constructor(message?: string) {
|
||||
super(message);
|
||||
Object.setPrototypeOf(this, new.target.prototype);
|
||||
}
|
||||
}
|
||||
|
||||
export class NotSupportedDecoratorError extends Error {
|
||||
public constructor(message?: string) {
|
||||
super(message);
|
||||
Object.setPrototypeOf(this, new.target.prototype);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -22,3 +22,10 @@ export enum DecoratorType {
|
|||
METHOD = 'method',
|
||||
PARAMETER = 'parameter',
|
||||
}
|
||||
|
||||
export enum LocaleDisplayType {
|
||||
LANGUAGE = 'LANGUAGE',
|
||||
COUNTRY = 'COUNTRY',
|
||||
VARIANT = 'VARIANT',
|
||||
SCRIPT = 'SCRIPT',
|
||||
}
|
||||
|
|
67
src/ts/@overflow/commons/core/util/assert.ts
Normal file
67
src/ts/@overflow/commons/core/util/assert.ts
Normal file
|
@ -0,0 +1,67 @@
|
|||
import { IllegalArgumentError } from '../type/error';
|
||||
import { StringUtil, StringUtils } from './string';
|
||||
|
||||
|
||||
|
||||
export abstract class Assert {
|
||||
/**
|
||||
* isTrue
|
||||
*/
|
||||
public static isTrue(expression: boolean, message?: string): void {
|
||||
if (!expression) {
|
||||
throw new IllegalArgumentError(undefined !== message ? message : '[Assertion failed] - this expression must be true');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* isUndefined
|
||||
*/
|
||||
public static isUndefined(obj: any, message?: string): void {
|
||||
if (undefined !== obj) {
|
||||
throw new IllegalArgumentError(undefined !== message ? message : '[Assertion failed] - the object argument must be undefined');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* notUndefined
|
||||
*/
|
||||
public static notUndefined(obj: any, message?: string): void {
|
||||
if (undefined === obj) {
|
||||
throw new IllegalArgumentError(undefined !== message ? message : '[Assertion failed] - the object argument must not be undefined');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* isNull
|
||||
*/
|
||||
public static isNull(obj: any, message?: string): void {
|
||||
if (undefined === obj || null !== obj) {
|
||||
throw new IllegalArgumentError(undefined !== message ? message : '[Assertion failed] - the object argument must be null');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* isNull
|
||||
*/
|
||||
public static notNull(obj: any, message?: string): void {
|
||||
if (undefined === obj || null === obj) {
|
||||
throw new IllegalArgumentError(undefined !== message ? message : '[Assertion failed] - the object argument must not be null');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* isNull
|
||||
*/
|
||||
public static hasLength(text: string, message?: string): void {
|
||||
if (!StringUtils.hasLength(text)) {
|
||||
throw new IllegalArgumentError(
|
||||
undefined !== message
|
||||
? message
|
||||
: '[Assertion failed] - this String argument must have length; it must not be null or empty',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1 +1,4 @@
|
|||
export * from './assert';
|
||||
export * from './locale';
|
||||
export * from './registry';
|
||||
export * from './string';
|
||||
|
|
3
src/ts/@overflow/commons/core/util/locale.ts
Normal file
3
src/ts/@overflow/commons/core/util/locale.ts
Normal file
|
@ -0,0 +1,3 @@
|
|||
export class Locale {
|
||||
|
||||
}
|
73
src/ts/@overflow/commons/core/util/string.ts
Normal file
73
src/ts/@overflow/commons/core/util/string.ts
Normal file
|
@ -0,0 +1,73 @@
|
|||
export abstract class StringUtils {
|
||||
private static readonly FOLDER_SEPARATOR: string = '/';
|
||||
private static readonly WINDOWS_FOLDER_SEPARATOR: string = '\\';
|
||||
private static readonly TOP_PATH: string = '..';
|
||||
private static readonly CURRENT_PATH: string = '.';
|
||||
private static readonly EXTENSION_SEPARATOR: string = '.';
|
||||
|
||||
/**
|
||||
* isEmpty
|
||||
*/
|
||||
public static isEmpty(str: string): boolean {
|
||||
return (undefined === str || null === str || '' === str);
|
||||
}
|
||||
|
||||
/**
|
||||
* hasLength
|
||||
*/
|
||||
public static hasLength(str: string): boolean {
|
||||
return (undefined !== str && null !== str || 0 < str.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* hasText
|
||||
*/
|
||||
public static hasText(str: string): boolean {
|
||||
if (!StringUtils.hasLength(str)) {
|
||||
return false;
|
||||
}
|
||||
let t = StringUtils.trimAllWhitespace(str);
|
||||
return 0 !== t.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* containsWhitespace
|
||||
*/
|
||||
public static containsWhitespace(str: string): boolean {
|
||||
if (!StringUtils.hasLength(str)) {
|
||||
return false;
|
||||
}
|
||||
return /\s/.test(str);
|
||||
}
|
||||
|
||||
/**
|
||||
* trimAllWhitespace
|
||||
*/
|
||||
public static trimAllWhitespace(str: string): string {
|
||||
if (!StringUtils.hasLength(str)) {
|
||||
return str;
|
||||
}
|
||||
return str.replace(/^\s+|\s+$/g, '');
|
||||
}
|
||||
|
||||
/**
|
||||
* trimLeadingWhitespace
|
||||
*/
|
||||
public static trimLeadingWhitespace(str: string): string {
|
||||
if (!StringUtils.hasLength(str)) {
|
||||
return str;
|
||||
}
|
||||
return str.replace(/^\s*/, '');
|
||||
}
|
||||
|
||||
/**
|
||||
* trimTrailingWhitespace
|
||||
*/
|
||||
public static trimTrailingWhitespace(str: string): string {
|
||||
if (!StringUtils.hasLength(str)) {
|
||||
return str;
|
||||
}
|
||||
return str.replace(/\s*$/, '');
|
||||
}
|
||||
|
||||
}
|
42
src/ts/@overflow/commons/di/factory/__instance_definition.ts
Normal file
42
src/ts/@overflow/commons/di/factory/__instance_definition.ts
Normal file
|
@ -0,0 +1,42 @@
|
|||
import {
|
||||
ClassType, PropertyKeyType,
|
||||
} from '@overflow/commons/core/type';
|
||||
|
||||
import {
|
||||
Class,
|
||||
} from '@overflow/commons/core/reflect';
|
||||
|
||||
import {
|
||||
InstanceNameType,
|
||||
} from '@overflow/commons/di/type';
|
||||
import { InjectableAnnotation } from '@overflow/commons/di/decorators';
|
||||
|
||||
export class InstanceDefinition {
|
||||
private _instanceClass: Class;
|
||||
private _injectableAnnotation: InjectableAnnotation;
|
||||
|
||||
public constructor(instanceClassType: ClassType) {
|
||||
let clazz = Class.forClassType(instanceClassType);
|
||||
if (undefined === clazz) {
|
||||
throw new Error(`Class[${instanceClassType.name}] is not injectable type. Add @Injectable annotation.`);
|
||||
}
|
||||
|
||||
let injectableAnnotation: InjectableAnnotation = clazz.getOwnAnnotation(InjectableAnnotation);
|
||||
if (undefined === injectableAnnotation) {
|
||||
throw new Error(`Class is not Injectable type. Add @Injectable annotation to class[${instanceClassType.name}]`);
|
||||
}
|
||||
this._injectableAnnotation = injectableAnnotation;
|
||||
}
|
||||
|
||||
public get instanceClass(): Class {
|
||||
return this._instanceClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* getAttribute
|
||||
*/
|
||||
public get annotation(): InjectableAnnotation {
|
||||
return this._injectableAnnotation;
|
||||
}
|
||||
|
||||
}
|
178
src/ts/@overflow/commons/di/factory/__instance_factory.ts
Normal file
178
src/ts/@overflow/commons/di/factory/__instance_factory.ts
Normal file
|
@ -0,0 +1,178 @@
|
|||
import {
|
||||
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<InstanceNameType, any> = new Map();
|
||||
private _singletonFactories: Map<InstanceNameType, InstanceFactoryType> = new Map();
|
||||
private _instanceDefinitionMap: Map<InstanceNameType, InstanceDefinition> = new Map();
|
||||
private _instanceDefinitionNames: Set<InstanceNameType> = new Set();
|
||||
private _values: any;
|
||||
/**
|
||||
* getInstance
|
||||
*/
|
||||
public getInstance(name: InstanceNameType | undefined, requiredType: ClassType | undefined, ...args: any[]): any | undefined {
|
||||
if (undefined === name && undefined === requiredType) {
|
||||
throw new Error('One of name or requiredType must be specified.');
|
||||
}
|
||||
|
||||
if (undefined === name) {
|
||||
name = requiredType.name;
|
||||
}
|
||||
|
||||
let sharedInstance = this.getSingleton(name);
|
||||
if (undefined !== sharedInstance) {
|
||||
return sharedInstance;
|
||||
}
|
||||
|
||||
let instanceDefinition = this.getInstanceDefinition(name);
|
||||
let clazz = instanceDefinition.instanceClass;
|
||||
let ctor = clazz.getConstructor();
|
||||
let ctorParams = ctor.getParameters();
|
||||
let ctorArgs = [];
|
||||
if (0 < ctorParams.length) {
|
||||
//
|
||||
}
|
||||
|
||||
let instance = ctor.newInstance(ctorArgs);
|
||||
|
||||
this.applyInstance(clazz.getType(), instance);
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* applyInstance
|
||||
*/
|
||||
public injectByName(name: InstanceNameType, instanceDefinition: InstanceDefinition): void {
|
||||
//
|
||||
}
|
||||
|
||||
public injectByType(name: InstanceNameType, instanceDefinition: InstanceDefinition): void {
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* applyInstance
|
||||
*/
|
||||
public applyInstance(clazzType: ClassType, instance: any): void {
|
||||
let clazz: Class = Class.forClassType(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 {
|
||||
let singletonObject = this._singletonObjects.get(name);
|
||||
return singletonObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* containsInstance
|
||||
*/
|
||||
public containsInstance(name: InstanceNameType): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
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);
|
||||
if (undefined !== oldInstanceDefinition) {
|
||||
throw new Error(`InstanceDefinition[${name}] is already exist.`);
|
||||
}
|
||||
this._instanceDefinitionNames.add(name);
|
||||
this._instanceDefinitionMap.set(name, instanceDefinition);
|
||||
}
|
||||
|
||||
public removeInstanceDefinition(name: InstanceNameType): void {
|
||||
if (!this._instanceDefinitionMap.has(name)) {
|
||||
throw new Error(`InstanceDefinition[${name}] is not exist.`);
|
||||
}
|
||||
this._instanceDefinitionNames.delete(name);
|
||||
this._instanceDefinitionMap.delete(name);
|
||||
}
|
||||
|
||||
public getInstanceDefinition(name: InstanceNameType): InstanceDefinition | undefined {
|
||||
return this._instanceDefinitionMap.get(name);
|
||||
}
|
||||
|
||||
public containsInstanceDefinition(name: InstanceNameType): boolean {
|
||||
return this._instanceDefinitionMap.has(name);
|
||||
}
|
||||
|
||||
public getInstanceDefinitionNames(): Set<InstanceNameType> {
|
||||
return this._instanceDefinitionNames;
|
||||
}
|
||||
|
||||
public getInstanceDefinitionCount(): number {
|
||||
return this._instanceDefinitionMap.size;
|
||||
}
|
||||
|
||||
public isInstanceNameInUse(name: InstanceNameType): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
|
||||
|
||||
export class DependencyDescriptor {
|
||||
private methodParameter: MethodParameter;
|
||||
private field: Field;
|
||||
private declaringClass: ClassType;
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
export * from './instance_definition_registry';
|
||||
export * from './instance_definition';
|
||||
export * from './instance_factory';
|
||||
export * from './instance_name_generator';
|
||||
|
|
|
@ -1,42 +1,63 @@
|
|||
import {
|
||||
ClassType, PropertyKeyType,
|
||||
} from '@overflow/commons/core/type';
|
||||
|
||||
import {
|
||||
Class,
|
||||
} from '@overflow/commons/core/reflect';
|
||||
|
||||
import {
|
||||
InstanceNameType,
|
||||
} from '@overflow/commons/di/type';
|
||||
import { InjectableAnnotation } from '@overflow/commons/di/decorators';
|
||||
import { Assert } from '@overflow/commons/core/util';
|
||||
import { ScopeType, InjectModeType } from '@overflow/commons/di/type';
|
||||
|
||||
export class InstanceDefinition {
|
||||
private _instanceClass: Class;
|
||||
private _injectableAnnotation: InjectableAnnotation;
|
||||
private readonly attributes: Map<string, any> = new Map();
|
||||
private scope: ScopeType = ScopeType.Default;
|
||||
private injectMode: InjectModeType = InjectModeType.No;
|
||||
|
||||
public constructor(instanceClassType: ClassType) {
|
||||
let clazz = Class.forClassType(instanceClassType);
|
||||
if (undefined === clazz) {
|
||||
throw new Error(`Class[${instanceClassType.name}] is not injectable type. Add @Injectable annotation.`);
|
||||
// Attributes
|
||||
|
||||
public setAttribute(name: string, value?: any): void {
|
||||
Assert.notNull(name, 'Name must not be null');
|
||||
if (value !== undefined) {
|
||||
this.attributes.set(name, value);
|
||||
} else {
|
||||
this.removeAttribute(name);
|
||||
}
|
||||
}
|
||||
|
||||
let injectableAnnotation: InjectableAnnotation = clazz.getOwnAnnotation(InjectableAnnotation);
|
||||
if (undefined === injectableAnnotation) {
|
||||
throw new Error(`Class is not Injectable type. Add @Injectable annotation to class[${instanceClassType.name}]`);
|
||||
}
|
||||
this._injectableAnnotation = injectableAnnotation;
|
||||
public getAttribute(name: string): any | undefined {
|
||||
Assert.notNull(name, 'Name must not be null');
|
||||
return this.attributes.get(name);
|
||||
}
|
||||
|
||||
public get instanceClass(): Class {
|
||||
return this._instanceClass;
|
||||
public removeAttribute(name: string): boolean {
|
||||
Assert.notNull(name, 'Name must not be null');
|
||||
return this.attributes.delete(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* getAttribute
|
||||
*/
|
||||
public get annotation(): InjectableAnnotation {
|
||||
return this._injectableAnnotation;
|
||||
public hasAttribute(name: string): boolean {
|
||||
Assert.notNull(name, 'Name must not be null');
|
||||
return this.attributes.has(name);
|
||||
}
|
||||
|
||||
public attributeNames(): IterableIterator<string> {
|
||||
return this.attributes.keys();
|
||||
}
|
||||
|
||||
public setScope(scope: ScopeType): void {
|
||||
this.scope = scope;
|
||||
}
|
||||
|
||||
public getScope(): ScopeType {
|
||||
return this.scope;
|
||||
}
|
||||
|
||||
public isSingleton(): boolean {
|
||||
return ScopeType.Singleton === this.scope || ScopeType.Default === this.scope;
|
||||
}
|
||||
|
||||
public isTransiant(): boolean {
|
||||
return ScopeType.Transiant === this.scope;
|
||||
}
|
||||
|
||||
public setInjectMode(injectMode: InjectModeType): void {
|
||||
this.injectMode = injectMode;
|
||||
}
|
||||
|
||||
public getInjectMode(): InjectModeType {
|
||||
return this.injectMode;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,178 +1,140 @@
|
|||
import {
|
||||
ClassType, PropertyKeyType,
|
||||
} from '@overflow/commons/core/type';
|
||||
import {
|
||||
Class, Annotation, Field,
|
||||
Annotation,
|
||||
} from '@overflow/commons/core/reflect';
|
||||
|
||||
import {
|
||||
ValueAnnotation, InjectAnnotation, ResourceAnnotation,
|
||||
} from '@overflow/commons/di/decorators';
|
||||
ClassType,
|
||||
} from '@overflow/commons/core/type';
|
||||
|
||||
import {
|
||||
InjectType,
|
||||
InstanceNameType,
|
||||
InstanceFactoryType,
|
||||
} from '@overflow/commons/di/type';
|
||||
|
||||
|
||||
import {InstanceDefinitionRegistry} from './instance_definition_registry';
|
||||
import { InstanceDefinition } from './instance_definition';
|
||||
import { InstanceDefinitionRegistry } from './instance_definition_registry';
|
||||
|
||||
export class InstanceFactory {
|
||||
private instanceDefinitionRegistry: InstanceDefinitionRegistry;
|
||||
|
||||
|
||||
// Instance
|
||||
|
||||
export class InstanceFactory implements InstanceDefinitionRegistry {
|
||||
private _singletonObjects: Map<InstanceNameType, any> = new Map();
|
||||
private _singletonFactories: Map<InstanceNameType, InstanceFactoryType> = new Map();
|
||||
private _instanceDefinitionMap: Map<InstanceNameType, InstanceDefinition> = new Map();
|
||||
private _instanceDefinitionNames: Set<InstanceNameType> = new Set();
|
||||
private _values: any;
|
||||
/**
|
||||
* getInstance
|
||||
*/
|
||||
public getInstance(name: InstanceNameType | undefined, requiredType: ClassType | undefined, ...args: any[]): any | undefined {
|
||||
if (undefined === name && undefined === requiredType) {
|
||||
throw new Error('One of name or requiredType must be specified.');
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (undefined === name) {
|
||||
name = requiredType.name;
|
||||
}
|
||||
|
||||
let sharedInstance = this.getSingleton(name);
|
||||
if (undefined !== sharedInstance) {
|
||||
return sharedInstance;
|
||||
}
|
||||
|
||||
let instanceDefinition = this.getInstanceDefinition(name);
|
||||
let clazz = instanceDefinition.instanceClass;
|
||||
let ctor = clazz.getConstructor();
|
||||
let ctorParams = ctor.getParameters();
|
||||
let ctorArgs = [];
|
||||
if (0 < ctorParams.length) {
|
||||
//
|
||||
}
|
||||
|
||||
let instance = ctor.newInstance(ctorArgs);
|
||||
|
||||
this.applyInstance(clazz.getType(), instance);
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* applyInstance
|
||||
*/
|
||||
public injectByName(name: InstanceNameType, instanceDefinition: InstanceDefinition): void {
|
||||
//
|
||||
}
|
||||
|
||||
public injectByType(name: InstanceNameType, instanceDefinition: InstanceDefinition): void {
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* applyInstance
|
||||
*/
|
||||
public applyInstance(clazzType: ClassType, instance: any): void {
|
||||
let clazz: Class = Class.forClassType(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 {
|
||||
let singletonObject = this._singletonObjects.get(name);
|
||||
return singletonObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* containsInstance
|
||||
*/
|
||||
public containsInstance(name: InstanceNameType): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
public registerJSON(json: any): void {
|
||||
this._values = json;
|
||||
public isSingleton(name: InstanceNameType): boolean {
|
||||
return false;
|
||||
}
|
||||
public isTransiant(name: InstanceNameType): boolean {
|
||||
return false;
|
||||
}
|
||||
public isTypeMatch(name: InstanceNameType, typeToMatch: ClassType): boolean {
|
||||
return false;
|
||||
}
|
||||
public getType(name: InstanceNameType): ClassType {
|
||||
return undefined;
|
||||
}
|
||||
public getAliases(name: InstanceNameType): InstanceNameType[] {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
// Create Instance
|
||||
|
||||
public createInstance<T>(clazzType: ClassType<T>, injectMode?: InjectType, dependencyCheck?: boolean): T {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
public registerSingleton(name: InstanceNameType, instanceType: any, instance: any): void {
|
||||
this._singletonObjects.set(name, instance);
|
||||
public injectInstance(instance: any): void {
|
||||
//
|
||||
}
|
||||
|
||||
public registerInstanceDefinition(name: InstanceNameType, instanceDefinition: InstanceDefinition): void {
|
||||
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);
|
||||
public inject(clazzType: ClassType, injectMode?: InjectType, dependencyCheck?: boolean): any {
|
||||
//
|
||||
}
|
||||
|
||||
public removeInstanceDefinition(name: InstanceNameType): void {
|
||||
if (!this._instanceDefinitionMap.has(name)) {
|
||||
throw new Error(`InstanceDefinition[${name}] is not exist.`);
|
||||
}
|
||||
this._instanceDefinitionNames.delete(name);
|
||||
this._instanceDefinitionMap.delete(name);
|
||||
public injectInstanceProperties(instance: any, injectMode: InjectType, dependencyCheck: boolean): void {
|
||||
//
|
||||
}
|
||||
|
||||
public getInstanceDefinition(name: InstanceNameType): InstanceDefinition | undefined {
|
||||
return this._instanceDefinitionMap.get(name);
|
||||
public applyInstancePropertyValues(instance: any, name: InstanceNameType): void {
|
||||
//
|
||||
}
|
||||
|
||||
public initializeInstance(instance: any, name: InstanceNameType): any {
|
||||
//
|
||||
}
|
||||
|
||||
public applyInstancePostProcessorsBeforeInitialization(instance: any, name: InstanceNameType): any {
|
||||
//
|
||||
}
|
||||
|
||||
public applyInstancePostProcessorsAfterInitialization(instance: any, name: InstanceNameType): any {
|
||||
//
|
||||
}
|
||||
|
||||
public configureInstance(instance: any, name: InstanceNameType): any {
|
||||
//
|
||||
}
|
||||
|
||||
public destroyInstance(instance: any): any {
|
||||
//
|
||||
}
|
||||
|
||||
public resolveDependency(descriptor: DependencyDescriptor, name: InstanceNameType, injectInstanceNames?: Set<InstanceNameType>): any {
|
||||
//
|
||||
}
|
||||
|
||||
public getInstanceNamesIterator(): IterableIterator<InstanceNameType> {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// InstanceDefinition
|
||||
|
||||
public getInstanceDefinition(): InstanceDefinition {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
public containsInstanceDefinition(name: InstanceNameType): boolean {
|
||||
return this._instanceDefinitionMap.has(name);
|
||||
}
|
||||
|
||||
public getInstanceDefinitionNames(): Set<InstanceNameType> {
|
||||
return this._instanceDefinitionNames;
|
||||
}
|
||||
|
||||
public getInstanceDefinitionCount(): number {
|
||||
return this._instanceDefinitionMap.size;
|
||||
}
|
||||
|
||||
public isInstanceNameInUse(name: InstanceNameType): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
public getInstanceDefinitionCount(): number {
|
||||
return 0;
|
||||
}
|
||||
public getInstanceDefinitionNames(): InstanceNameType[] {
|
||||
return undefined;
|
||||
}
|
||||
public getInstanceNamesForType(clazzType: ClassType, includeNonSingletons?: boolean, allowEagerInit?: boolean): InstanceNameType[] {
|
||||
return undefined;
|
||||
}
|
||||
public getInstancesOfType<T>(clazzType: ClassType, includeNonSingletons?: boolean, allowEagerInit?: boolean): Map<InstanceNameType, T> {
|
||||
return undefined;
|
||||
}
|
||||
public getInstanceNamesForAnnotation<AnnotationType extends Annotation>(annotation: AnnotationType): InstanceNameType[] {
|
||||
return undefined;
|
||||
}
|
||||
public getInstancesWithAnnotation<AnnotationType extends Annotation>(annotation: AnnotationType): Map<InstanceNameType, any> {
|
||||
return undefined;
|
||||
}
|
||||
public findAnnotationOnInstance<AnnotationType extends Annotation>(name: InstanceNameType, annotation: AnnotationType): AnnotationType {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
|
||||
// Configuration
|
||||
|
||||
public ignoreDependencyType(clazzType: ClassType): void {
|
||||
//
|
||||
}
|
||||
|
||||
public registerResolvableDependency(dependencyType: ClassType, injectValue: any): void {
|
||||
//
|
||||
}
|
||||
|
||||
public isInjectCandidate(name: InstanceNameType, descriptor: DependencyDescriptor): boolean {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
import { InstanceDefinition } from './instance_definition';
|
||||
import { InstanceDefinitionRegistry } from './instance_definition_registry';
|
||||
|
||||
export class InstanceNameGenerator {
|
||||
public generateInstanceName(definition: InstanceDefinition, registry: InstanceDefinitionRegistry): string {
|
||||
return undefined;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
import {
|
||||
InstanceNameType,
|
||||
} from '@overflow/commons/di/type';
|
||||
|
||||
export class SingletonInstanceRegistry {
|
||||
public registerSingleton(name: InstanceNameType, singleton: any): void {
|
||||
//
|
||||
}
|
||||
public getSingleton(name: InstanceNameType): any {
|
||||
return undefined;
|
||||
}
|
||||
public containsSingleton(name: InstanceNameType): boolean {
|
||||
return false;
|
||||
}
|
||||
public getSingletonNames(): InstanceNameType[] {
|
||||
return undefined;
|
||||
}
|
||||
public getSingletonCount(): number {
|
||||
return 0;
|
||||
}
|
||||
}
|
15
src/ts/@overflow/commons/di/type/error.ts
Normal file
15
src/ts/@overflow/commons/di/type/error.ts
Normal file
|
@ -0,0 +1,15 @@
|
|||
export class InstanceError extends Error {
|
||||
public constructor(message?: string) {
|
||||
super(message);
|
||||
Object.setPrototypeOf(this, new.target.prototype);
|
||||
}
|
||||
}
|
||||
|
||||
export class NoSuchInstanceDefinitionError extends InstanceError {
|
||||
public constructor(message?: string) {
|
||||
super(message);
|
||||
Object.setPrototypeOf(this, new.target.prototype);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1 +1,2 @@
|
|||
export * from './error';
|
||||
export * from './type';
|
||||
|
|
|
@ -6,6 +6,13 @@ export type InstanceNameType = IdentityType<string>;
|
|||
export type InstanceFactoryType = (...args: any[]) => any;
|
||||
|
||||
export enum ScopeType {
|
||||
Default = '',
|
||||
Singleton = 'Singleton',
|
||||
Transiant = 'Transiant',
|
||||
}
|
||||
|
||||
export enum InjectModeType {
|
||||
No = 'No',
|
||||
ByName = 'ByName',
|
||||
ByType = 'ByType',
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user