Mercurial > pub > ImplabJs
diff src/implab/di/ServiceDescriptor.js @ 34:27e8e9e38e07 default tip
Слияние
author | nickolay |
---|---|
date | Wed, 05 Jun 2019 20:44:15 +0300 |
parents | 8af8e840dd49 1dc2fd263b90 |
children |
line wrap: on
line diff
--- a/src/implab/di/ServiceDescriptor.js Wed Jun 05 17:44:17 2019 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,289 +0,0 @@ -define( - [ - "../declare", - "../safe", - "./Descriptor", - "./ValueDescriptor" - ], - - function (declare, safe, Descriptor, Value) { - var SINGLETON_ACTIVATION = 1, - CONTAINER_ACTIVATION = 2, - CONTEXT_ACTIVATION = 3, - CALL_ACTIVATION = 4, - HIERARCHY_ACTIVATION = 5; - - var injectMethod = function (target, method, context, args) { - var m = target[method]; - if (!m) - throw new Error("Method '" + method + "' not found"); - - if (args instanceof Array) - m.apply(target, context.parse(args, "." + method)); - else - m.call(target, context.parse(args, "." + method)); - }; - - var makeClenupCallback = function (target, method) { - if (typeof (method) === "string") { - return function () { - target[method](); - }; - } else { - return function () { - method(target); - }; - } - }; - - var cacheId = 0; - - var cls = declare( - Descriptor, { - _instance: null, - _hasInstance: false, - _activationType: CALL_ACTIVATION, - _services: null, - _type: null, - _typeMap: null, - _factory: null, - _params: undefined, - _inject: null, - _cleanup: null, - _cacheId: null, - _owner: null, - - constructor: function (opts) { - safe.argumentNotNull(opts, "opts"); - safe.argumentNotNull(opts.owner, "opts.owner"); - - this._owner = opts.owner; - - if (!(opts.type || opts.factory)) - throw new Error( - "Either a type or a factory must be specified"); - - if (typeof (opts.type) === "string" && !opts.typeMap) - throw new Error( - "The typeMap is required when the type is specified by its name"); - - if (opts.activation) - this._activationType = opts.activation; - if (opts.type) - this._type = opts.type; - if (opts.params) - this._params = opts.params; - if (opts.inject) - this._inject = opts.inject instanceof Array ? opts.inject : [opts.inject]; - if (opts.services) - this._services = opts.services; - if (opts.factory) - this._factory = opts.factory; - if (opts.typeMap) - this._typeMap = opts.typeMap; - if (opts.cleanup) { - if (!(typeof (opts.cleanup) === "string" || opts.cleanup instanceof Function)) - throw new Error( - "The cleanup parameter must be either a function or a function name"); - - this._cleanup = opts.cleanup; - } - - this._cacheId = ++cacheId; - }, - - activate: function (context, name) { - - // if we have a local service records, register them first - - var instance; - - switch (this._activationType) { - case 1: // SINGLETON - // if the value is cached return it - if (this._hasInstance) - return this._instance; - - var tof = this._type || this._factory; - - // create the persistent cache identifier for the type - if (safe.isPrimitive(tof)) - this._cacheId = this._type; - else - this._cacheId = safe.oid(tof); - - // singletons are bound to the root container - var container = context.container.getRootContainer(); - - if (container.has(this._cacheId)) { - instance = container.get(this._cacheId); - } else { - instance = this._create(context, name); - container.store(this._cacheId, instance); - if (this._cleanup) - container.onDispose( - makeClenupCallback(instance, this._cleanup)); - } - - this._hasInstance = true; - return (this._instance = instance); - - case 2: // CONTAINER - //return a cached value - if (this._hasInstance) - return this._instance; - - // create an instance - instance = this._create(context, name); - - // the instance is bound to the container - if (this._cleanup) - this._owner.onDispose( - makeClenupCallback(instance, this._cleanup)); - - // cache and return the instance - this._hasInstance = true; - return (this._instance = instance); - case 3: // CONTEXT - //return a cached value if one exists - if (context.has(this._cacheId)) - return context.get(this._cacheId); - // context context activated instances are controlled by callers - return context.store(this._cacheId, this._create( - context, - name)); - case 4: // CALL - // per-call created instances are controlled by callers - return this._create(context, name); - case 5: // HIERARCHY - // hierarchy activated instances are behave much like container activated - // except they are created and bound to the child container - - // return a cached value - if (context.container.has(this._cacheId)) - return context.container.get(this._cacheId); - - instance = this._create(context, name); - - if (this._cleanup) - context.container.onDispose(makeClenupCallback( - instance, - this._cleanup)); - - return context.container.store(this._cacheId, instance); - default: - throw "Invalid activation type: " + this._activationType; - } - }, - - isInstanceCreated: function () { - return this._hasInstance; - }, - - getInstance: function () { - return this._instance; - }, - - _create: function (context, name) { - context.enter(name, this, Boolean(this._services)); - - if (this._activationType != CALL_ACTIVATION && - context.visit(this._cacheId) > 0) - throw new Error("Recursion detected"); - - if (this._services) { - for (var p in this._services) { - var sv = this._services[p]; - context.register(p, sv instanceof Descriptor ? sv : new Value(sv, false)); - } - } - - var instance; - - if (!this._factory) { - var ctor, type = this._type; - - if (typeof (type) === "string") { - ctor = this._typeMap[type]; - if (!ctor) - throw new Error("Failed to resolve the type '" + - type + "'"); - } else { - ctor = type; - } - - if (this._params === undefined) { - this._factory = function () { - return new ctor(); - }; - } else if (this._params instanceof Array) { - this._factory = function () { - var inst = Object.create(ctor.prototype); - var ret = ctor.apply(inst, arguments); - return typeof (ret) === "object" ? ret : inst; - }; - } else { - this._factory = function (param) { - return new ctor(param); - }; - } - } - - if (this._params === undefined) { - instance = this._factory(); - } else if (this._params instanceof Array) { - instance = this._factory.apply(this, context.parse( - this._params, - ".params")); - } else { - instance = this._factory(context.parse( - this._params, - ".params")); - } - - if (this._inject) { - this._inject.forEach(function (spec) { - for (var m in spec) - injectMethod(instance, m, context, spec[m]); - }); - } - - context.leave(); - - return instance; - }, - - // @constructor {singleton} foo/bar/Baz - // @factory {singleton} - toString: function () { - var parts = []; - - parts.push(this._type ? "@constructor" : "@factory"); - - parts.push(activationNames[this._activationType]); - - if (typeof (this._type) === "string") - parts.push(this._type); - - return parts.join(" "); - } - - }); - - cls.SINGLETON = SINGLETON_ACTIVATION; - cls.CONTAINER = CONTAINER_ACTIVATION; - cls.CONTEXT = CONTEXT_ACTIVATION; - cls.CALL = CALL_ACTIVATION; - cls.HIERARCHY = HIERARCHY_ACTIVATION; - - var activationNames = [ - "", - "{singleton}", - "{container}", - "{context}", - "{call}", - "{hierarchy}" - ]; - - return cls; - }); \ No newline at end of file