You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
85 lines
2.8 KiB
85 lines
2.8 KiB
import {AbstractFactory} from './AbstractFactory'
|
|
import {Inject, Injectable} from '../decorator/injection'
|
|
import {Logging} from '../../service/Logging'
|
|
import {Config} from '../../service/Config'
|
|
import {
|
|
DEPENDENCY_KEYS_METADATA_KEY,
|
|
DependencyRequirement,
|
|
Instantiable,
|
|
isInstantiable,
|
|
PropertyDependency,
|
|
} from '../types'
|
|
import {Collection, ErrorWithContext, Maybe} from '../../util'
|
|
import 'reflect-metadata'
|
|
|
|
@Injectable()
|
|
export abstract class ConfiguredSingletonFactory<T> extends AbstractFactory<T> {
|
|
protected static loggedDefaultImplementationWarningOnce = false
|
|
|
|
@Inject()
|
|
protected readonly logging!: Logging
|
|
|
|
@Inject()
|
|
protected readonly config!: Config
|
|
|
|
constructor() {
|
|
super({})
|
|
}
|
|
|
|
protected abstract getConfigKey(): string
|
|
|
|
protected abstract getDefaultImplementation(): Instantiable<T>
|
|
|
|
protected abstract getAbstractImplementation(): any
|
|
|
|
protected getDefaultImplementationWarning(): Maybe<string> {
|
|
return undefined
|
|
}
|
|
|
|
produce(dependencies: any[], parameters: any[]): T {
|
|
return new (this.getImplementation())(...dependencies, ...parameters)
|
|
}
|
|
|
|
match(something: unknown): boolean {
|
|
return something === this.getAbstractImplementation()
|
|
}
|
|
|
|
getDependencyKeys(): Collection<DependencyRequirement> {
|
|
const meta = Reflect.getMetadata(DEPENDENCY_KEYS_METADATA_KEY, this.getImplementation())
|
|
if ( meta ) {
|
|
return meta
|
|
}
|
|
|
|
return new Collection<DependencyRequirement>()
|
|
}
|
|
|
|
getInjectedProperties(): Collection<PropertyDependency> {
|
|
return this.getInjectedPropertiesForPrototypeChain(this.getImplementation())
|
|
}
|
|
|
|
protected getImplementation(): Instantiable<T> {
|
|
const ctor = this.constructor as typeof ConfiguredSingletonFactory
|
|
const ImplementationClass = this.config.get(this.getConfigKey(), this.getDefaultImplementation())
|
|
if ( ImplementationClass === this.getDefaultImplementation() ) {
|
|
const warning = this.getDefaultImplementationWarning()
|
|
if ( warning && !ctor.loggedDefaultImplementationWarningOnce ) {
|
|
this.logging.warn(warning)
|
|
ctor.loggedDefaultImplementationWarningOnce = true
|
|
}
|
|
}
|
|
|
|
if (
|
|
!isInstantiable(ImplementationClass)
|
|
|| !(ImplementationClass.prototype instanceof this.getAbstractImplementation())
|
|
) {
|
|
throw new ErrorWithContext('Configured service clas does not properly extend from implementation base class.', {
|
|
configKey: this.getConfigKey(),
|
|
class: `${ImplementationClass}`,
|
|
mustExtendBase: `${this.getAbstractImplementation()}`,
|
|
})
|
|
}
|
|
|
|
return ImplementationClass as Instantiable<T>
|
|
}
|
|
}
|