Mercurial > pub > ImplabJs
annotate src/implab/di/Container.js @ 14:5fd2a35d65c0
Слияние
| author | cin |
|---|---|
| date | Fri, 08 Sep 2017 13:45:10 +0300 |
| parents | fcc63f34d0a2 |
| children |
| rev | line source |
|---|---|
| 0 | 1 define([ |
| 2 "../declare", | |
| 3 "../safe", | |
| 1 | 4 "../Uuid", |
| 5 "../Deferred", | |
| 0 | 6 "./ActivationContext", |
| 7 "./Descriptor", | |
| 8 "./ValueDescriptor", | |
| 9 "./ReferenceDescriptor", | |
| 10 "./ServiceDescriptor", | |
| 11 "./ActivationError" | |
| 12 ], function ( | |
| 13 declare, | |
| 14 safe, | |
| 1 | 15 Uuid, |
| 0 | 16 Deferred, |
| 17 ActivationContext, | |
| 18 Descriptor, | |
| 19 Value, | |
| 20 Reference, | |
| 21 Service, | |
| 22 ActivationError) { | |
| 23 var Container = declare(null, { | |
| 24 _services: null, | |
| 25 _cache: null, | |
| 26 _cleanup: null, | |
| 27 _root: null, | |
| 28 _parent: null, | |
| 29 | |
| 30 constructor: function (parent) { | |
| 31 this._parent = parent; | |
| 3 | 32 this._services = parent ? Object.create(parent._services) : {}; |
| 0 | 33 this._cache = {}; |
| 34 this._cleanup = []; | |
| 35 this._root = parent ? parent.getRootContainer() : this; | |
| 36 this._services.container = new Value(this, true); | |
| 37 }, | |
| 38 | |
| 39 getRootContainer: function () { | |
| 40 return this._root; | |
| 41 }, | |
| 42 | |
| 43 getParent: function () { | |
| 44 return this._parent; | |
| 45 }, | |
| 46 | |
| 1 | 47 /** |
| 48 * | |
| 49 */ | |
| 0 | 50 getService: function (name, def) { |
| 51 var d = this._services[name]; | |
| 52 if (!d) | |
| 53 if (arguments.length > 1) | |
| 54 return def; | |
| 55 else | |
| 56 throw new Error("Service '" + name + "' isn't found"); | |
| 57 if (d.isInstanceCreated()) | |
| 58 return d.getInstance(); | |
| 59 | |
| 60 var context = new ActivationContext(this, this._services); | |
| 61 | |
| 62 try { | |
| 63 return d.activate(context, name); | |
| 64 } catch (error) { | |
| 65 throw new ActivationError(name, context.getStack(), error); | |
| 66 } | |
| 67 }, | |
| 68 | |
| 69 register: function (name, service) { | |
| 70 if (arguments.length == 1) { | |
| 71 var data = name; | |
| 72 for (name in data) | |
| 73 this.register(name, data[name]); | |
| 74 } else { | |
| 75 if (!(service instanceof Descriptor)) | |
| 76 service = new Value(service, true); | |
| 77 this._services[name] = service; | |
| 78 } | |
| 79 return this; | |
| 80 }, | |
| 81 | |
| 82 onDispose: function (callback) { | |
| 83 if (!(callback instanceof Function)) | |
| 84 throw new Error("The callback must be a function"); | |
| 85 this._cleanup.push(callback); | |
| 86 }, | |
| 87 | |
| 88 dispose: function () { | |
| 89 if (this._cleanup) { | |
| 90 for (var i = 0; i < this._cleanup.length; i++) | |
| 91 this._cleanup[i].call(null); | |
| 92 this._cleanup = null; | |
| 93 } | |
| 94 }, | |
| 95 | |
| 96 /** | |
| 97 * @param{String|Object} config | |
| 98 * The configuration of the contaier. Can be either a string or an object, | |
| 99 * if the configuration is an object it's treated as a collection of | |
| 100 * services which will be registed in the contaier. | |
| 101 * | |
| 102 * @param{Function} opts.contextRequire | |
| 103 * The function which will be used to load a configuration or types for services. | |
| 104 * | |
| 105 */ | |
| 106 configure: function (config, opts) { | |
| 107 var p, me = this, | |
| 108 contextRequire = (opts && opts.contextRequire); | |
| 109 | |
| 110 if (typeof (config) === "string") { | |
| 111 p = new Deferred(); | |
| 112 if (!contextRequire) { | |
|
4
fcc63f34d0a2
fixed container configuration when the config path contains only a package name
cin
parents:
3
diff
changeset
|
113 var shim = [config, new Uuid()].join(config.indexOf("/") != -1 ? "-" : "/"); |
| 0 | 114 define(shim, ["require", config], function (ctx, data) { |
| 115 p.resolve([data, { | |
| 116 contextRequire: ctx | |
| 117 }]); | |
| 118 }); | |
| 119 require([shim]); | |
| 120 } else { | |
| 121 // TODO how to get correct contextRequire for the relative config module? | |
| 122 contextRequire([config], function (data) { | |
| 123 p.resolve([data, { | |
| 124 contextRequire: contextRequire | |
| 125 }]); | |
| 126 }); | |
| 127 } | |
| 128 | |
| 129 return p.then(function (args) { | |
| 130 return me._configure.apply(me, args); | |
| 131 }); | |
| 132 } else { | |
| 133 return me._configure(config, opts); | |
| 134 } | |
| 135 }, | |
| 136 | |
| 137 createChildContainer: function () { | |
| 138 return new Container(this); | |
| 139 }, | |
| 140 | |
| 141 has: function (id) { | |
| 142 return id in this._cache; | |
| 143 }, | |
| 144 | |
| 145 get: function (id) { | |
| 146 return this._cache[id]; | |
| 147 }, | |
| 148 | |
| 149 store: function (id, value) { | |
| 150 return (this._cache[id] = value); | |
| 151 }, | |
| 152 | |
| 153 _configure: function (data, opts) { | |
| 154 var typemap = {}, | |
| 155 d = new Deferred(), | |
| 156 me = this, | |
| 157 p, | |
| 158 contextRequire = (opts && opts.contextRequire) || require; | |
| 159 | |
| 160 var services = {}; | |
| 161 | |
| 162 for (p in data) { | |
| 163 var service = me._parse(data[p], typemap); | |
| 164 if (!(service instanceof Descriptor)) | |
| 165 service = new Value(service, false); | |
| 166 services[p] = service; | |
| 167 } | |
| 168 | |
| 169 me.register(services); | |
| 170 | |
| 171 var names = []; | |
| 172 | |
| 173 for (p in typemap) | |
| 174 names.push(p); | |
| 175 | |
| 176 if (names.length) { | |
| 177 contextRequire(names, function () { | |
| 178 for (var i = 0; i < names.length; i++) | |
| 179 typemap[names[i]] = arguments[i]; | |
| 180 d.resolve(me); | |
| 181 }); | |
| 182 } else { | |
| 183 d.resolve(me); | |
| 184 } | |
| 185 return d.promise; | |
| 186 }, | |
| 187 | |
| 188 _parse: function (data, typemap) { | |
| 189 if (safe.isPrimitive(data) || data instanceof Descriptor) | |
| 190 return data; | |
| 191 if (data.$dependency) | |
| 192 return new Reference( | |
| 193 data.$dependency, | |
| 194 data.lazy, | |
| 195 data.optional, | |
| 196 data["default"], | |
| 197 data.services && this._parseObject(data.services, typemap)); | |
| 198 if (data.$value) { | |
| 199 var raw = !data.parse; | |
| 200 return new Value(raw ? data.$value : this._parse( | |
| 201 data.$value, | |
| 202 typemap), raw); | |
| 203 } | |
| 204 if (data.$type || data.$factory) | |
| 205 return this._parseService(data, typemap); | |
| 206 if (data instanceof Array) | |
| 207 return this._parseArray(data, typemap); | |
| 208 | |
| 209 return this._parseObject(data, typemap); | |
| 210 }, | |
| 211 | |
| 212 _parseService: function (data, typemap) { | |
| 213 var me = this, | |
| 214 opts = { | |
| 215 owner: this | |
| 216 }; | |
| 217 if (data.$type) { | |
| 218 | |
| 219 opts.type = data.$type; | |
| 220 | |
| 221 if (typeof (data.$type) === "string") { | |
| 222 typemap[data.$type] = null; | |
| 223 opts.typeMap = typemap; | |
| 224 } | |
| 225 } | |
| 226 | |
| 227 if (data.$factory) | |
| 228 opts.factory = data.$factory; | |
| 229 | |
| 230 if (data.services) | |
| 231 opts.services = me._parseObject(data.services, typemap); | |
| 232 if (data.inject) | |
| 1 | 233 opts.inject = data.inject instanceof Array ? data.inject.map(function (x) { |
| 234 return me._parseObject(x, typemap); | |
| 235 }) : me._parseObject(data.inject, typemap); | |
| 0 | 236 if (data.params) |
| 237 opts.params = me._parse(data.params, typemap); | |
| 238 | |
| 239 if (data.activation) { | |
| 240 if (typeof (data.activation) === "string") { | |
| 241 switch (data.activation.toLowerCase()) { | |
| 242 case "singleton": | |
| 243 opts.activation = Service.SINGLETON; | |
| 244 break; | |
| 245 case "container": | |
| 246 opts.activation = Service.CONTAINER; | |
| 247 break; | |
| 248 case "hierarchy": | |
| 249 opts.activation = Service.HIERARCHY; | |
| 250 break; | |
| 251 case "context": | |
| 252 opts.activation = Service.CONTEXT; | |
| 253 break; | |
| 254 case "call": | |
| 255 opts.activation = Service.CALL; | |
| 256 break; | |
| 257 default: | |
| 258 throw new Error("Unknown activation type: " + | |
| 259 data.activation); | |
| 260 } | |
| 261 } else { | |
| 262 opts.activation = Number(data.activation); | |
| 263 } | |
| 264 } | |
| 265 | |
| 266 if (data.cleanup) | |
| 267 opts.cleanup = data.cleanup; | |
| 268 | |
| 269 return new Service(opts); | |
| 270 }, | |
| 271 | |
| 272 _parseObject: function (data, typemap) { | |
| 273 if (data.constructor && | |
| 274 data.constructor.prototype !== Object.prototype) | |
| 275 return new Value(data, true); | |
| 276 | |
| 277 var o = {}; | |
| 278 | |
| 279 for (var p in data) | |
| 280 o[p] = this._parse(data[p], typemap); | |
| 281 | |
| 282 return o; | |
| 283 }, | |
| 284 | |
| 285 _parseArray: function (data, typemap) { | |
| 286 if (data.constructor && | |
| 287 data.constructor.prototype !== Array.prototype) | |
| 288 return new Value(data, true); | |
| 289 | |
| 290 var me = this; | |
| 1 | 291 return data.map(function (x) { |
| 0 | 292 return me._parse(x, typemap); |
| 293 }); | |
| 294 } | |
| 295 | |
| 296 }); | |
| 297 | |
| 298 return Container; | |
| 299 }); |
