1 /**
2 License:
3 	Boost Software License - Version 1.0 - August 17th, 2003
4 
5 	Permission is hereby granted, free of charge, to any person or organization
6 	obtaining a copy of the software and accompanying documentation covered by
7 	this license (the "Software") to use, reproduce, display, distribute,
8 	execute, and transmit the Software, and to prepare derivative works of the
9 	Software, and to permit third-parties to whom the Software is furnished to
10 	do so, all subject to the following:
11 	
12 	The copyright notices in the Software and this entire statement, including
13 	the above license grant, this restriction and the following disclaimer,
14 	must be included in all copies of the Software, in whole or in part, and
15 	all derivative works of the Software, unless such copies or derivative
16 	works are solely in the form of machine-executable object code generated by
17 	a source language processor.
18 	
19 	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 	FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
22 	SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
23 	FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
24 	ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 	DEALINGS IN THE SOFTWARE.
26 
27 Authors:
28 	aermicioi
29 **/
30 module aermicioi.aedi.configurer.register.context;
31 
32 import aermicioi.aedi.configurer.register.configuration_context_factory;
33 import aermicioi.aedi.factory.factory;
34 import aermicioi.aedi.factory.generic_factory;
35 import aermicioi.aedi.factory.wrapping_factory;
36 import aermicioi.aedi.storage.locator;
37 import aermicioi.aedi.storage.storage;
38 import std.traits;
39 
40 
41 /**
42 A component registration interface for storage.
43 
44 Registration context registers components into storage,
45 and uses a locator as a source of dependencies for components.
46 
47 Params:
48 	ObjectWrappingFactory = factory used to wrap components that are not
49 	derived from Object.
50 **/
51 struct RegistrationContext(
52     alias ObjectWrappingFactory = WrappingFactory
53 ) {
54     public {
55         
56         /**
57         Storage into which to store components;
58         **/
59         Storage!(ObjectFactory, string) storage;
60         
61         /**
62         Locator used for fetching components dependencies;
63         **/
64         Locator!(Object, string) locator;
65         
66         /**
67         Constructor for RegistrationContext
68         
69         Params: 
70             storage = storage where to put registered components
71             locator = locator used to get registered component's dependencies
72         **/
73         this(Storage!(ObjectFactory, string) storage, Locator!(Object, string) locator) {
74             this.storage = storage;
75             this.locator = locator;
76         }
77         
78         /**
79         Register a component of type T by identity, type, or interface it implements.
80         
81         Register a component of type T by identity, type, or interface it implements.
82         
83         Params:
84             Interface = interface of registered component that it implements
85         	T = type of registered component
86         	identity = identity by which component is stored in storage
87         
88         Returns:
89         	GenericFactory!T factory for component for further configuration
90         **/
91         ConfigurationContextFactory!T register(T)(string identity) {
92             ConfigurationContextFactory!T factory = new ConfigurationContextFactory!T();
93             
94             GenericFactoryImpl!T implementation = new GenericFactoryImpl!T(locator);
95             ObjectWrappingFactory!(GenericFactory!T) wrapper = new ObjectWrappingFactory!(GenericFactory!T)(implementation);
96             
97             factory.decorated = implementation;
98             factory.wrapper = wrapper;
99             factory.locator = locator;
100             factory.storage = storage;
101             factory.identity = identity;
102             
103             storage.set(wrapper, identity);
104             return factory;
105         }
106         
107         /**
108         ditto
109         **/
110         ConfigurationContextFactory!T register(T)() {
111             return register!T(fullyQualifiedName!T);
112         }
113         
114         /**
115         ditto
116         **/
117         ConfigurationContextFactory!T register(Interface, T : Interface)()
118             if (!is(T == Interface)) {
119             return register!T(fullyQualifiedName!Interface);
120         }
121         
122         /**
123         Register a component of type T by identity, type, or interface it implements with a default value.
124         
125         Register a component of type T by identity, type, or interface it implements with a default value.
126         
127         Params:
128             Interface = interface of registered component that it implements
129         	T = type of registered component
130         	identity = identity by which component is stored in storage
131         	value = initial value of component;
132         
133         Returns:
134         	GenericFactory!T factory for component for further configuration
135         **/
136         ConfigurationContextFactory!T register(T)(auto ref T value, string identity) {
137             import aermicioi.aedi.configurer.register.factory_configurer : val = value;
138             
139             ConfigurationContextFactory!T factory = register!T(identity);
140             
141             factory.val(value);
142             
143             return factory;
144         }
145         
146         /**
147         ditto
148         **/
149         ConfigurationContextFactory!T register(T)(auto ref T value)
150             if (!is(T == string)) {
151             
152             return register(value, fullyQualifiedName!T);
153         }
154             
155         /**
156         ditto
157         **/
158         ConfigurationContextFactory!T register(Interface, T : Interface)(auto ref T value)
159             if (!is(T == Interface)) {
160             
161             return register(value, fullyQualifiedName!Interface);
162         }
163     }
164 }
165 
166 /**
167 Start registering components using a storage and a locator.
168 
169 Start registering components using a storage and a locator.
170 
171 Params:
172 	storage = store registered components into it.
173 	locator = locator of dependencies for registered components
174 
175 Returns:
176 	RegistrationContext context with registration interface used to register components.
177 **/
178 RegistrationContext!ObjectWrappingFactory configure
179         (alias ObjectWrappingFactory = WrappingFactory)
180         (Storage!(ObjectFactory, string) storage, Locator!(Object, string) locator) {
181     return RegistrationContext!ObjectWrappingFactory(storage, locator);
182 }
183 
184 /**
185 ditto
186 **/
187 RegistrationContext!ObjectWrappingFactory configure
188         (alias ObjectWrappingFactory = WrappingFactory)
189         (Locator!(Object, string) locator, Storage!(ObjectFactory, string) storage) {
190     return RegistrationContext!ObjectWrappingFactory(storage, locator);
191 }
192 
193 /**
194 Start registering components using a container.
195 
196 Start registering components using a container.
197 
198 Params:
199 	container = storage and locator of components.
200 
201 Returns:
202 	RegistrationContext context with registration interface used to register components.
203 **/
204 RegistrationContext!ObjectWrappingFactory configure(T, alias ObjectWrappingFactory = WrappingFactory)(T container)
205     if (is(T : Storage!(ObjectFactory, string)) && is(T : Locator!(Object, string))) {
206     
207     return configure(cast(Locator!(Object, string)) container, container);
208 }
209 
210 /**
211 Start registering components using a storage and a locator.
212 
213 Start registering components using a storage and a locator.
214 
215 Params:
216 	storage = identity of a storage located in locator used by registration context to store components.
217 	locator = locator of dependencies for registered components
218 
219 Returns:
220 	RegistrationContext context with registration interface used to register components.
221 **/
222 RegistrationContext!ObjectWrappingFactory configure
223         (alias ObjectWrappingFactory = WrappingFactory)
224         (Locator!(Object, string) locator, string storage) {
225     return configure!ObjectWrappingFactory(locator, locator.locate!(Storage!(ObjectFactory, string))(storage));
226 }
227 
228 /**
229 Use locator or storage as basis for registering components.
230 
231 Use locator or storage as basis for registering components.
232 
233 Params:
234     registrationContext = context for which to set new configured storage, or used locator
235 	storage = store registered components into it.
236 	locator = locator of dependencies for registered components
237 
238 Returns:
239 	RegistrationContext context with registration interface used to register components.
240 **/
241 Context along
242         (Context : RegistrationContext!T, alias T)
243         (Context registrationContext, Storage!(ObjectFactory, string) storage) {
244     registrationContext.storage = storage;
245     
246     return registrationContext;
247 }
248 
249 /**
250 ditto
251 **/
252 Context along(Context : RegistrationContext!T, alias T)(Context registrationContext, Locator!(Object, string) locator) {
253     registrationContext.locator = locator;
254     
255     return registrationContext;
256 }
257 
258 /**
259 Use locator or storage as basis for registering components.
260 
261 Use locator or storage as basis for registering components.
262 
263 Params:
264     registrationContext = context for which to set new configured storage, or used locator
265 	storage = identity of a storage located in locator that should be used by registrationContext to store components.
266 
267 Returns:
268 	RegistrationContext context with registration interface used to register components.
269 **/
270 Context along(Context : RegistrationContext!T, alias T)(Context registrationContext, string storage) {
271     registrationContext.storage = registrationContext.locator.locate!(Storage!(ObjectFactory, string))(storage);
272     
273     return registrationContext;
274 }
275 
276 /**
277 A registration interface for components already created.
278 
279 Value registration context, provides a nice registration
280 api over Object containers, to store already instantiated
281 components into container.
282 **/
283 struct ValueRegistrationContext {
284     
285     public {
286         /**
287         Storage for already instantiated components.
288         **/
289         Storage!(Object, string) storage;
290     
291         /**
292         Register a component into value container by identity, type or interface.
293         
294         Register a component into value container by identity, type or interface.
295         
296         Params:
297         	value = component to be registered in container
298         	identity = identity of component in container
299         	T = type of component
300         	Interface = interface that T component implements
301         
302         Returns:
303         	ValueRegistrationContext
304         **/
305         ref ValueRegistrationContext register(T)(auto ref T value, string identity) {
306             static if (is(T : Object)) {
307                 storage.set(value, identity);
308             } else {
309                 import aermicioi.aedi.storage.wrapper : WrapperImpl;
310                 
311                 storage.set(new WrapperImpl!T(value), identity);
312             }
313             
314             return this;
315         }
316         
317         /**
318         ditto
319         **/
320         ref ValueRegistrationContext register(T)(auto ref T value) {
321             return register!T(value, fullyQualifiedName!T);
322         }
323         
324         /**
325         ditto
326         **/
327         ref ValueRegistrationContext register(Interface, T : Interface)(auto ref T value) {
328             return register!T(value, fullyQualifiedName!Interface);
329         }
330     }
331 }
332 
333 /**
334 Start registering instantiated components into a value container.
335 
336 Start registering instantiated components into a value container.
337 Description
338 
339 Params:
340 	storage = value container used to store instantiated components
341 
342 Returns:
343 	ValueRegistrationContext context that provides register api, using storage to store registered components.
344 **/
345 ValueRegistrationContext configure(Storage!(Object, string) storage) {
346     return ValueRegistrationContext(storage);
347 }
348 
349 /**
350 Adds registration location information in component's factory for easier debugging.
351 
352 Params:
353     context = original preconfigured registration context to use as basis.
354 **/
355 struct RegistrationInfoTaggedRegistrationContext(T : RegistrationContext!Z, alias Z) {
356     import aermicioi.aedi.factory.decorating_factory : RegistrationAwareDecoratingFactory;
357     
358     public {
359         
360         /**
361         Underlying registration context.
362         **/
363         T context;
364         
365         alias context this;
366         
367         /**
368         Constructor for RegistrationInfoTaggedRegistrationContext
369         
370         Params: 
371             context = underlying context used for registration
372         **/
373         this(T context) {
374             this.context = context;
375         }
376         
377         /**
378         Register a component of type T by identity, type, or interface it implements.
379         
380         Register a component of type T by identity, type, or interface it implements.
381         
382         Params:
383             Interface = interface of registered component that it implements
384         	T = type of registered component
385         	identity = identity by which component is stored in storage
386         
387         Returns:
388         	GenericFactory!T factory for component for further configuration
389         **/
390         ConfigurationContextFactory!T register(T, string file = __FILE__, size_t line = __LINE__)(string identity) {
391             auto factory = this.context.register!T(identity);
392             
393             this.inject(factory, file, line);
394             return factory;
395         }
396         
397         /**
398         ditto
399         **/
400         ConfigurationContextFactory!T register(T, string file = __FILE__, size_t line = __LINE__)() {
401             auto factory = this.context.register!T();
402             
403             this.inject(factory, file, line);
404             return factory;
405         }
406         
407         /**
408         ditto
409         **/
410         ConfigurationContextFactory!T register
411                 (Interface, T : Interface, string file = __FILE__, size_t line = __LINE__)()
412             if (!is(T == Interface)) {
413             auto factory = this.context.register!(Interface, T)();
414             
415             this.inject(factory, file, line);
416             return factory;
417         }
418         
419         /**
420         Register a component of type T by identity, type, or interface it implements with a default value.
421         
422         Register a component of type T by identity, type, or interface it implements with a default value.
423         
424         Params:
425             Interface = interface of registered component that it implements
426         	T = type of registered component
427         	identity = identity by which component is stored in storage
428         	value = initial value of component;
429         
430         Returns:
431         	GenericFactory!T factory for component for further configuration
432         **/
433         ConfigurationContextFactory!T register
434                 (T, string file = __FILE__, size_t line = __LINE__)
435                 (auto ref T value, string identity) {
436             auto factory = this.context.register!T(value, identity);
437             
438             this.inject(factory, file, line);
439             return factory;
440         }
441         
442         /**
443         ditto
444         **/
445         ConfigurationContextFactory!T register
446                 (T, string file = __FILE__, size_t line = __LINE__)
447                 (auto ref T value)
448             if (!is(T == string)) {
449             auto factory = this.context.register!T(value);
450             
451             this.inject(factory, file, line);
452             return factory;
453         }
454             
455         /**
456         ditto
457         **/
458         ConfigurationContextFactory!T register
459                 (Interface, T : Interface, string file = __FILE__, size_t line = __LINE__)
460                 (auto ref T value)
461             if (!is(T == Interface)) {
462             auto factory = this.context.register!(Interface, T)(value);
463             
464             this.inject(factory, file, line);
465             return factory;
466         }
467     }
468     
469     private {
470         void inject(T)(ConfigurationContextFactory!T factory, string file, size_t line) {
471             RegistrationAwareDecoratingFactory!Object wrapper = new RegistrationAwareDecoratingFactory!Object();
472             wrapper.file = file;
473             wrapper.line = line;
474             
475             wrapper.decorated = factory.wrapper;
476             factory.wrapper = wrapper;
477             
478             factory.storage.set(factory.wrapper, factory.identity);
479         }
480     }
481 }
482 
483 /**
484 ditto
485 **/
486 auto withRegistrationInfo(T : RegistrationContext!Z, alias Z)(auto ref T context) {
487     return RegistrationInfoTaggedRegistrationContext!T(context);
488 }