1 /**
2 3 License:
4 Boost Software License - Version 1.0 - August 17th, 2003
5 6 Permission is hereby granted, free of charge, to any person or organization
7 obtaining a copy of the software and accompanying documentation covered by
8 this license (the "Software") to use, reproduce, display, distribute,
9 execute, and transmit the Software, and to prepare derivative works of the
10 Software, and to permit third-parties to whom the Software is furnished to
11 do so, all subject to the following:
12 13 The copyright notices in the Software and this entire statement, including
14 the above license grant, this restriction and the following disclaimer,
15 must be included in all copies of the Software, in whole or in part, and
16 all derivative works of the Software, unless such copies or derivative
17 works are solely in the form of machine-executable object code generated by
18 a source language processor.
19 20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
23 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
24 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
25 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 DEALINGS IN THE SOFTWARE.
27 28 Authors:
29 Alexandru Ermicioi
30 **/31 moduleaermicioi.aedi.container.singleton_container;
32 33 importaermicioi.aedi.container.container;
34 importaermicioi.aedi.util.typecons : Pair, pair;
35 importaermicioi.aedi.storage.object_storage;
36 importaermicioi.aedi.storage.locator_aware;
37 importaermicioi.aedi.storage.locator;
38 importaermicioi.aedi.factory.factory;
39 importaermicioi.aedi.exception;
40 importaermicioi.aedi.container.factory;
41 42 importstd.range.interfaces;
43 44 /**
45 Singleton container.
46 47 It creates objects from ObjectFactory implementations and sets them as long as it lives in application.
48 **/49 @safeclassSingletonContainer : ConfigurableContainer {
50 51 private {
52 53 ObjectStorage!() singletons;
54 ObjectStorage!(ObjectFactory, string) factories;
55 }
56 57 public {
58 59 /**
60 * Default constructor for SingletonContainer
61 **/62 this() {
63 this.singletons = newObjectStorage!();
64 this.factories = newObjectStorage!(ObjectFactory, string);
65 }
66 67 /**
68 * Set object factory
69 *
70 * Params:
71 * object = factory for a object that is to be managed by prototype container.
72 * key = identity of factory
73 * Returns:
74 * typeof(this)
75 **/76 SingletonContainerset(ObjectFactoryobject, stringkey) {
77 this.factories.set(newExceptionChainingObjectFactory(newInProcessObjectFactoryDecorator(object), key), key);
78 79 returnthis;
80 }
81 82 /**
83 * Remove an object factory from container.
84 *
85 * Params:
86 * key = identity of factory to be removed
87 * Returns:
88 * typeof(this)
89 **/90 SingletonContainerremove(stringkey) {
91 92 if (this.singletons.has(key)) {
93 94 autotemporary = this.singletons.get(key);
95 this.factories.get(key).destruct(temporary);
96 }
97 98 this.factories.remove(key);
99 this.singletons.remove(key);
100 101 returnthis;
102 }
103 104 /**
105 * Get object created by a factory identified by key
106 *
107 * Params:
108 * key = identity of factory
109 * Returns:
110 * Object
111 **/112 Objectget(stringkey) {
113 114 if (!this.singletons.has(key)) {
115 if (!this.factories.has(key)) {
116 thrownewNotFoundException("Component ${identity} not found.", key);
117 }
118 119 this.singletons.set(
120 this.factories.get(key).factory(),
121 this.resolve(key),
122 );
123 }
124 125 returnthis.singletons.get(key);
126 }
127 128 /**
129 * Check if an object factory for it exists in container.
130 *
131 * Params:
132 * key = identity of factory
133 * Returns:
134 * bool
135 **/136 boolhas(instringkey) inout {
137 returnthis.factories.has(key);
138 }
139 140 /**
141 Sets up the internal state of container.
142 143 Sets up the internal state of container (Ex, for singleton container it will spawn all objects that locator contains).
144 **/145 SingletonContainerinstantiate() {
146 importstd.algorithm : filter;
147 foreach (pair; this.factories.contents.byKeyValue.filter!((pair) => pair.key !inthis.singletons.contents)) {
148 this.singletons.set(
149 pair.value.factory,
150 pair.key,
151 );
152 }
153 154 returnthis;
155 }
156 157 /**
158 Destruct all managed components.
159 160 Destruct all managed components. The method denotes the end of container lifetime, and therefore destruction of all managed components
161 by it.
162 **/163 Containerterminate() {
164 foreach (pair; this.singletons.contents.byKeyValue) {
165 this.factories.get(pair.key).destruct(pair.value);
166 }
167 168 (() scope @trusted => this.singletons.contents.clear)();
169 170 returnthis;
171 }
172 173 /**
174 Alias a key to an alias_.
175 176 Params:
177 key = the originial identity which is to be aliased.
178 alias_ = the alias of identity.
179 180 Returns:
181 this
182 **/183 SingletonContainerlink(stringkey, stringalias_) {
184 this.singletons.link(key, alias_);
185 this.factories.link(key, alias_);
186 187 returnthis;
188 }
189 190 /**
191 Removes alias.
192 193 Params:
194 alias_ = alias to remove.
195 196 Returns:
197 this
198 199 **/200 SingletonContainerunlink(stringalias_) {
201 this.singletons.unlink(alias_);
202 this.factories.unlink(alias_);
203 204 returnthis;
205 }
206 207 /**
208 Resolve an alias to original identity, if possible.
209 210 Params:
211 key = alias of original identity
212 213 Returns:
214 Type the last identity in alias chain.
215 216 **/217 const(string) resolve(instringkey) const {
218 returnthis.factories.resolve(key);
219 }
220 221 /**
222 Get factory for constructed component identified by identity.
223 224 Get factory for constructed component identified by identity.
225 Params:
226 identity = the identity of component that factory constructs.
227 228 Throws:
229 NotFoundException when factory for it is not found.
230 231 Returns:
232 ObjectFactory the factory for constructed component.
233 **/234 ObjectFactorygetFactory(stringidentity) {
235 returnthis.factories.get(identity);
236 }
237 238 /**
239 Get all factories available in container.
240 241 Get all factories available in container.
242 243 Returns:
244 InputRange!(Pair!(ObjectFactory, string)) a pair of factory => identity.
245 **/246 InputRange!(Pair!(ObjectFactory, string)) getFactories() {
247 importstd.algorithm : map;
248 249 returnthis.factories.contents.byKeyValue.map!(
250 a => Pair!(ObjectFactory, string)(a.value, a.key)
251 ).inputRangeObject;
252 }
253 }
254 }