1 /**
2 Provides annotation based configuration and registration for components.
3 
4 License:
5 	Boost Software License - Version 1.0 - August 17th, 2003
6 
7 	Permission is hereby granted, free of charge, to any person or organization
8 	obtaining a copy of the software and accompanying documentation covered by
9 	this license (the "Software") to use, reproduce, display, distribute,
10 	execute, and transmit the Software, and to prepare derivative works of the
11 	Software, and to permit third-parties to whom the Software is furnished to
12 	do so, all subject to the following:
13 	
14 	The copyright notices in the Software and this entire statement, including
15 	the above license grant, this restriction and the following disclaimer,
16 	must be included in all copies of the Software, in whole or in part, and
17 	all derivative works of the Software, unless such copies or derivative
18 	works are solely in the form of machine-executable object code generated by
19 	a source language processor.
20 	
21 	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 	FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
24 	SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
25 	FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
26 	ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 	DEALINGS IN THE SOFTWARE.
28 
29 Authors:
30 	aermicioi
31 **/
32 module aermicioi.aedi.configurer.annotation.component_scan;
33 
34 import aermicioi.aedi.configurer.annotation.annotation;
35 import aermicioi.aedi.storage.locator;
36 import aermicioi.aedi.storage.storage;
37 import aermicioi.aedi.storage.wrapper;
38 import aermicioi.aedi.container.container;
39 import aermicioi.aedi.factory.factory;
40 import aermicioi.aedi.factory.reference;
41 import aermicioi.aedi.factory.generic_factory;
42 import aermicioi.aedi.factory.proxy_factory;
43 import aermicioi.aedi.exception;
44 import aermicioi.util.traits;
45 import aermicioi.aedi.factory.decorating_factory : WrappingFactory;
46 
47 import std.traits;
48 import std.meta;
49 import std.typecons;
50 import std.conv : to;
51 import std.algorithm;
52 
53 /**
54 Register an object into storage using annotations provided in it.
55 
56 An object will be registered in storage only in case when it is annotated with @component annotation. In case when no @component
57 annotation is found, object is not registered in storage.
58 
59 Params:
60     T = type of object to be registered
61     storage = the storage where to register the object
62     locator = the locator used to find object dependencies
63     id = identity by which object will be stored in storage
64 **/
65 auto componentScan(T)(Storage!(ObjectFactory, string) storage, Locator!() locator, string id) {
66     auto factory = componentScanImpl!T(locator);
67     
68     alias SubComponents = staticMap!(
69         partialPrefixed!(
70             getMember,
71             T
72         ),
73         Filter!(
74             templateAnd!(
75                 partialPrefixed!(
76                     partialSuffixed!(
77                         isProtection,
78                         "public"
79                     ),
80                     T
81                 ),
82                 chain!(
83                     isType,
84                     partialPrefixed!(
85                         getMember,
86                         T
87                     )
88                 ),
89                 chain!(
90                     isClass,
91                     partialPrefixed!(
92                         getMember,
93                         T
94                     )
95                 )
96             ),
97             __traits(allMembers, T)
98         )
99     );
100     
101     static if (SubComponents.length > 0) {
102         storage.componentScan!SubComponents(locator);
103     }
104     
105     if (factory !is null) {
106         storage.set(new WrappingFactory!(Factory!T)(factory), id);
107     }
108     
109     return storage;
110 }
111 
112 /**
113 Register an object into storage by it's type FQN using annotations provided in it.
114 
115 An object will be registered in storage only in case when it is annotated with @component annotation. In case when no @component
116 annotation is found, object is not registered in storage.
117 
118 Params:
119     T = type of object to be registered
120     storage = the storage where to register the object
121 **/
122 auto componentScan(T)(Storage!(ObjectFactory, string) storage, Locator!() locator) {
123         
124     alias qualifiers = Filter!(isQualifier, allUDAs!T);
125 
126     static if (qualifiers.length > 0) {
127         return storage.componentScan!T(locator, qualifiers[0].id);
128     } else {
129         return storage.componentScan!T(locator, name!T);
130     }
131 }
132 
133 /**
134 ditto
135 **/
136 auto componentScan(T)(ConfigurableContainer storage) {
137     
138     return storage.componentScan!T(storage);
139 }
140 
141 /**
142 Register an object into storage by I's interface FQN that it implements using annotations provided in it.
143 
144 An object will be registered in storage only in case when it is annotated with @component annotation. In case when no @component
145 annotation is found, object is not registered in storage.
146 
147 Params:
148     I = the inteface that object implements.
149     T = type of object to be registered
150     storage = the storage where to register the object
151 **/
152 auto componentScan(I, T)(Storage!(ObjectFactory, string) storage, Locator!() locator)
153     if (is(I == interface) && is(T == class) && is(T : I)) {
154     
155     alias qualifiers = Filter!(
156         isQualifier,
157         allUDAs!I
158     );
159     
160     static if (qualifiers.length > 0) {
161         return storage.componentScan!T(locator, qualifier[0].id);
162     } else {
163         return storage.componentScan!T(locator, name!I);
164     }
165 }
166 
167 /**
168 ditto
169 **/
170 auto componentScan(I, T)(ConfigurableContainer storage)
171     if (is(I == interface) && is(T == class) && is(T : I)) {
172     
173     return storage.componentScan!(I, T)(storage);
174 }
175 
176 /**
177 Register a set of objects by it's type, or implemented interface into a storage.
178 
179 When registering an object by it's interface, next to interface it is required to specify the original type of object.
180 Note: An object will be registered in storage only in case when it is annotated with @component annotation. In case when no @component
181 annotation is found, object is not registered in storage.
182 
183 Params:
184     I = the inteface that object implements.
185     T = type of object to be registered
186     storage = the storage where to register the object
187 **/
188 auto componentScan(T, V...)(Storage!(ObjectFactory, string) storage, Locator!() locator) {
189     storage.componentScan!T(locator);
190     
191     return storage.componentScan!V(locator);
192 }
193 
194 /**
195 ditto
196 **/
197 auto componentScan(T, V...)(ConfigurableContainer storage) {
198     
199     return storage.componentScan!(T, V)(storage);
200 }
201     
202 /**
203 ditto
204 **/
205 auto componentScan(I, T, V...)(Storage!(ObjectFactory, string) storage, Locator!() locator)
206     if (is(I == interface) && is(T == class) && is(T : I)) {
207     storage.componentScan!(I, T)(locator);
208 
209     return storage.componentScan!(V)(locator);
210 }
211 
212 /**
213 ditto
214 **/
215 auto componentScan(I, T, V...)(ConfigurableContainer storage)
216     if (is(I == interface) && is(T == class) && is(T : I)) {
217     
218     return storage.componentScan!(I, T, V)(storage);
219 }
220 
221 /**
222 Scan a module and register all public objects that are annotated with @component annotation.
223 
224 Note: An object will be registered in storage only in case when it is annotated with @component annotation. In case when no @component
225 annotation is found, object is not registered in storage.
226 
227 Params:
228     Module = module to scan for components.
229     storage = the storage where to register the object
230     locator = the locator used to fetch registered object's dependencies.
231 **/
232 auto componentScan(alias Module)(Storage!(ObjectFactory, string) storage, Locator!() locator) 
233     if (startsWith(Module.stringof, "module ")) {
234     
235     alias components = staticMap!(
236         partialPrefixed!(
237             getMember,
238             Module
239         ),
240         Filter!(
241             templateAnd!(
242                 partialSuffixed!(
243                     partialPrefixed!(
244                         isProtection,
245                         Module
246                     ),
247                     "public"
248                 ),
249                 chain!(
250                     isType,
251                     partialPrefixed!(
252                         getMember,
253                         Module
254                     )
255                 ),
256                 chain!(
257                     isClass,
258                     partialPrefixed!(
259                         getMember,
260                         Module
261                     )
262                 )
263             ),
264             __traits(allMembers, Module)
265         )
266     );
267     
268     storage.componentScan!components(locator);
269     
270     return storage;
271 }
272 
273 /**
274 ditto
275 **/
276 auto componentScan(alias M)(ConfigurableContainer storage)
277     if (startsWith(M.stringof, "module")) {
278     
279     return storage.componentScan!(M)(storage);
280 }
281 
282 /**
283 Scan a set of modules and register all public objects that are annotated with @component annotation.
284 
285 Due to limitations of D language currently it is impossible to recursively scan all public imports of a module to register all 
286 depencies of a package. Each particular module should be specified in order to register dependencies.
287 Note: An object will be registered in storage only in case when it is annotated with @component annotation. In case when no @component
288 annotation is found, object is not registered in storage.
289 
290 Params:
291     M = current module to scan.
292     V = rest set of modules waiting for scan.
293     storage = the storage where to register the object
294     locator = the locator used to fetch registered object's dependencies.
295 **/
296 auto componentScan(alias M, V...)(Storage!(ObjectFactory, string) storage, Locator!() locator)
297     if (startsWith(M.stringof, "module")) {
298     storage.componentScan!M(locator);
299     return storage.componentScan!V(locator);
300 }
301 
302 /**
303 ditto
304 **/
305 auto componentScan(alias M, V...)(ConfigurableContainer storage)
306     if (startsWith(M.stringof, "module")) {
307     
308     return storage.componentScan!(M, V)(storage);
309 }
310 
311 /**
312 Register an object into a storage contained in storageLocator and identified by @container annotation using annotations provided in it.
313 
314 An object will be registered in storage only in case when it is annotated with @component annotation. In case when no @component
315 annotation is found, object is not registered in storage.
316 
317 Params:
318     T = type of object to be registered
319     storageLocator = the locator from which to fetch storage for object
320     locator = locator used to find dependencies for object
321     id = identity by which object will be stored in storage
322 **/
323 auto componentScan(T, R : Locator!())(R storageLocator, Locator!() locator, string id) 
324     if (!is(R : Storage!(ObjectFactory, string))) {
325     
326     alias containers = Filter!(
327         isContained,
328         allUDAs!T
329     );
330     
331     static if (containers.length > 0) {
332         string storageId = containers[0].id;
333     } else {
334         string storageId = "singleton";
335     }
336     
337     auto storage = storageLocator.locate!(Storage!(ObjectFactory, string))(storageId);
338     
339     if (storage !is null) {
340         
341         storage.componentScan!T(locator, id);
342     } else {
343         
344         throw new NotFoundException("Could not find storage to save factory for object of identity " ~ id);
345     }
346     
347     return storageLocator;
348 }
349 
350 /**
351 ditto
352 **/
353 auto componentScan(T, R : Locator!())(R locator, string id)
354     if (!is(R : Storage!(ObjectFactory, string))) {
355     return locator.componentScan!T(locator, id);
356 }
357 
358 /**
359 ditto
360 **/
361 auto componentScan(T, R : Locator!())(R storageLocator, Locator!() locator)
362     if (!is(R : Storage!(ObjectFactory, string))) {
363     
364     alias qualifiers = Filter!(
365         isQualifier,
366         allUDAs!T
367     );
368     
369     static if (qualifiers.length > 0) {
370         return storageLocator.componentScan!T(locator, qualifiers[0].id);
371     } else {
372         return storageLocator.componentScan!T(locator, name!T);
373     }
374 }
375 
376 /**
377 ditto
378 **/
379 auto componentScan(T, R : Locator!())(R locator)
380     if (!is(R : Storage!(ObjectFactory, string))) {
381     return locator.componentScan!T(locator);
382 }
383 
384 /**
385 ditto
386 **/
387 template componentScan(T, V...)
388     if((V.length > 0)) {
389         
390     /**
391     ditto
392     **/
393     auto componentScan(R : Locator!())(R storageLocator, Locator!() locator) 
394         if (!is(R : Storage!(ObjectFactory, string))) {
395         .componentScan!T(storageLocator, locator);
396         
397         return .componentScan!V(storageLocator, locator);
398     }
399     
400     /**
401     ditto
402     **/
403     auto componentScan(R : Locator!())(R locator) 
404         if (!is(R : Storage!(ObjectFactory, string))) {
405         .componentScan!T(locator, locator);
406         
407         return .componentScan!V(locator, locator);
408     }
409 }
410 
411 /**
412 Register an object into a storage contained in storageLocator and identified by @container annotation using annotations provided in it.
413 
414 An object will be registered in storage only in case when it is annotated with @component annotation. In case when no @component
415 annotation is found, object is not registered in storage.
416 
417 Params:
418     I = interface implemented by object, by which to register it.
419     T = type of object to be registered
420     storageLocator = locator used to find storage for object
421     locator = locator used to find dependencies for object
422 **/
423 auto componentScan(I, T, R : Locator!())(R storageLocator, Locator!() locator)
424     if (is (I == interface) && is (T == class) && is (T : I) && !is(R : Storage!(ObjectFactory, string))) {
425     alias qualifiers = Filter!(
426         isQualifier,
427         allUDAs!I
428     );
429     
430     static if (qualifiers.length > 0) {
431         return storageLocator.componentScan!T(locator, qualifiers[0].id);
432     } else {
433         return storageLocator.componentScan!T(locator, name!I);
434     }
435 }
436 
437 /**
438 ditto
439 **/
440 auto componentScan(I, T, R : Locator!())(R locator)
441     if (is (I == interface) && is (T == class) && is (T : I) && !is(R : Storage!(ObjectFactory, string))) {
442     
443     return locator.componentScan!(I, T)(locator);
444 }
445 
446 /**
447 ditto
448 **/
449 template componentScan(I, T, V...) 
450     if (is (I == interface) && is (T == class) && is (T : I) && (V.length > 0)) {
451         
452     /**
453     ditto
454     **/
455     auto componentScan(R : Locator!())(R storageLocator, Locator!() locator)
456         if (!is(R : Storage!(ObjectFactory, string))) {
457 
458         .componentScan!(I, T)(storageLocator, locator);
459         
460         return .componentScan!(V)(storageLocator, locator);
461     }
462 
463     /**
464     ditto
465     **/
466     auto componentScan(R : Locator!())(R locator)
467         if (!is(R : Storage!(ObjectFactory, string))) {
468         
469         .componentScan!(I, T)(locator);
470         
471         return .componentScan!(V)(locator);
472     }
473 }
474 
475 /**
476 Register module's objects into a storage contained in storageLocator and identified by @container annotation using annotations provided in it.
477 
478 An object will be registered in storage only in case when it is annotated with @component annotation. In case when no @component
479 annotation is found, object is not registered in storage.
480 
481 Params:
482     M = module to scan for instantiable objects.
483     storageLocator = locator used to find storage for objects
484     locator = locator used to find object dependencies
485 **/
486 auto componentScan(alias M, R : Locator!())(R storageLocator, Locator!() locator) 
487     if (M.stringof.startsWith("module ") && !is(R : Storage!(ObjectFactory, string)))  {
488     
489     alias components = getPossibleComponents!M;
490     
491     storageLocator.componentScan!components(locator);
492     
493     return storageLocator;
494 }
495 
496 /**
497 ditto
498 **/
499 auto componentScan(alias M, R : Locator!())(R locator) 
500     if (M.stringof.startsWith("module ") && !is(R : Storage!(ObjectFactory, string)))  {
501     
502     locator.componentScan!M(locator);
503     
504     return locator;
505 }
506 
507 /**
508 ditto
509 **/
510 template componentScan(alias M, V...) 
511     if (M.stringof.startsWith("module ") && (V.length > 0)) {
512         
513     /**
514     ditto
515     **/
516     auto componentScan(R : Locator!())(R locatorStorage, Locator!() locator)
517         if (!is(R : Storage!(ObjectFactory, string))) {
518         
519         .componentScan!M(locatorStorage, locator);
520         return .componentScan!V(locatorStorage, locator);
521     }
522         
523     /**
524     ditto
525     **/
526     auto componentScan(R : Locator!())(R locator)
527         if (!is(R : Storage!(ObjectFactory, string))) {
528         
529         .componentScan!M(locator);
530         return .componentScan!V(locator);
531     }
532 }
533 
534 /**
535 Checks if a structure has factory method for GenericFactory.
536 
537 This static interface is used by annotation system to identify annotations that mark an object as instantiable by container.
538 The @component annotation is such a structure that implements this static interface and therefore it is possible to use it to 
539 mark components instantiable. A "@component" annotation must have a factory method that returns a GenericFactory instance that
540 further will be used to configure an instantiable object. In such a way it is possbile to define other custom annotations that
541 return GenericFactory implementations that add/or behave differrently comparing to default implementation of GenericFactory.
542 
543 Examples:
544 --------------------
545     struct Component {
546         GenericFactory!T factory(T)(Locator!() locator) {
547             return new GenericFactoryImpl!(T)(locator);
548         }
549     }
550 --------------------
551 Params:
552     T = the structure to be tested for interface compatibility
553     Z = the type of object that T has to instantiate
554     
555 Returns:
556     true in case of structure implementing static interface, false otherwise.
557 **/
558 template canFactoryGenericFactory(alias T, Z) 
559     if (!isTemplate!T) {
560     alias canFactoryGenericFactory = canFactoryGenericFactory!(typeof(T), Z);
561 }
562 
563 /**
564 ditto
565 **/
566 template canFactoryGenericFactory(T, Z)
567     if (isAggregateType!T) {
568 
569     static if (hasMember!(T, "factory")) {
570         alias factory = getMember!(T, "factory");
571         
572         alias checker = templateOr!(
573             chain!(
574                 partialPrefixed!(
575                     isDerived,
576                     ReturnType!(factory!Z)
577                 ),
578                 chain!(
579                     GenericFactory,
580                     Wrapper
581                 )
582             ),
583             chain!(
584                 partialPrefixed!(
585                     isDerived,
586                     ReturnType!(factory!Z)
587                 ),
588                 GenericFactory
589             )
590         );
591         enum bool canFactoryGenericFactory = checker!Z;
592     } else {
593         
594         enum bool canFactoryGenericFactory = false;
595     }
596 }
597 
598 /**
599 Checks if a structure has factoryContainer method for InstanceFactory.
600 
601 This static interface is used to find annotations that can provide a InstanceFactory for GenericFactory to be used by it to instantiate
602 the object. The @constructor annotation implements this annotation and therefore it is possible to use it to mark a constructor to be used
603 for object construction. Any annotation implementing this interface can be used by annotation system to configure objects.
604 
605 Examples:
606 --------------------
607     struct SetterAnnotation(Args...) {
608         Tuple!Args args;
609         
610         this(Args args) {
611             this.args = args;
612         }
613         
614         InstanceFactory!T factoryContainer(T, string property)(Locator!() locator) {
615             auto constructor = new ConstructorBasedFactory!(T, Args)(args.expand);
616             constructor.locator = locator;
617             
618             return constructor;
619             
620         }
621     }
622 --------------------
623 Params:
624     T = the structure to be tested for interface compatibility
625     Z = the type of object that T has to instantiate
626     
627 Returns:
628     true in case of structure implementing static interface, false otherwise.
629 **/
630 template canFactoryInstanceFactory(alias T, Z, string property = "__ctor") {
631     alias canFactoryInstanceFactory = canFactoryInstanceFactory!(typeof(T), Z, property);
632 }
633 
634 /**
635 ditto
636 **/
637 template canFactoryInstanceFactory(T, Z, string property = "__ctor") {
638     static if (hasMember!(T, "factoryContainer")) {
639         alias factory = getMember!(T, "factoryContainer");
640         
641         alias checker = templateOr!(
642             chain!(
643                 partialPrefixed!(
644                     isDerived,
645                     ReturnType!(factory!(Z, property))
646                 ),
647                 chain!(
648                     InstanceFactory,
649                     Wrapper
650                 )
651             ),
652             chain!(
653                 partialPrefixed!(
654                     isDerived,
655                     ReturnType!(factory!(Z, property))
656                 ),
657                 InstanceFactory
658             )
659         );
660         enum bool canFactoryInstanceFactory = checker!Z;
661     } else {
662         
663         enum bool canFactoryInstanceFactory = false;
664     }
665 }
666 
667 /**
668 Checks if a structure has factoryConfigurer method for PropertyConfigurer.
669 
670 This static interface is used to find annotations that can provide a PropertyConfigurer for GenericFactory to be used by it to configure
671 the object. The @setter annotation implements this annotation and therefore it is possible to use it to mark a setter to be used
672 for object construction. Any annotation implementing this interface can be used by annotation system to configure objects.
673 
674 Examples:
675 --------------------
676     struct Setter(Args...) {
677         Tuple!Args args;
678         
679         this(Args args) {
680             this.args = args;
681         }
682         
683         PropertyConfigurer!T factoryConfigurer(T, string method)(Locator!() locator) {
684             auto method = new MethodConfigurer!(T, method, Args)(args.expand);
685             method.locator = locator;
686             
687             return method;
688         }
689     }
690 --------------------
691 Params:
692     T = the structure to be tested for interface compatibility
693     Z = the type of object that T has to call T's property method
694     property = the method of Z that T has to call
695 Returns:
696     true in case of structure implementing static interface, false otherwise.
697 **/
698 template canFactoryPropertyConfigurer(alias T, Z, string property = "") {
699     alias canFactoryPropertyConfigurer = canFactoryPropertyConfigurer!(typeof(T), Z, property);
700 }
701 
702 /**
703 ditto
704 **/
705 template canFactoryPropertyConfigurer(T, Z, string property = "") {
706     static if (hasMember!(T, "factoryConfigurer")) {
707         alias factory = getMember!(T, "factoryConfigurer");
708 
709         alias checker = templateOr!(
710             chain!(
711                 partialPrefixed!(
712                     isDerived,
713                     ReturnType!(factory!(Z, property))
714                 ),
715                 chain!(
716                     PropertyConfigurer,
717                     Wrapper
718                 )
719             ),
720             chain!(
721                 partialPrefixed!(
722                     isDerived,
723                     ReturnType!(factory!(Z, property))
724                 ),
725                 PropertyConfigurer
726             )
727         );
728         enum bool canFactoryPropertyConfigurer = checker!Z;
729     } else {
730         
731         enum bool canFactoryPropertyConfigurer = false;
732     }
733 }
734 
735 public auto componentScanImpl(T)(Locator!() locator) {
736     debug {
737         pragma(msg, "Scanning ", fullyQualifiedName!T);
738     }
739     
740     alias Components = Filter!(
741         partialSuffixed!(
742             canFactoryGenericFactory,
743             T
744         ),
745         allUDAs!T
746     );
747     
748     static if (Components.length > 0) {
749         auto factory = toValue!(Components[0]).factory!T(locator);
750         
751         debug {
752             pragma(msg, "Found component");
753         }
754         
755         alias constructorUdas = Filter!(
756             partialSuffixed!(
757                 canFactoryInstanceFactory,
758                 T
759             ),
760             allUDAs!T
761         );
762         
763         alias configurerUdas = Filter!(
764             partialSuffixed!(
765                 canFactoryPropertyConfigurer,
766                 T
767             ),
768             allUDAs!T
769         );
770         
771         foreach (configurer; tuple(staticMap!(toValue, configurerUdas))) {
772             debug {
773                 pragma(msg, "Found configurer ", name!configurer, " on ", name!T, " declaration");
774             }
775             
776             factory.addPropertyConfigurer(configurer.factoryConfigurer!(T, "")(locator));
777         }
778         
779         static if (constructorUdas.length > 0) {
780             debug {
781                 pragma(msg, "Found constructor right on ", name!T);
782             }
783             
784             factory.setInstanceFactory(toValue!(constructorUdas[0]).factoryContainer!(T, name!T)(locator));
785         } else {
786             alias instantiatorHolders = Filter!(
787                 templateAnd!(
788                     partialSuffixed!(
789                         partialPrefixed!(
790                             isProtection,
791                             T
792                         ),
793                         "public"
794                     ),
795                     eq!"__ctor",
796                     chain!(
797                         isSomeFunction,
798                         partialPrefixed!(
799                             getMember,
800                             T
801                         )
802                     )
803                 ),
804                 __traits(allMembers, T)
805             );
806             
807             foreach (instantiatorHolder; instantiatorHolders) {
808                 foreach (overload; __traits(getOverloads, T, instantiatorHolder)) {
809                     alias udas = Filter!(
810                         partialSuffixed!(
811                             canFactoryInstanceFactory,
812                             T
813                         ),
814                         allUDAs!overload
815                     );
816                     
817                     static if (udas.length > 0) {
818                         debug {
819                             pragma(msg, "Found custom constructor for ", name!T, " on ", instantiatorHolder, " with arguments ", Parameters!overload);
820                         }
821                         
822                         factory.setInstanceFactory(toValue!(udas[0]).factoryContainer!(T, instantiatorHolder)(locator));
823                     }
824                 }
825             }
826         }
827         
828         alias configurerHolders = Filter!(
829             templateAnd!(
830                 partialSuffixed!(
831                     partialPrefixed!(
832                         isProtection,
833                         T
834                     ),
835                     "public"
836                 ),
837                 templateNot!(eq!"__ctor")
838             ),
839             __traits(allMembers, T)
840         );
841         
842         foreach (member; configurerHolders) {
843             
844             static if (isSomeFunction!(getMember!(T, member))) {
845                 foreach (overload; __traits(getOverloads, T, member)) {
846                     alias udas = Filter!(
847                         partialSuffixed!(
848                             canFactoryPropertyConfigurer,
849                             T,
850                             member
851                         ),
852                         allUDAs!overload
853                     );
854                     
855                     foreach (uda; tuple(staticMap!(toValue, udas))) {
856                         debug {
857                             pragma(msg, "Found configurer ", name!uda, " for ", name!T, "'s method ", member);
858                         }
859                         
860                         factory.addPropertyConfigurer(uda.factoryConfigurer!(T, member)(locator));
861                     }
862                 }
863             } else static if (isField!(T, member)) {
864                 
865                 alias udas = Filter!(
866                     partialSuffixed!(
867                         canFactoryPropertyConfigurer,
868                         T,
869                         member
870                     ),
871                     allUDAs!(getMember!(T, member))
872                 );
873                 
874                 foreach (uda; tuple(staticMap!(toValue, udas))) {
875                     debug {
876                         pragma(msg, "Found configurer ", name!uda, " for ", name!T, "'s field ", member);
877                     }
878                     
879                     factory.addPropertyConfigurer(uda.factoryConfigurer!(T, member)(locator));
880                 }
881             }
882         }
883 
884         return factory;
885     } else {
886         debug {
887             pragma(msg, "Not a component");
888         }
889         
890         return null;
891     }
892 }
893 
894 private template isQualifier(alias T) {
895     alias isQualifier = isQualifier!(typeof(T));
896 }
897 
898 private template isQualifier(T) {
899     enum bool isQualifier = is(T == QualifierAnnotation);
900 }
901 
902 private template isContained(alias T) {
903     alias isContained = isContained!(typeof(T));
904 }
905 
906 private template isContained(T) {
907     enum bool isContained = is(T == ContainedAnnotation);
908 }
909 
910 private template isValue(T) {
911     enum bool isValue = is (typeof(T));
912 }
913 
914 private template isReturnTypeEq(alias symbol, Type)
915     if (isSomeFunction!symbol) {
916     enum bool isReturnTypeEq = is(ReturnType!symbol : Type);
917 }
918 
919 private template isNamedTemplate(alias T, string name) {
920     enum bool isNamedTemplate = isTemplate!T && (identifier!T == name);
921 }
922 
923 private template isEqByFQDN(alias first, alias second) {
924     enum bool isEqByFQDN = fullyQualifiedName!first == fullyQualifiedName!second;
925 }
926 
927 private template instantiatonToTemplate(alias T, alias Template = T) {
928     static if (isTemplateInstantiationOf!(T, Template)) {
929         alias instantiatonToTemplate = Template;
930     } else static if (isTemplate!T) {
931         alias instantiatonToTemplate = T;
932     }
933 }
934 
935 private enum bool isTemplateInstantiationOf(T, alias Template) = is(T : Template!(Z), Z...);
936 private enum bool isTemplateInstantiationOf(alias T, alias Template) = is(typeof(T) : Template!(Z), Z...);
937 
938 private template identifierEq(alias T, string identity) {
939     enum bool identifierEq = identifier!T == identity;
940 }
941 
942 private template allUDAs(alias symbol) {
943     alias allUDAs = AliasSeq!(__traits(getAttributes, symbol));
944 }
945 
946 private template toValue(T) {
947     enum auto toValue = T();
948 }
949 
950 private template toValue(alias T) {
951     alias toValue = T;
952 }
953 
954 private template isType(alias T) {
955     static if (__traits(compiles, () { T z = T.init; })) {
956         
957         enum bool isType = true;
958     } else {
959     
960         enum bool isType = false;
961     }
962 }
963 
964 private template isClass(alias T) {
965     enum bool isClass = is(typeof(T) == class);
966 }
967 
968 private template isClass(T) {
969     enum bool isClass = is(T == class);
970 }
971 
972 private template isStruct(alias T) {
973     enum bool isStruct = is(typeof(T) == struct);
974 }
975 
976 private template isStruct(T) {
977     enum bool isStruct = is(T == struct);
978 }
979 
980 private template getPublicAggregateMembers(alias Symbol) {
981     alias getPublicAggregateMembers = Filter!(
982         templateAnd!(
983             partialSuffixed!(
984                 partialPrefixed!(
985                     isProtection,
986                     Symbol
987                 ),
988                 "public"
989             ),
990             chain!(
991                 hasMembers,
992                 partialPrefixed!(
993                     getMember,
994                     Symbol
995                 )
996             )
997         ),
998         __traits(allMembers, Symbol)
999     );
1000 }
1001 
1002 private template getPossibleComponents(alias Symbol) {
1003     alias getPossibleComponents = staticMap!(
1004         partialPrefixed!(
1005             getMember,
1006             Symbol
1007         ),
1008         Filter!(
1009             templateAnd!(
1010                 partialSuffixed!(
1011                     partialPrefixed!(
1012                         isProtection,
1013                         Symbol
1014                     ),
1015                     "public"
1016                 ),
1017                 chain!(
1018                     isType,
1019                     partialPrefixed!(
1020                         getMember,
1021                         Symbol
1022                     )
1023                 ),
1024                 chain!(
1025                     templateOr!(
1026                         isClass,
1027                         isStruct
1028                     ),
1029                     partialPrefixed!(
1030                         getMember,
1031                         Symbol
1032                     )
1033                 )
1034             ),
1035             __traits(allMembers, Symbol)
1036         )
1037     );
1038 }