##// END OF EJS Templates
Don't call .remove() method of objects bound to the container
cin -
r165:c446ccde5f9f v1.4.2 default
parent child
Show More
@@ -1,218 +1,216
1 1 import { IDestroyable, MapOf } from "../interfaces";
2 2 import { argumentNotNull, isDestroyable, argumentNotEmptyString, isRemovable } from "../safe";
3 3 import { ILifetime, ServiceContainer } from "./interfaces";
4 4 import { ActivationContext } from "./ActivationContext";
5 5
6 6 function safeCall(item: () => void) {
7 7 try {
8 8 item();
9 9 } catch {
10 10 // silence!
11 11 }
12 12 }
13 13
14 14 const emptyLifetime: ILifetime = Object.freeze({
15 15 has() {
16 16 return false;
17 17 },
18 18
19 19 initialize() {
20 20
21 21 },
22 22
23 23 get() {
24 24 throw new Error("The specified item isn't registered with this lifetime manager");
25 25 },
26 26
27 27 store() {
28 28 // does nothing
29 29 },
30 30
31 31 toString() {
32 32 return `[object EmptyLifetime]`;
33 33 }
34 34
35 35 });
36 36
37 37 const unknownLifetime: ILifetime = Object.freeze({
38 38 has() {
39 39 return false;
40 40 },
41 41 initialize() {
42 42 throw new Error("Can't call initialize on the unknown lifetime object");
43 43 },
44 44 get() {
45 45 throw new Error("The lifetime object isn't initialized");
46 46 },
47 47 store() {
48 48 throw new Error("Can't store a value in the unknown lifetime object");
49 49 },
50 50 toString() {
51 51 return `[object UnknownLifetime]`;
52 52 }
53 53 });
54 54
55 55 let nextId = 0;
56 56
57 57 const singletons: any = {};
58 58
59 59 export class LifetimeManager implements IDestroyable {
60 60 private _cleanup: (() => void)[] = [];
61 61 private _cache: MapOf<any> = {};
62 62 private _destroyed = false;
63 63
64 64 private _pending: MapOf<boolean> = {};
65 65
66 66 create(): ILifetime {
67 67 const self = this;
68 68 const id = ++nextId;
69 69 return {
70 70 has() {
71 71 return (id in self._cache);
72 72 },
73 73
74 74 get() {
75 75 const t = self._cache[id];
76 76 if (t === undefined)
77 77 throw new Error(`The item with with the key ${id} isn't found`);
78 78 return t;
79 79 },
80 80
81 81 initialize() {
82 82 if (self._pending[id])
83 83 throw Error(`Cyclic reference detected: the item with the key ${id} is already activating.`);
84 84 self._pending[id] = true;
85 85 },
86 86
87 87 store(item: any, cleanup?: (item: any) => void) {
88 88 argumentNotNull(id, "id");
89 89 argumentNotNull(item, "item");
90 90
91 91 if (this.has())
92 92 throw new Error(`The item with with the key ${id} already registered with this lifetime manager`);
93 93 delete self._pending[id];
94 94
95 95 self._cache[id] = item;
96 96
97 97 if (self._destroyed)
98 98 throw new Error("Lifetime manager is destroyed");
99 99 if (cleanup) {
100 100 self._cleanup.push(() => cleanup(item));
101 101 } else if (isDestroyable(item)) {
102 102 self._cleanup.push(() => item.destroy());
103 } else if (isRemovable(item)) {
104 self._cleanup.push(() => item.remove());
105 103 }
106 104 }
107 105 };
108 106 }
109 107
110 108 destroy() {
111 109 if (!this._destroyed) {
112 110 this._destroyed = true;
113 111 this._cleanup.forEach(safeCall);
114 112 this._cleanup.length = 0;
115 113 }
116 114 }
117 115
118 116 static empty(): ILifetime {
119 117 return emptyLifetime;
120 118 }
121 119
122 120 static hierarchyLifetime() {
123 121 let _lifetime = unknownLifetime;
124 122 return {
125 123 initialize(context: ActivationContext<any>) {
126 124 if (_lifetime !== unknownLifetime)
127 125 throw new Error("Cyclic reference activation detected");
128 126
129 127 _lifetime = context.getContainer().getLifetimeManager().create();
130 128 },
131 129 get() {
132 130 return _lifetime.get();
133 131 },
134 132 has() {
135 133 return _lifetime.has();
136 134 },
137 135 store(item: any, cleanup?: (item: any) => void) {
138 136 return _lifetime.store(item, cleanup);
139 137 },
140 138 toString() {
141 139 return `[object HierarchyLifetime, has=${this.has()}]`;
142 140 }
143 141 };
144 142 }
145 143
146 144 static contextLifetime() {
147 145 let _lifetime = unknownLifetime;
148 146 return {
149 147 initialize(context: ActivationContext<any>) {
150 148 if (_lifetime !== unknownLifetime)
151 149 throw new Error("Cyclic reference detected");
152 150 _lifetime = context.createLifetime();
153 151 },
154 152 get() {
155 153 return _lifetime.get();
156 154 },
157 155 has() {
158 156 return _lifetime.has();
159 157 },
160 158 store(item: any) {
161 159 _lifetime.store(item);
162 160 },
163 161 toString() {
164 162 return `[object ContextLifetime, has=${this.has()}]`;
165 163 }
166 164 };
167 165 }
168 166
169 167 static singletonLifetime(typeId: string) {
170 168 argumentNotEmptyString(typeId, "typeId");
171 169 let pending = false;
172 170 return {
173 171 has() {
174 172 return typeId in singletons;
175 173 },
176 174 get() {
177 175 if (!this.has())
178 176 throw new Error(`The instance ${typeId} doesn't exists`);
179 177 return singletons[typeId];
180 178 },
181 179 initialize() {
182 180 if (pending)
183 181 throw new Error("Cyclic reference detected");
184 182 pending = true;
185 183 },
186 184 store(item: any) {
187 185 singletons[typeId] = item;
188 186 pending = false;
189 187 },
190 188 toString() {
191 189 return `[object SingletonLifetime, has=${this.has()}, typeId=${typeId}]`;
192 190 }
193 191 };
194 192 }
195 193
196 194 static containerLifetime(container: ServiceContainer<any>) {
197 195 let _lifetime = unknownLifetime;
198 196 return {
199 197 initialize(context: ActivationContext<any>) {
200 198 if (_lifetime !== unknownLifetime)
201 199 throw new Error("Cyclic reference detected");
202 200 _lifetime = container.getLifetimeManager().create();
203 201 },
204 202 get() {
205 203 return _lifetime.get();
206 204 },
207 205 has() {
208 206 return _lifetime.has();
209 207 },
210 208 store(item: any) {
211 209 _lifetime.store(item);
212 210 },
213 211 toString() {
214 212 return `[object ContainerLifetime, has=${_lifetime.has()}]`
215 213 }
216 214 };
217 215 }
218 216 }
General Comments 0
You need to be logged in to leave comments. Login now