1 module glued.application.scanlisteners.concrete; 2 3 import std.traits; 4 5 import glued.logging; 6 7 import glued.codescan.scannable; 8 import glued.codescan.listener; 9 10 import glued.application.stereotypes; 11 import glued.application.di.providers; 12 import glued.application.di.annotations; 13 14 import dejector; 15 16 class ConcreteTypesListener: ScanListener!Dejector { 17 mixin CreateLogger; 18 private Logger log; 19 private Dejector injector; 20 21 void init(Dejector injector) 22 { 23 this.injector = injector; 24 log = Logger(injector.get!LogSink); 25 } 26 27 void onScannable(alias scannable)() if (isScannable!scannable) 28 { 29 //todo track what scannable does type and its binding come from (?) - this is tricky and far in the future 30 } 31 32 void onType(A)() //A as in "aggregate" 33 { 34 static if (canHandle!A()) { //todo log about it 35 static if (isMarkedAsStereotype!(A, Component)) { 36 handleComponent!A(); 37 } 38 static if (isMarkedAsStereotype!(A, Configuration)){ 39 handleConfiguration!A(); 40 } 41 } 42 } 43 44 void onBundleModule(string modName)() 45 { 46 } 47 48 void onScannerFreeze() 49 { 50 } 51 52 private static bool canHandle(A)(){ 53 return is(A == class); 54 } 55 56 private void handleComponent(A)(){ 57 log.info.emit("Binding ", fullyQualifiedName!A); 58 injector.bind!(A)(new ComponentClassProvider!A(log.logSink)); 59 log.info.emit("Bound ", fullyQualifiedName!A, " based on its class definition"); 60 } 61 62 private void handleConfiguration(A)(){ 63 log.info.emit("Binding based on configuration ", fullyQualifiedName!A); 64 injector.bind!(A, Singleton)(new ComponentClassProvider!A(log.logSink)); 65 static foreach (name; __traits(allMembers, A)){ 66 static if (__traits(getProtection, __traits(getMember, A, name)) == "public" && 67 isFunction!(__traits(getMember, A, name))) { 68 static foreach (i, overload; __traits(getOverloads, A, name)) { 69 static if (hasAnnotation!(overload, Component)) { 70 static if (!hasAnnotation!(overload, IgnoreResultBinding)){ 71 //todo reuse the same provider for many bindings 72 log.info.emit("Binding type "~fullyQualifiedName!(ReturnType!overload)~" with method ", fullyQualifiedName!A, ".", name, "[#", i, "]"); 73 injector.bind!(ReturnType!overload)(new ConfigurationMethodProvider!(A, name, i)(log.logSink)); 74 log.info.emit("Bound "~fullyQualifiedName!(ReturnType!overload)~" with method ", fullyQualifiedName!A, ".", name, "[#", i, "]"); 75 } //todo else assert exactly one ignore and any Bind 76 77 static foreach (bind; getAnnotations!(overload, Bind)){ 78 log.info.emit("Binding type "~fullyQualifiedName!(Bind.As)~" with method ", fullyQualifiedName!A, ".", name, "[#", i, "]"); 79 injector.bind!(Bind.As)(new ConfigurationMethodProvider!(A, name, i)(log.logSink)); 80 log.info.emit("Bound "~fullyQualifiedName!(Bind.As)~" with method ", fullyQualifiedName!A, ".", name, "[#", i, "]"); 81 } 82 } 83 } 84 } 85 } 86 log.info.emit("Bound chosen members on configuration ", fullyQualifiedName!A); 87 } 88 }