AppContext ing
This commit is contained in:
parent
09226de460
commit
01bd5e5f94
|
@ -42,7 +42,7 @@ import {
|
||||||
import * as injectTapEventPlugin from 'react-tap-event-plugin';
|
import * as injectTapEventPlugin from 'react-tap-event-plugin';
|
||||||
|
|
||||||
import Platform from '@overflow/commons/platform';
|
import Platform from '@overflow/commons/platform';
|
||||||
import AppContext from '@overflow/commons/context';
|
import AppContext from '@overflow/commons/context/AppContext';
|
||||||
import * as AppContextLifecycleActions from '@overflow/commons/context/redux/action/lifecycle';
|
import * as AppContextLifecycleActions from '@overflow/commons/context/redux/action/lifecycle';
|
||||||
import WebSocketRPC from '@overflow/commons/websocket/WebSocketRPC';
|
import WebSocketRPC from '@overflow/commons/websocket/WebSocketRPC';
|
||||||
import ReducerContext from '@overflow/commons/redux/ReducerContext';
|
import ReducerContext from '@overflow/commons/redux/ReducerContext';
|
||||||
|
@ -86,8 +86,8 @@ class Application {
|
||||||
this.displayLoading();
|
this.displayLoading();
|
||||||
|
|
||||||
this.context = await this.initContext();
|
this.context = await this.initContext();
|
||||||
// this.rpcClient = await this.initRpcClient();
|
this.rpcClient = await this.initRpcClient();
|
||||||
// this.context.put(this.rpcClient);
|
this.context.PouchFactory.registerPouch(this.rpcClient);
|
||||||
|
|
||||||
await this.initRedux();
|
await this.initRedux();
|
||||||
|
|
||||||
|
@ -102,7 +102,7 @@ class Application {
|
||||||
|
|
||||||
private initContext(): Promise<AppContext> {
|
private initContext(): Promise<AppContext> {
|
||||||
const appContext = new Promise<AppContext>(resolve => {
|
const appContext = new Promise<AppContext>(resolve => {
|
||||||
const context = AppContext.getContext();
|
const context = AppContext.getInstance();
|
||||||
resolve(context);
|
resolve(context);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import inject from '../context/decorator/inject';
|
import Inject from '../context/pouches/decorator/Inject';
|
||||||
import WebSocketRPC from '../websocket/WebSocketRPC';
|
import WebSocketRPC from '../websocket/WebSocketRPC';
|
||||||
|
|
||||||
abstract class Service {
|
abstract class Service {
|
||||||
@inject({qualifier: '11111', required: false})
|
@Inject({required: false})
|
||||||
private webSocketRPC: WebSocketRPC;
|
private webSocketRPC: WebSocketRPC;
|
||||||
private name: string;
|
private name: string;
|
||||||
protected constructor(name: string) {
|
protected constructor(name: string) {
|
||||||
|
|
41
src/ts/@overflow/commons/context/AppContext.ts
Normal file
41
src/ts/@overflow/commons/context/AppContext.ts
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
import PouchFactory from './pouches/factory/PouchFactory';
|
||||||
|
import {
|
||||||
|
ClassConstructor,
|
||||||
|
} from './pouches/constants';
|
||||||
|
|
||||||
|
class AppContext {
|
||||||
|
private static _instance: AppContext;
|
||||||
|
private _pouchFactory: PouchFactory;
|
||||||
|
|
||||||
|
public constructor() {
|
||||||
|
this._pouchFactory = new PouchFactory();
|
||||||
|
}
|
||||||
|
|
||||||
|
public get PouchFactory(): PouchFactory {
|
||||||
|
return this._pouchFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getPouch
|
||||||
|
*/
|
||||||
|
public getPouch<T>(type: ClassConstructor<T>, ...args: any[]): T {
|
||||||
|
return this._pouchFactory.getPouch(type, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getPouchByQualifier
|
||||||
|
*/
|
||||||
|
public getPouchByQualifier<T>(type: ClassConstructor<T>, qualifier: string | symbol, ...args: any[]): T {
|
||||||
|
return this._pouchFactory.getPouchByQualifier(type, qualifier, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static getInstance(): AppContext {
|
||||||
|
if (undefined === AppContext._instance) {
|
||||||
|
AppContext._instance = new AppContext();
|
||||||
|
}
|
||||||
|
return AppContext._instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AppContext;
|
|
@ -21,7 +21,7 @@ class AppContext {
|
||||||
this.instanceMap.set(aaa, instance);
|
this.instanceMap.set(aaa, instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
private setValue(type: any, target: object): void {
|
private setValue(type: Function, target: object): void {
|
||||||
if (type.constructor === Object) {
|
if (type.constructor === Object) {
|
||||||
console.log('Object');
|
console.log('Object');
|
||||||
return;
|
return;
|
||||||
|
@ -44,7 +44,7 @@ class AppContext {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static getService<T>(type: ClassConstructor<T>, ...args: any[]): T {
|
public static getService<T>(type: ClassConstructor<T>, ...args: any[]): T {
|
||||||
let clazz = type.prototype;
|
let clazz: Function = type.prototype;
|
||||||
let instance = Object.create(clazz);
|
let instance = Object.create(clazz);
|
||||||
instance.constructor.apply(instance, args);
|
instance.constructor.apply(instance, args);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
import { PouchScope, POUCH_DEFAULT_QUALIFIER } from '../constants';
|
||||||
|
|
||||||
|
class PouchDefinition {
|
||||||
|
protected _type: Function;
|
||||||
|
protected _scope: PouchScope = PouchScope.SINGLETON;
|
||||||
|
protected _qualifier: string | symbol;
|
||||||
|
protected _postConstruct: string[] = null;
|
||||||
|
protected _preDestroy: string[] = null;
|
||||||
|
|
||||||
|
public constructor(type: Function) {
|
||||||
|
this._type = type;
|
||||||
|
this._qualifier = POUCH_DEFAULT_QUALIFIER;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get type(): Function {
|
||||||
|
return this._type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get scope(): PouchScope {
|
||||||
|
return this._scope;
|
||||||
|
}
|
||||||
|
|
||||||
|
public set scope(scope: PouchScope) {
|
||||||
|
this._scope = scope;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get qualifier(): string | symbol {
|
||||||
|
return this._qualifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public set qualifier(qualifier: string | symbol) {
|
||||||
|
this._qualifier = qualifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get postConstruct(): string[] {
|
||||||
|
return this._postConstruct;
|
||||||
|
}
|
||||||
|
|
||||||
|
public addPostConstruct(postConstruct: string): void {
|
||||||
|
if (null == this._postConstruct) {
|
||||||
|
this._postConstruct = [];
|
||||||
|
}
|
||||||
|
this._postConstruct.push(postConstruct);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get preDestroy(): string[] {
|
||||||
|
return this._preDestroy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public addPreDestroy(preDestroy: string): void {
|
||||||
|
if (null == this._preDestroy) {
|
||||||
|
this._preDestroy = [];
|
||||||
|
}
|
||||||
|
this._preDestroy.push(preDestroy);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PouchDefinition;
|
|
@ -0,0 +1,92 @@
|
||||||
|
import * as METADATA from '../constants';
|
||||||
|
import { DecoratorType, POUCH_DEFAULT_QUALIFIER } from '../constants';
|
||||||
|
import InjectConfig from '../decorator/InjectConfig';
|
||||||
|
|
||||||
|
export interface InjectItem {
|
||||||
|
decoratorType: DecoratorType;
|
||||||
|
propertyConfig?: InjectConfig;
|
||||||
|
parameterConfigMap?: Map<number, InjectConfig>;
|
||||||
|
}
|
||||||
|
|
||||||
|
class PouchInjectDefinition {
|
||||||
|
protected target: Object;
|
||||||
|
protected injectMap: Map<string | symbol, InjectItem>;
|
||||||
|
|
||||||
|
public constructor(target: Object) {
|
||||||
|
this.target = target;
|
||||||
|
this.injectMap = new Map();
|
||||||
|
}
|
||||||
|
|
||||||
|
public get injectors(): Map<string | symbol, InjectItem> {
|
||||||
|
return this.injectMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* addInject
|
||||||
|
*/
|
||||||
|
public addInject(injectConfig: InjectConfig, propertyKey: string | symbol, parameterIndex?: number): void {
|
||||||
|
if (undefined === injectConfig.qualifier) {
|
||||||
|
injectConfig.qualifier = POUCH_DEFAULT_QUALIFIER;
|
||||||
|
}
|
||||||
|
if (undefined === injectConfig.required) {
|
||||||
|
injectConfig.required = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(typeof parameterIndex === 'number') {
|
||||||
|
this.addInjectParameter(injectConfig, propertyKey, parameterIndex);
|
||||||
|
} else {
|
||||||
|
this.addInjectProperty(injectConfig, propertyKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private addInjectParameter(injectConfig: InjectConfig, propertyKey: string | symbol, parameterIndex: number): void {
|
||||||
|
let injectItem: InjectItem;
|
||||||
|
let parameterTypes: any[] = Reflect.getMetadata(METADATA.DESIGN_PARAMTYPES, this.target, propertyKey);
|
||||||
|
|
||||||
|
if (undefined === injectConfig.type) {
|
||||||
|
injectConfig.type = parameterTypes[parameterIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.injectMap.has(propertyKey)) {
|
||||||
|
injectItem = this.injectMap.get(propertyKey);
|
||||||
|
} else {
|
||||||
|
injectItem = {
|
||||||
|
decoratorType: DecoratorType.PARAMETER,
|
||||||
|
};
|
||||||
|
this.injectMap.set(propertyKey, injectItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null !== injectItem.parameterConfigMap) {
|
||||||
|
if (injectItem.parameterConfigMap.has(parameterIndex)) {
|
||||||
|
throw new Error(`Cannot apply @inject decorator on one parameter[${propertyKey}:${parameterIndex}] multiple times.`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
injectItem.parameterConfigMap = new Map();
|
||||||
|
}
|
||||||
|
|
||||||
|
injectItem.parameterConfigMap.set(parameterIndex, injectConfig);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private addInjectProperty(injectConfig: InjectConfig, propertyKey: string | symbol): void {
|
||||||
|
if (this.injectMap.has(propertyKey)) {
|
||||||
|
throw new Error(`Cannot apply @inject decorator on one property[${propertyKey}] multiple times.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
let propertyType: any = Reflect.getMetadata(METADATA.DESIGN_TYPE, this.target, propertyKey);
|
||||||
|
|
||||||
|
if (undefined === injectConfig.type) {
|
||||||
|
injectConfig.type = propertyType;
|
||||||
|
}
|
||||||
|
|
||||||
|
let injectItem: InjectItem = {
|
||||||
|
decoratorType: DecoratorType.PROPERTY,
|
||||||
|
propertyConfig: injectConfig,
|
||||||
|
};
|
||||||
|
|
||||||
|
this.injectMap.set(propertyKey, injectItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PouchInjectDefinition;
|
29
src/ts/@overflow/commons/context/pouches/constants.ts
Normal file
29
src/ts/@overflow/commons/context/pouches/constants.ts
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
// used to access design time types
|
||||||
|
export const DESIGN_TYPE = 'design:type';
|
||||||
|
// used to access design time types
|
||||||
|
export const DESIGN_PARAMTYPES = 'design:paramtypes';
|
||||||
|
// used to access design time types
|
||||||
|
export const DESIGN_RETURNTYPE = 'design:returntype';
|
||||||
|
|
||||||
|
|
||||||
|
// used to store types to be injected
|
||||||
|
export const POUCH_DEFINITION = 'loafer:pouch_definition';
|
||||||
|
|
||||||
|
// used to store types to be injected
|
||||||
|
export const POUCH_INJECT_DEFINITION = 'loafer:pouch_inject_definition';
|
||||||
|
|
||||||
|
export const POUCH_DEFAULT_QUALIFIER = Symbol('__QUALIFIER__');
|
||||||
|
|
||||||
|
export enum PouchScope {
|
||||||
|
SINGLETON,
|
||||||
|
PROTOTYPE,
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum DecoratorType {
|
||||||
|
CLASS,
|
||||||
|
PROPERTY,
|
||||||
|
PARAMETER,
|
||||||
|
METHOD,
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ClassConstructor<T> = {new(...args: any[]): T};
|
66
src/ts/@overflow/commons/context/pouches/decorator/Inject.ts
Normal file
66
src/ts/@overflow/commons/context/pouches/decorator/Inject.ts
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
import * as METADATA from '../constants';
|
||||||
|
import { POUCH_DEFAULT_QUALIFIER } from '../constants';
|
||||||
|
import InjectConfig from './InjectConfig';
|
||||||
|
import PouchInjectDefinition from '../config/PouchInjectDefinition';
|
||||||
|
|
||||||
|
const Inject = (injectConfig: InjectConfig = {}) => {
|
||||||
|
return (...args: any[]) => {
|
||||||
|
switch(args.length) {
|
||||||
|
case 1:
|
||||||
|
return injectClass.apply(this, args);
|
||||||
|
case 2:
|
||||||
|
return injectProperty.apply(this, args);
|
||||||
|
case 3:
|
||||||
|
if(typeof args[2] === 'number') {
|
||||||
|
return injectParameter.apply(this, args);
|
||||||
|
}
|
||||||
|
return injectMethod.apply(this, args);
|
||||||
|
default:
|
||||||
|
throw new Error('@Inject decorators are not valid here!');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const injectClass = (injectConfig: InjectConfig = {}) => {
|
||||||
|
return <TFunction extends Function>(target: TFunction): TFunction | void => {
|
||||||
|
throw new Error('Cannot apply @Inject decorator on Class.');
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const injectProperty = (injectConfig: InjectConfig = {}) => {
|
||||||
|
return (target: Object, propertyKey: string | symbol): void => {
|
||||||
|
let pouchInjectDefinition: PouchInjectDefinition = getPouchInjectDefinition(target);
|
||||||
|
pouchInjectDefinition.addInject(injectConfig, propertyKey);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const injectParameter = (injectConfig: InjectConfig = {}) => {
|
||||||
|
return (target: Object, propertyKey: string | symbol, parameterIndex: number): void => {
|
||||||
|
let pouchInjectDefinition: PouchInjectDefinition = getPouchInjectDefinition(target);
|
||||||
|
pouchInjectDefinition.addInject(injectConfig, propertyKey, parameterIndex);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const injectMethod = (injectConfig: InjectConfig = {}) => {
|
||||||
|
return (target: Object, propertyKey: string | symbol,
|
||||||
|
descriptor: TypedPropertyDescriptor<any>): TypedPropertyDescriptor<any> | void => {
|
||||||
|
throw new Error('Cannot apply @Inject decorator on Class.');
|
||||||
|
|
||||||
|
// return descriptor;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const getPouchInjectDefinition = (target: Object) => {
|
||||||
|
let pouchInjectDefinition: PouchInjectDefinition;
|
||||||
|
if (Reflect.hasOwnMetadata(METADATA.POUCH_INJECT_DEFINITION, target) !== true) {
|
||||||
|
pouchInjectDefinition = new PouchInjectDefinition(target);
|
||||||
|
Reflect.defineMetadata(METADATA.POUCH_INJECT_DEFINITION, pouchInjectDefinition, target);
|
||||||
|
} else {
|
||||||
|
pouchInjectDefinition = Reflect.getMetadata(METADATA.POUCH_INJECT_DEFINITION, target);
|
||||||
|
}
|
||||||
|
return pouchInjectDefinition;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Inject;
|
|
@ -0,0 +1,7 @@
|
||||||
|
interface InjectConfig {
|
||||||
|
qualifier?: string | symbol;
|
||||||
|
required?: boolean;
|
||||||
|
type?: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default InjectConfig;
|
|
@ -0,0 +1,60 @@
|
||||||
|
import * as METADATA from '../constants';
|
||||||
|
import PouchDefinition from '../config/PouchDefinition';
|
||||||
|
|
||||||
|
|
||||||
|
const Injectable = (...args: any[]) => {
|
||||||
|
switch(args.length) {
|
||||||
|
case 1:
|
||||||
|
return injectableClass.apply(this, args);
|
||||||
|
case 2:
|
||||||
|
return injectableProperty.apply(this, args);
|
||||||
|
case 3:
|
||||||
|
if(typeof args[2] === 'number') {
|
||||||
|
return injectableParameter.apply(this, args);
|
||||||
|
}
|
||||||
|
return injectableMethod.apply(this, args);
|
||||||
|
default:
|
||||||
|
throw new Error('@Injectable decorators are not valid here!');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const injectableClass = <TFunction extends Function>(target: TFunction): TFunction | void => {
|
||||||
|
if (Reflect.hasOwnMetadata(METADATA.POUCH_DEFINITION, target) === true) {
|
||||||
|
throw new Error('Cannot apply @injectable decorator multiple times.');
|
||||||
|
}
|
||||||
|
|
||||||
|
let pouchDefinition: PouchDefinition = getPouchDefinition(target.prototype);
|
||||||
|
|
||||||
|
return target;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const injectableProperty = (target: Object, propertyKey: string | symbol): void => {
|
||||||
|
throw new Error('Cannot apply @Injectable decorator on property.');
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const injectableParameter = (target: Object, propertyKey: string | symbol, parameterIndex: number): void => {
|
||||||
|
throw new Error('Cannot apply @Injectable decorator on parameter.');
|
||||||
|
};
|
||||||
|
|
||||||
|
const injectableMethod = <T>(target: Object, propertyKey: string | symbol,
|
||||||
|
descriptor: TypedPropertyDescriptor<T>): TypedPropertyDescriptor<T> | void => {
|
||||||
|
throw new Error('Cannot apply @Injectable decorator on method.');
|
||||||
|
// return descriptor;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getPouchDefinition = <TFunction extends Function>(target: TFunction) => {
|
||||||
|
let pouchDefinition: PouchDefinition;
|
||||||
|
if (Reflect.hasOwnMetadata(METADATA.POUCH_DEFINITION, target) !== true) {
|
||||||
|
pouchDefinition = new PouchDefinition(target);
|
||||||
|
Reflect.defineMetadata(METADATA.POUCH_DEFINITION, pouchDefinition, target);
|
||||||
|
} else {
|
||||||
|
pouchDefinition = Reflect.getMetadata(METADATA.POUCH_DEFINITION, target);
|
||||||
|
}
|
||||||
|
return pouchDefinition;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export default Injectable;
|
|
@ -0,0 +1,14 @@
|
||||||
|
import * as METADATA from '../constants';
|
||||||
|
import PouchDefinition from '../config/PouchDefinition';
|
||||||
|
|
||||||
|
const PostConstruct = (target: Object, propertyKey: string, descriptor: TypedPropertyDescriptor<any>): TypedPropertyDescriptor<any> => {
|
||||||
|
if (Reflect.hasOwnMetadata(METADATA.POUCH_DEFINITION, target) !== true) {
|
||||||
|
throw new Error('Cannot apply @PostConstruct decorator on the not @Injectable class.');
|
||||||
|
}
|
||||||
|
let pouchDefinition: PouchDefinition = Reflect.getMetadata(METADATA.POUCH_DEFINITION, target);
|
||||||
|
pouchDefinition.addPostConstruct(propertyKey);
|
||||||
|
|
||||||
|
return descriptor;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default PostConstruct;
|
|
@ -0,0 +1,14 @@
|
||||||
|
import * as METADATA from '../constants';
|
||||||
|
import PouchDefinition from '../config/PouchDefinition';
|
||||||
|
|
||||||
|
const PreDestroy = (target: Object, propertyKey: string, descriptor: TypedPropertyDescriptor<any>): TypedPropertyDescriptor<any> => {
|
||||||
|
if (Reflect.hasOwnMetadata(METADATA.POUCH_DEFINITION, target) !== true) {
|
||||||
|
throw new Error('Cannot apply @PreDestroy decorator on the not @Injectable class.');
|
||||||
|
}
|
||||||
|
let pouchDefinition: PouchDefinition = Reflect.getMetadata(METADATA.POUCH_DEFINITION, target);
|
||||||
|
pouchDefinition.addPreDestroy(propertyKey);
|
||||||
|
|
||||||
|
return descriptor;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default PreDestroy;
|
|
@ -0,0 +1,16 @@
|
||||||
|
import * as METADATA from '../constants';
|
||||||
|
import PouchDefinition from '../config/PouchDefinition';
|
||||||
|
|
||||||
|
const Qualifier = (value: string | symbol) => {
|
||||||
|
return <TFunction extends Function>(target: TFunction): TFunction | void => {
|
||||||
|
if (Reflect.hasOwnMetadata(METADATA.POUCH_DEFINITION, target) !== true) {
|
||||||
|
throw new Error('Cannot apply @Qualifier decorator on the not @Injectable class.');
|
||||||
|
}
|
||||||
|
let pouchDefinition: PouchDefinition = Reflect.getMetadata(METADATA.POUCH_DEFINITION, target);
|
||||||
|
pouchDefinition.qualifier = value;
|
||||||
|
|
||||||
|
return target;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Qualifier;
|
17
src/ts/@overflow/commons/context/pouches/decorator/Scope.ts
Normal file
17
src/ts/@overflow/commons/context/pouches/decorator/Scope.ts
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
import * as METADATA from '../constants';
|
||||||
|
import PouchDefinition from '../config/PouchDefinition';
|
||||||
|
import { PouchScope } from '../constants';
|
||||||
|
|
||||||
|
const Scope = (value: PouchScope = PouchScope.SINGLETON) => {
|
||||||
|
return <TFunction extends Function>(target: TFunction): TFunction | void => {
|
||||||
|
if (Reflect.hasOwnMetadata(METADATA.POUCH_DEFINITION, target) !== true) {
|
||||||
|
throw new Error('Cannot apply @Scope decorator on the not @Injectable class.');
|
||||||
|
}
|
||||||
|
let pouchDefinition: PouchDefinition = Reflect.getMetadata(METADATA.POUCH_DEFINITION, target);
|
||||||
|
pouchDefinition.scope = value;
|
||||||
|
|
||||||
|
return target;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Scope;
|
195
src/ts/@overflow/commons/context/pouches/factory/PouchFactory.ts
Normal file
195
src/ts/@overflow/commons/context/pouches/factory/PouchFactory.ts
Normal file
|
@ -0,0 +1,195 @@
|
||||||
|
import * as METADATA from '../constants';
|
||||||
|
|
||||||
|
import {
|
||||||
|
ClassConstructor,
|
||||||
|
DecoratorType,
|
||||||
|
PouchScope,
|
||||||
|
POUCH_DEFAULT_QUALIFIER,
|
||||||
|
} from '../constants';
|
||||||
|
|
||||||
|
import PouchDefinition from '../config/PouchDefinition';
|
||||||
|
|
||||||
|
import PouchInjectDefinition, {
|
||||||
|
InjectItem,
|
||||||
|
} from '../config/PouchInjectDefinition';
|
||||||
|
|
||||||
|
import InjectConfig from '../decorator/InjectConfig';
|
||||||
|
|
||||||
|
class PouchFactory {
|
||||||
|
private pouchDefinitionMap: Map<Function, PouchDefinition>;
|
||||||
|
private pouchInstanceMap: Map<Function, Map<string | symbol, any>>;
|
||||||
|
|
||||||
|
public constructor() {
|
||||||
|
this.pouchDefinitionMap = new Map();
|
||||||
|
this.pouchInstanceMap = new Map();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getPouch
|
||||||
|
*/
|
||||||
|
public getPouch<T>(type: ClassConstructor<T>, ...args: any[]): T {
|
||||||
|
let qualifier = POUCH_DEFAULT_QUALIFIER;
|
||||||
|
return this.getPouchByQualifier(type, qualifier, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getPouchByQualifier
|
||||||
|
*/
|
||||||
|
public getPouchByQualifier<T>(type: ClassConstructor<T>, qualifier: string | symbol, ...args: any[]): T {
|
||||||
|
let clazz: Function = type.prototype;
|
||||||
|
|
||||||
|
let instance = this._getPouch(clazz, qualifier, args);
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* registerPouch
|
||||||
|
*/
|
||||||
|
public registerPouch(pouch: any, qualifier: string | symbol = POUCH_DEFAULT_QUALIFIER): void {
|
||||||
|
let clazz = pouch.prototype;
|
||||||
|
this._putPouchInstance(clazz, qualifier, pouch);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* registerPouch
|
||||||
|
*/
|
||||||
|
public registerPouchDefinition<T>(type: ClassConstructor<T>, pouchDefinition: PouchDefinition): void {
|
||||||
|
let clazz: Function = type.prototype;
|
||||||
|
if (this.pouchDefinitionMap.has(clazz)) {
|
||||||
|
throw new Error(`Pouch Definition of [${clazz.name}] is already exist.`);
|
||||||
|
}
|
||||||
|
this.pouchDefinitionMap.set(clazz, pouchDefinition);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected getPouchDefinition(clazz: Function): PouchDefinition {
|
||||||
|
let pouchDefinition: PouchDefinition = this.pouchDefinitionMap.get(clazz);
|
||||||
|
if (undefined !== pouchDefinition) {
|
||||||
|
return pouchDefinition;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Reflect.hasOwnMetadata(METADATA.POUCH_DEFINITION, clazz) !== true) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
pouchDefinition = Reflect.getMetadata(METADATA.POUCH_DEFINITION, clazz);
|
||||||
|
this.pouchDefinitionMap.set(clazz, pouchDefinition);
|
||||||
|
|
||||||
|
return pouchDefinition;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected getPouchInjectDefinition(clazz: Function): PouchInjectDefinition {
|
||||||
|
if (Reflect.hasOwnMetadata(METADATA.POUCH_INJECT_DEFINITION, clazz) !== true) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
let pouchInjectDefinition: PouchInjectDefinition = Reflect.getMetadata(METADATA.POUCH_INJECT_DEFINITION, clazz);
|
||||||
|
|
||||||
|
return pouchInjectDefinition;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _getPouch(clazz: Function, qualifier: string | symbol, ...args: any[]): any {
|
||||||
|
let pouchDefinition: PouchDefinition = this.getPouchDefinition(clazz);
|
||||||
|
|
||||||
|
let instance: any;
|
||||||
|
if (null == pouchDefinition) {
|
||||||
|
if (this._hasPouchInstance(clazz, qualifier)) {
|
||||||
|
instance = this._getPouchInstance(clazz, qualifier);
|
||||||
|
} else {
|
||||||
|
instance = this._newInstance(clazz, pouchDefinition, args);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (pouchDefinition.scope === PouchScope.PROTOTYPE) {
|
||||||
|
instance = this._newInstance(clazz, pouchDefinition, args);
|
||||||
|
} else {
|
||||||
|
if (this._hasPouchInstance(clazz, qualifier)) {
|
||||||
|
return this._getPouchInstance(clazz, qualifier);
|
||||||
|
}
|
||||||
|
instance = this._newInstance(clazz, pouchDefinition, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _newInstance(clazz: Function, pouchDefinition: PouchDefinition, ...args: any[]): any {
|
||||||
|
let instance: any;
|
||||||
|
instance = Object.create(clazz);
|
||||||
|
instance.constructor.apply(instance, args);
|
||||||
|
|
||||||
|
this._injectDependency(instance, clazz);
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _injectDependency(target: object, clazz: Function): void {
|
||||||
|
if (clazz.constructor === Object) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let pouchInjectDefinition: PouchInjectDefinition = this.getPouchInjectDefinition(clazz);
|
||||||
|
if (null !== pouchInjectDefinition) {
|
||||||
|
let injectors: Map<string | symbol, InjectItem> = pouchInjectDefinition.injectors;
|
||||||
|
let propertyDescriptor: any;
|
||||||
|
injectors.forEach((injectItem, key, map) => {
|
||||||
|
propertyDescriptor = Object.getOwnPropertyDescriptor(target, key);
|
||||||
|
|
||||||
|
switch (injectItem.decoratorType) {
|
||||||
|
case DecoratorType.PROPERTY:
|
||||||
|
this._injectDependencyProperty(target, clazz, key, propertyDescriptor, injectItem.propertyConfig);
|
||||||
|
break;
|
||||||
|
case DecoratorType.PARAMETER:
|
||||||
|
this._injectDependencyParameter(target, propertyDescriptor, injectItem.parameterConfigMap);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this._injectDependency(target, Object.getPrototypeOf(clazz));
|
||||||
|
}
|
||||||
|
|
||||||
|
private _injectDependencyProperty(target: object, clazz: Function, propertyKey: string | symbol,
|
||||||
|
propertyDescriptor: PropertyDescriptor, injectConfig: InjectConfig): void {
|
||||||
|
let instance = this.getPouch(injectConfig.type, injectConfig.qualifier);
|
||||||
|
if (injectConfig.required && undefined === instance) {
|
||||||
|
throw new Error(`Pouch which used by [${clazz.name}.${propertyKey}] is not exist in the context.`);
|
||||||
|
}
|
||||||
|
target[propertyKey] = instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _injectDependencyParameter(target: object, propertyDescriptor: PropertyDescriptor,
|
||||||
|
parameterConfigs: Map<number, InjectConfig>): void {
|
||||||
|
console.log('');
|
||||||
|
}
|
||||||
|
|
||||||
|
private _hasPouchInstance(clazz: Function, qualifier: string | symbol): boolean {
|
||||||
|
if (!this.pouchInstanceMap.has(clazz) || !this.pouchInstanceMap.get(clazz).has(qualifier)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _getPouchInstance(clazz: Function, qualifier: string | symbol): any {
|
||||||
|
if (!this._hasPouchInstance(clazz, qualifier)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return this.pouchInstanceMap.get(clazz).get(qualifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _putPouchInstance(clazz: Function, qualifier: string | symbol, instance: any): void {
|
||||||
|
let instanceMap: Map<string | symbol, any> = this.pouchInstanceMap.get(clazz);
|
||||||
|
|
||||||
|
if (undefined === instanceMap) {
|
||||||
|
instanceMap = new Map();
|
||||||
|
this.pouchInstanceMap.set(clazz, instanceMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
instanceMap.set(qualifier, instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PouchFactory;
|
|
@ -1,11 +1,11 @@
|
||||||
import Service from '@overflow/commons/api/Service';
|
import Service from '@overflow/commons/api/Service';
|
||||||
import Member from '../model/Member';
|
import Member from '../model/Member';
|
||||||
import injectable from '@overflow/commons/context/decorator/injectable';
|
import Injectable from '@overflow/commons/context/pouches/decorator/Injectable';
|
||||||
import inject from '@overflow/commons/context/decorator/inject';
|
import inject from '@overflow/commons/context/decorator/inject';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@injectable()
|
@Injectable
|
||||||
export class MemberService extends Service {
|
export class MemberService extends Service {
|
||||||
|
|
||||||
public constructor() {
|
public constructor() {
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { call, Effect, fork, put, takeLatest } from 'redux-saga/effects';
|
||||||
|
|
||||||
import { SagaWatcher } from '@overflow/commons/redux-saga';
|
import { SagaWatcher } from '@overflow/commons/redux-saga';
|
||||||
|
|
||||||
import AppContext from '@overflow/commons/context';
|
import AppContext from '@overflow/commons/context/AppContext';
|
||||||
import Action from '@overflow/commons/redux/Action';
|
import Action from '@overflow/commons/redux/Action';
|
||||||
|
|
||||||
import Member from '../../api/model/Member';
|
import Member from '../../api/model/Member';
|
||||||
|
@ -18,7 +18,7 @@ function* signin(action: Action<SigninPayload>): SagaIterator {
|
||||||
// type: types.SENDING_REQUEST,
|
// type: types.SENDING_REQUEST,
|
||||||
// payload: {sendingRequest: true},
|
// payload: {sendingRequest: true},
|
||||||
// });
|
// });
|
||||||
let memberService = AppContext.getService(MemberService);
|
let memberService = AppContext.getInstance().getPouch(MemberService);
|
||||||
|
|
||||||
const member = yield call({context: memberService, fn: memberService.signin}, signinId, signinPw);
|
const member = yield call({context: memberService, fn: memberService.signin}, signinId, signinPw);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user