This commit is contained in:
crusader 2018-01-23 19:21:47 +09:00
parent f0247ea2bd
commit 8be774ec18
17 changed files with 266 additions and 85 deletions

View File

@ -32,6 +32,19 @@ export class Application {
this._appClass = clazz;
this._appAnnotation = wa;
this._applicationContext = new ApplicationContext();
let injectables: ClassType[] = this._appAnnotation.attributes.injectables;
this._applicationContext.registerInjectables(...injectables);
let configurations: ClassType[] = this._appAnnotation.attributes.configurations;
this._applicationContext.registerConfigurations(...configurations);
let jsonSources: any[] = this._appAnnotation.attributes.jsonSources;
this._applicationContext.registerJSONSources(...jsonSources);
this._applicationContext.registerInjectable(this._appClass.getType(), undefined);
}
public static async run(primaryClass: ClassType): Promise<ApplicationContext> {
@ -42,18 +55,13 @@ export class Application {
* run
*/
public run(): ApplicationContext {
this._applicationContext = new ApplicationContext();
let injectables: ClassType[] = this.getInjectables();
this._applicationContext.instanceDefinitionReader.registerInjectables(...injectables);
let runner = this.findRunner();
if (undefined === runner) {
throw new Error(`There is not exist @Runner on Application[${this._appClass.getName()}]`);
}
let instanceFactory = this._applicationContext.instanceFactory;
let instance = instanceFactory.getInstance();
let instance = this._applicationContext.getInstance(undefined, this._appClass.getType());
runner.invoke(instance);

View File

@ -6,17 +6,20 @@ import {
InstanceFactory,
} from '@overflow/commons/di/factory';
import {
InstanceNameType,
} from '@overflow/commons/di/type';
import { ApplicationContextIDType } from '@overflow/commons/application/type';
import { MessageSource } from './message_source';
import { JSONSource } from './json_source';
import { InstanceDefinitionReader } from './instance_definition_reader';
export class ApplicationContext {
public static readonly MESSAGE_SOURCE_INSTANCE_NAME: string = 'messageSource';
private _id: ApplicationContextIDType;
private _parent: ApplicationContext;
private _messageSource: MessageSource;
private _jsonSource: JSONSource;
private _instanceFactory: InstanceFactory;
private _instanceDefinitionReader: InstanceDefinitionReader;
@ -24,9 +27,9 @@ export class ApplicationContext {
this.parent = parent;
this._instanceFactory = new InstanceFactory();
this._instanceDefinitionReader = new InstanceDefinitionReader(this._instanceFactory.instanceDefinitionRegistry);
this._jsonSource = new JSONSource();
}
// Context
public get id(): ApplicationContextIDType {
@ -47,19 +50,11 @@ export class ApplicationContext {
this._parent = parent;
}
public get instanceFactory(): InstanceFactory {
return this._instanceFactory;
}
public get instanceDefinitionReader(): InstanceDefinitionReader {
return this._instanceDefinitionReader;
}
// Configuration
// MessageSource
public get messageSource(): MessageSource {
return this._messageSource;
// JSONSource
public get jsonSource(): JSONSource {
return this._jsonSource;
}
// Lifecycle
@ -73,4 +68,22 @@ export class ApplicationContext {
public isRunning(): boolean {
return false;
}
// Instance
public registerInjectables(...injectables: ClassType[]): void {
this._instanceDefinitionReader.registerInjectables(...injectables);
}
public registerInjectable(injectable: ClassType, name: InstanceNameType | undefined): InstanceNameType {
return this._instanceDefinitionReader.registerInjectable(injectable, name);
}
public registerConfigurations(...configurations: ClassType[]): void {
return this._instanceDefinitionReader.registerConfigurations(...configurations);
}
public registerJSONSources(...jsonSources: any[]): void {
this._jsonSource.addSources(...jsonSources);
}
}

View File

@ -1,4 +1,5 @@
export * from './application_context';
export * from './instance_definition_reader';
export * from './json_source';
export * from './scope_metadata';
export * from './scope_metadata_resolver';

View File

@ -1,9 +1,15 @@
import {
Annotation,
Class,
Method,
} from '@overflow/commons/core/reflect';
import {
ClassType,
PropertyKeyType,
NotDecoratedClassError,
} from '@overflow/commons/core/type';
import { Annotation } from '@overflow/commons/core/reflect';
import {
Assert,
AnnotationUtils,
@ -25,6 +31,15 @@ import {
NotInjectableError,
} from '@overflow/commons/di/type';
import {
ConfigurationAnnotation,
InstanceAnnotation,
} from '@overflow/commons/application/decorators';
import {
NotConfigurationError,
} from '@overflow/commons/application/type';
import { ScopeMetadataResolver } from './scope_metadata_resolver';
export class InstanceDefinitionReader {
@ -43,13 +58,18 @@ export class InstanceDefinitionReader {
});
}
public registerInjectable<QT extends Annotation>
(injectable: ClassType, name: InstanceNameType | undefined, ...qualifierTypes: ClassType<QT>[]): void {
public registerInjectable(injectable: ClassType, name: InstanceNameType | undefined): InstanceNameType {
let clazz = Class.forClassType(injectable);
if (undefined === clazz) {
throw new NotDecoratedClassError();
}
if (!AnnotationUtils.hasAnnotation(injectable, InjectableAnnotation)) {
throw new NotInjectableError(`Class[${injectable.name}] does not contains @Injectable`);
}
let definition: InstanceDefinition = new InstanceDefinition(injectable);
let definition: InstanceDefinition = new InstanceDefinition();
definition.instanceClass = clazz;
let scopeMeta = this.scopeMetadataResolver.resolveScopeMetadata(definition);
definition.scope = scopeMeta.scope;
let instanceName =
@ -57,12 +77,42 @@ export class InstanceDefinitionReader {
? name
: this.instanceNameGenerator.generateInstanceName(definition, this.instanceDefinitionRegistry);
if (undefined !== qualifiers) {
qualifiers.forEach(qualifier => {
definition.addQualifier(qualifier);
});
this.instanceDefinitionRegistry.registerInstanceDefinition(instanceName, definition);
return instanceName;
}
public registerConfigurations(...configurations: ClassType[]): void {
configurations.forEach(configuration => {
this.registerConfiguration(configuration);
});
}
public registerConfiguration(configuration: ClassType): void {
let clazz = Class.forClassType(configuration);
if (undefined === clazz) {
throw new NotDecoratedClassError();
}
this.instanceDefinitionRegistry.registerInstanceDefinition(instanceName, definition);
if (!AnnotationUtils.hasAnnotation(configuration, ConfigurationAnnotation)) {
throw new NotConfigurationError(`Class[${configuration.name}] does not contains @Configuration`);
}
let factoryInstanceName = this.registerInjectable(configuration, undefined);
let methods = clazz.getMethods();
methods.forEach((method: Method, methodName: PropertyKeyType) => {
let ia = method.getAnnotation(InstanceAnnotation);
if (undefined === ia) {
return;
}
let instanceName = undefined !== ia.attributes.name ? ia.attributes.name : method.getName();
let definition: InstanceDefinition = new InstanceDefinition();
definition.factoryInstanceName = factoryInstanceName;
definition.factoryMethod = method;
this.instanceDefinitionRegistry.registerInstanceDefinition(instanceName, definition);
});
}
}

View File

@ -0,0 +1,21 @@
import { Locale } from '@overflow/commons/core/util';
export class JSONSource {
private _jsonSources: any;
public constructor() {
this._jsonSources = {};
}
public addSources(...jsonSources: any[]): void {
if (undefined === jsonSources || null === jsonSources) {
return;
}
this._jsonSources = Object.assign(this._jsonSources, ...jsonSources);
}
public getSource(code: string, args: any[], defaultMessage: string | undefined, locale: Locale): string {
return undefined;
}
}

View File

@ -1,7 +0,0 @@
import { Locale } from '@overflow/commons/core/util';
export class MessageSource {
public getMessage(code: string, args: any[], defaultMessage: string | undefined, locale: Locale): string {
return undefined;
}
}

View File

@ -1,4 +1,5 @@
export * from './configuration';
export * from './instance';
export * from './json_source';
export * from './runner';
export * from './web_application';

View File

@ -0,0 +1,42 @@
import {
Annotation,
Decorator,
} from '@overflow/commons/core/reflect';
import {
PropertyKeyType,
TypeUtil,
} from '@overflow/commons/core/type';
export interface JSONSourceAnnotationAttributes {
key: string;
}
export class JSONSourceAnnotation extends Annotation {
public readonly attributes: JSONSourceAnnotationAttributes = {
key: undefined,
};
public constructor(key: string | JSONSourceAnnotationAttributes) {
super();
if (undefined === key) {
throw new Error(`key attribute must be specified.`);
}
if (TypeUtil.isString(key)) {
this.attributes.key = <string>key;
} else {
this.copyAttributes(this.attributes, <JSONSourceAnnotationAttributes>key);
}
}
public propertyDecorator(target: Object, propertyKey: PropertyKeyType): void {
console.log('JSONSource');
}
public parameterDecorator(target: Object, propertyKey: PropertyKeyType, parameterIndex: number): void {
console.log('JSONSource');
}
}
export const JSONSource = Decorator.create(JSONSourceAnnotation);

View File

@ -8,7 +8,9 @@ import {
PropertyKeyType,
} from '@overflow/commons/core/type';
import { Configuration } from './configuration';
import {
Injectable,
} from '@overflow/commons/di/decorators';
export interface WebApplicationAnnotationAttributes {
jsonSources?: any[];
@ -16,7 +18,7 @@ export interface WebApplicationAnnotationAttributes {
configurations?: ClassType[];
}
@Configuration()
@Injectable()
export class WebApplicationAnnotation extends Annotation {
public readonly attributes: WebApplicationAnnotationAttributes = {
};

View File

@ -0,0 +1,13 @@
export class ApplicationError extends Error {
public constructor(message?: string) {
super(message);
Object.setPrototypeOf(this, new.target.prototype);
}
}
export class NotConfigurationError extends ApplicationError {
public constructor(message?: string) {
super(message);
Object.setPrototypeOf(this, new.target.prototype);
}
}

View File

@ -1 +1,2 @@
export * from './error';
export * from './type';

View File

@ -12,4 +12,9 @@ export class NotSupportedDecoratorError extends Error {
}
}
export class NotDecoratedClassError extends Error {
public constructor(message?: string) {
super(message);
Object.setPrototypeOf(this, new.target.prototype);
}
}

View File

@ -0,0 +1,3 @@
export class ArgumentValues {
}

View File

@ -1,9 +1,13 @@
import {
Annotation,
Class,
Method,
Parameter,
} from '@overflow/commons/core/reflect';
import {
ClassType,
PropertyKeyType,
} from '@overflow/commons/core/type';
import { Assert } from '@overflow/commons/core/util';
@ -15,34 +19,65 @@ import {
import {
ScopeType,
InjectModeType,
InstanceFactoryType,
InstanceNameType,
NotInjectableError,
} from '@overflow/commons/di/type';
/**
*
*
* Class: create by class constructor (class, constructor parameter)
* Instance method: create by instance method (instance name, method name, method parameter)
*/
export class InstanceDefinition {
private readonly attributes: Map<string, any> = new Map();
private _instanceClass: Class;
private _factoryInstanceName: InstanceNameType;
private _factoryMethod: Method;
private _annotations: Map<ClassType, Annotation>;
private _scope: ScopeType = ScopeType.Default;
private _injectMode: InjectModeType = InjectModeType.No;
public constructor() {
this._annotations = new Map();
}
public constructor(instanceClassType: ClassType) {
let clazz = Class.forClassType(instanceClassType);
if (undefined === clazz) {
throw new NotInjectableError();
}
public set instanceClass(instanceClass: Class) {
this._instanceClass = instanceClass;
this._instanceClass = clazz;
let annotations = instanceClass.getOwnAnnotations();
annotations.forEach((annon: Annotation, classType: ClassType) => {
this._annotations.set(classType, annon);
});
}
public get instanceClass(): Class {
return this._instanceClass;
}
// Metadata
public getMetadata(): AnnotationMetadata {
return undefined;
public set factoryInstanceName(factoryInstanceName: InstanceNameType) {
this._factoryInstanceName = factoryInstanceName;
}
public get factoryInstanceName(): InstanceNameType {
return this._factoryInstanceName;
}
public set factoryMethod(factoryMethod: Method) {
this._factoryMethod = factoryMethod;
let annotations = factoryMethod.getOwnAnnotations();
annotations.forEach((annon: Annotation, classType: ClassType) => {
this._annotations.set(classType, annon);
});
}
public get factoryMethod(): Method {
return this._factoryMethod;
}
// Metadata
public set scope(scope: ScopeType) {
this.scope = scope;
}
@ -51,14 +86,6 @@ export class InstanceDefinition {
return this.scope;
}
public get injectMode(): InjectModeType {
return this._injectMode;
}
public set injectMode(injectMode: InjectModeType) {
this._injectMode = injectMode;
}
public isSingleton(): boolean {
return ScopeType.Singleton === this.scope || ScopeType.Default === this.scope;
}

View File

@ -4,12 +4,26 @@ import {
import {InstanceDefinition} from './instance_definition';
export interface InstanceDefinitionRegistry {
registerInstanceDefinition(name: InstanceNameType, instanceDefinition:InstanceDefinition): void;
removeInstanceDefinition(name: InstanceNameType): void;
getInstanceDefinition(name: InstanceNameType): InstanceDefinition;
containsInstanceDefinition(name: InstanceNameType): boolean;
getInstanceDefinitionNames(): Set<InstanceNameType>;
getInstanceDefinitionCount(): number;
isInstanceNameInUse(name: InstanceNameType): boolean;
export class InstanceDefinitionRegistry {
public registerInstanceDefinition(name: InstanceNameType, instanceDefinition:InstanceDefinition): void {
//
}
public removeInstanceDefinition(name: InstanceNameType): void {
//
}
public getInstanceDefinition(name: InstanceNameType): InstanceDefinition | undefined {
return undefined;
}
public containsInstanceDefinition(name: InstanceNameType): boolean {
return false;
}
public getInstanceDefinitionNames(): Set<InstanceNameType> | undefined {
return undefined;
}
public getInstanceDefinitionCount(): number {
return 0;
}
public isInstanceNameInUse(name: InstanceNameType): boolean {
return false;
}
}

View File

@ -17,6 +17,9 @@ import { InstanceDefinitionRegistry } from './instance_definition_registry';
export class InstanceFactory {
private _instanceDefinitionRegistry: InstanceDefinitionRegistry;
public constructor() {
this._instanceDefinitionRegistry = new InstanceDefinitionRegistry();
}
public get instanceDefinitionRegistry(): InstanceDefinitionRegistry {
return this._instanceDefinitionRegistry;

View File

@ -59,14 +59,6 @@ declare global {
const module: { hot: any };
}
abstract class B {
public abstract b(): void;
}
// abstract class C {
// public abstract c(): void;
// }
@WebApplication({
injectables: injectables,
jsonSources: jsonSources,
@ -77,18 +69,10 @@ abstract class B {
WebAppConfiguration,
],
})
class WebAppApplication implements B {
class WebAppApplication {
private static isProduction:boolean = process.env.NODE_ENV === 'production' ? true : false;
private static useReduxDevTools:boolean = window.devToolsExtension && !WebAppApplication.isProduction ? true : false;
public b(): void {
//
}
public c(): void {
//
}
@Resource()
private containerPromise: Promise<HTMLElement>;
private container: HTMLElement;