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.wrapping_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 //     enum bool canFactoryGenericFactory = false;
569 // }
570 
571 /**
572 ditto
573 **/
574 template canFactoryGenericFactory(T, Z)
575     if (isAggregateType!T) {
576 
577     static if (hasMember!(T, "factory")) {
578         alias factory = getMember!(T, "factory");
579         
580         alias checker = templateOr!(
581             chain!(
582                 partialPrefixed!(
583                     isDerived,
584                     ReturnType!(factory!Z)
585                 ),
586                 chain!(
587                     GenericFactory,
588                     Wrapper
589                 )
590             ),
591             chain!(
592                 partialPrefixed!(
593                     isDerived,
594                     ReturnType!(factory!Z)
595                 ),
596                 GenericFactory
597             )
598         );
599         enum bool canFactoryGenericFactory = checker!Z;
600     } else {
601         
602         enum bool canFactoryGenericFactory = false;
603     }
604 }
605 
606 /**
607 Checks if a structure has factoryContainer method for InstanceFactory.
608 
609 This static interface is used to find annotations that can provide a InstanceFactory for GenericFactory to be used by it to instantiate
610 the object. The @constructor annotation implements this annotation and therefore it is possible to use it to mark a constructor to be used
611 for object construction. Any annotation implementing this interface can be used by annotation system to configure objects.
612 
613 Examples:
614 --------------------
615     struct SetterAnnotation(Args...) {
616         Tuple!Args args;
617         
618         this(Args args) {
619             this.args = args;
620         }
621         
622         InstanceFactory!T factoryContainer(T, string property)(Locator!() locator) {
623             auto constructor = new ConstructorBasedFactory!(T, Args)(args.expand);
624             constructor.locator = locator;
625             
626             return constructor;
627             
628         }
629     }
630 --------------------
631 Params:
632     T = the structure to be tested for interface compatibility
633     Z = the type of object that T has to instantiate
634     
635 Returns:
636     true in case of structure implementing static interface, false otherwise.
637 **/
638 template canFactoryInstanceFactory(alias T, Z, string property = "__ctor") {
639     alias canFactoryInstanceFactory = canFactoryInstanceFactory!(typeof(T), Z, property);
640 }
641 
642 /**
643 ditto
644 **/
645 template canFactoryInstanceFactory(T, Z, string property = "__ctor") {
646     static if (hasMember!(T, "factoryContainer")) {
647         alias factory = getMember!(T, "factoryContainer");
648         
649         alias checker = templateOr!(
650             chain!(
651                 partialPrefixed!(
652                     isDerived,
653                     ReturnType!(factory!(Z, property))
654                 ),
655                 chain!(
656                     InstanceFactory,
657                     Wrapper
658                 )
659             ),
660             chain!(
661                 partialPrefixed!(
662                     isDerived,
663                     ReturnType!(factory!(Z, property))
664                 ),
665                 InstanceFactory
666             )
667         );
668         enum bool canFactoryInstanceFactory = checker!Z;
669     } else {
670         
671         enum bool canFactoryInstanceFactory = false;
672     }
673 }
674 
675 /**
676 Checks if a structure has factoryConfigurer method for PropertyConfigurer.
677 
678 This static interface is used to find annotations that can provide a PropertyConfigurer for GenericFactory to be used by it to configure
679 the object. The @setter annotation implements this annotation and therefore it is possible to use it to mark a setter to be used
680 for object construction. Any annotation implementing this interface can be used by annotation system to configure objects.
681 
682 Examples:
683 --------------------
684     struct Setter(Args...) {
685         Tuple!Args args;
686         
687         this(Args args) {
688             this.args = args;
689         }
690         
691         PropertyConfigurer!T factoryConfigurer(T, string method)(Locator!() locator) {
692             auto method = new MethodConfigurer!(T, method, Args)(args.expand);
693             method.locator = locator;
694             
695             return method;
696         }
697     }
698 --------------------
699 Params:
700     T = the structure to be tested for interface compatibility
701     Z = the type of object that T has to call T's property method
702     property = the method of Z that T has to call
703 Returns:
704     true in case of structure implementing static interface, false otherwise.
705 **/
706 template canFactoryPropertyConfigurer(alias T, Z, string property = "") {
707     alias canFactoryPropertyConfigurer = canFactoryPropertyConfigurer!(typeof(T), Z, property);
708 }
709 
710 /**
711 ditto
712 **/
713 template canFactoryPropertyConfigurer(T, Z, string property = "") {
714     static if (hasMember!(T, "factoryConfigurer")) {
715         alias factory = getMember!(T, "factoryConfigurer");
716 
717         alias checker = templateOr!(
718             chain!(
719                 partialPrefixed!(
720                     isDerived,
721                     ReturnType!(factory!(Z, property))
722                 ),
723                 chain!(
724                     PropertyConfigurer,
725                     Wrapper
726                 )
727             ),
728             chain!(
729                 partialPrefixed!(
730                     isDerived,
731                     ReturnType!(factory!(Z, property))
732                 ),
733                 PropertyConfigurer
734             )
735         );
736         enum bool canFactoryPropertyConfigurer = checker!Z;
737     } else {
738         
739         enum bool canFactoryPropertyConfigurer = false;
740     }
741 }
742 
743 public auto componentScanImpl(T)(Locator!() locator) {
744     debug(compileTimeDebug) {
745         pragma(msg, "Scanning ", fullyQualifiedName!T);
746     }
747     
748     alias Components = Filter!(
749         partialSuffixed!(
750             canFactoryGenericFactory,
751             T
752         ),
753         allUDAs!T
754     );
755     
756     static if (Components.length > 0) {
757         auto factory = toValue!(Components[0]).factory!T(locator);
758         
759         debug(compileTimeDebug) {
760             pragma(msg, "Found component");
761         }
762         
763         alias constructorUdas = Filter!(
764             partialSuffixed!(
765                 canFactoryInstanceFactory,
766                 T
767             ),
768             allUDAs!T
769         );
770         
771         alias configurerUdas = Filter!(
772             partialSuffixed!(
773                 canFactoryPropertyConfigurer,
774                 T
775             ),
776             allUDAs!T
777         );
778         
779         foreach (configurer; tuple(staticMap!(toValue, configurerUdas))) {
780             debug(compileTimeDebug) {
781                 pragma(msg, "Found configurer ", name!configurer, " on ", name!T, " declaration");
782             }
783             
784             factory.addPropertyConfigurer(configurer.factoryConfigurer!(T, "")(locator));
785         }
786         
787         static if (constructorUdas.length > 0) {
788             debug(compileTimeDebug) {
789                 pragma(msg, "Found constructor right on ", name!T);
790             }
791             
792             factory.setInstanceFactory(toValue!(constructorUdas[0]).factoryContainer!(T, name!T)(locator));
793         } else {
794             alias instantiatorHolders = Filter!(
795                 templateAnd!(
796                     partialSuffixed!(
797                         partialPrefixed!(
798                             isProtection,
799                             T
800                         ),
801                         "public"
802                     ),
803                     eq!"__ctor",
804                     chain!(
805                         isSomeFunction,
806                         partialPrefixed!(
807                             getMember,
808                             T
809                         )
810                     )
811                 ),
812                 __traits(allMembers, T)
813             );
814             
815             foreach (instantiatorHolder; instantiatorHolders) {
816                 foreach (overload; __traits(getOverloads, T, instantiatorHolder)) {
817                     alias udas = Filter!(
818                         partialSuffixed!(
819                             canFactoryInstanceFactory,
820                             T
821                         ),
822                         allUDAs!overload
823                     );
824                     
825                     static if (udas.length > 0) {
826                         debug(compileTimeDebug) {
827                             pragma(msg, "Found custom constructor for ", name!T, " on ", instantiatorHolder, " with arguments ", Parameters!overload);
828                         }
829                         
830                         factory.setInstanceFactory(toValue!(udas[0]).factoryContainer!(T, instantiatorHolder)(locator));
831                     }
832                 }
833             }
834         }
835         
836         alias configurerHolders = Filter!(
837             templateAnd!(
838                 partialSuffixed!(
839                     partialPrefixed!(
840                         isProtection,
841                         T
842                     ),
843                     "public"
844                 ),
845                 templateNot!(eq!"__ctor")
846             ),
847             __traits(allMembers, T)
848         );
849         
850         foreach (member; configurerHolders) {
851             
852             static if (isSomeFunction!(getMember!(T, member))) {
853                 foreach (overload; __traits(getOverloads, T, member)) {
854                     alias udas = Filter!(
855                         partialSuffixed!(
856                             canFactoryPropertyConfigurer,
857                             T,
858                             member
859                         ),
860                         allUDAs!overload
861                     );
862                     
863                     foreach (uda; tuple(staticMap!(toValue, udas))) {
864                         debug(compileTimeDebug) {
865                             pragma(msg, "Found configurer ", name!uda, " for ", name!T, "'s method ", member);
866                         }
867                         
868                         factory.addPropertyConfigurer(uda.factoryConfigurer!(T, member)(locator));
869                     }
870                 }
871             } else static if (isField!(T, member)) {
872                 
873                 alias udas = Filter!(
874                     partialSuffixed!(
875                         canFactoryPropertyConfigurer,
876                         T,
877                         member
878                     ),
879                     allUDAs!(getMember!(T, member))
880                 );
881                 
882                 foreach (uda; tuple(staticMap!(toValue, udas))) {
883                     debug(compileTimeDebug) {
884                         pragma(msg, "Found configurer ", name!uda, " for ", name!T, "'s field ", member);
885                     }
886                     
887                     factory.addPropertyConfigurer(uda.factoryConfigurer!(T, member)(locator));
888                 }
889             }
890         }
891 
892         return factory;
893     } else {
894         debug(compileTimeDebug) {
895             pragma(msg, "Not a component");
896         }
897         
898         return null;
899     }
900 }
901 
902 private template isQualifier(alias T) {
903     alias isQualifier = isQualifier!(typeof(T));
904 }
905 
906 private template isQualifier(T) {
907     enum bool isQualifier = is(T == QualifierAnnotation);
908 }
909 
910 private template isContained(alias T) {
911     alias isContained = isContained!(typeof(T));
912 }
913 
914 private template isContained(T) {
915     enum bool isContained = is(T == ContainedAnnotation);
916 }
917 
918 private template isValue(T) {
919     enum bool isValue = is (typeof(T));
920 }
921 
922 private template isReturnTypeEq(alias symbol, Type)
923     if (isSomeFunction!symbol) {
924     enum bool isReturnTypeEq = is(ReturnType!symbol : Type);
925 }
926 
927 private template isNamedTemplate(alias T, string name) {
928     enum bool isNamedTemplate = isTemplate!T && (identifier!T == name);
929 }
930 
931 private template isEqByFQDN(alias first, alias second) {
932     enum bool isEqByFQDN = fullyQualifiedName!first == fullyQualifiedName!second;
933 }
934 
935 private template instantiatonToTemplate(alias T, alias Template = T) {
936     static if (isTemplateInstantiationOf!(T, Template)) {
937         alias instantiatonToTemplate = Template;
938     } else static if (isTemplate!T) {
939         alias instantiatonToTemplate = T;
940     }
941 }
942 
943 private enum bool isTemplateInstantiationOf(T, alias Template) = is(T : Template!(Z), Z...);
944 private enum bool isTemplateInstantiationOf(alias T, alias Template) = is(typeof(T) : Template!(Z), Z...);
945 
946 private template identifierEq(alias T, string identity) {
947     enum bool identifierEq = identifier!T == identity;
948 }
949 
950 private template allUDAs(alias symbol) {
951     alias allUDAs = AliasSeq!(__traits(getAttributes, symbol));
952 }
953 
954 private template toValue(T) {
955     enum auto toValue = T();
956 }
957 
958 private template toValue(alias T) {
959     alias toValue = T;
960 }
961 
962 private template isType(alias T) {
963     static if (__traits(compiles, () { T z = T.init; })) {
964         
965         enum bool isType = true;
966     } else {
967     
968         enum bool isType = false;
969     }
970 }
971 
972 private template isClass(alias T) {
973     enum bool isClass = is(typeof(T) == class);
974 }
975 
976 private template isClass(T) {
977     enum bool isClass = is(T == class);
978 }
979 
980 private template isStruct(alias T) {
981     enum bool isStruct = is(typeof(T) == struct);
982 }
983 
984 private template isStruct(T) {
985     enum bool isStruct = is(T == struct);
986 }
987 
988 private template getPublicAggregateMembers(alias Symbol) {
989     alias getPublicAggregateMembers = Filter!(
990         templateAnd!(
991             partialSuffixed!(
992                 partialPrefixed!(
993                     isProtection,
994                     Symbol
995                 ),
996                 "public"
997             ),
998             chain!(
999                 hasMembers,
1000                 partialPrefixed!(
1001                     getMember,
1002                     Symbol
1003                 )
1004             )
1005         ),
1006         __traits(allMembers, Symbol)
1007     );
1008 }
1009 
1010 private template getPossibleComponents(alias Symbol) {
1011     alias getPossibleComponents = staticMap!(
1012         partialPrefixed!(
1013             getMember,
1014             Symbol
1015         ),
1016         Filter!(
1017             templateAnd!(
1018                 partialSuffixed!(
1019                     partialPrefixed!(
1020                         isProtection,
1021                         Symbol
1022                     ),
1023                     "public"
1024                 ),
1025                 chain!(
1026                     isType,
1027                     partialPrefixed!(
1028                         getMember,
1029                         Symbol
1030                     )
1031                 ),
1032                 chain!(
1033                     templateOr!(
1034                         isClass,
1035                         isStruct
1036                     ),
1037                     partialPrefixed!(
1038                         getMember,
1039                         Symbol
1040                     )
1041                 )
1042             ),
1043             __traits(allMembers, Symbol)
1044         )
1045     );
1046 }