1 /** 2 * This module contains objects for defining and scoping dependency registrations. 3 * 4 * Part of the Poodinis Dependency Injection framework. 5 * 6 * Authors: 7 * Mike Bierlee, m.bierlee@lostmoment.com 8 * Copyright: 2014-2023 Mike Bierlee 9 * License: 10 * This software is licensed under the terms of the MIT license. 11 * The full terms of the license can be found in the LICENSE file. 12 */ 13 14 module poodinis.registration; 15 16 import poodinis.container : DependencyContainer; 17 import poodinis.factory : InstanceFactory, InstanceEventHandler, 18 InstanceCreationException, InstanceFactoryParameters, CreatesSingleton; 19 20 class Registration { 21 private TypeInfo _registeredType = null; 22 private TypeInfo_Class _instanceType = null; 23 private Registration linkedRegistration; 24 private shared(DependencyContainer) _originatingContainer; 25 private InstanceFactory _instanceFactory; 26 private void delegate() _preDestructor; 27 28 public @property registeredType() { 29 return _registeredType; 30 } 31 32 public @property instanceType() { 33 return _instanceType; 34 } 35 36 public @property originatingContainer() { 37 return _originatingContainer; 38 } 39 40 public @property instanceFactory() { 41 return _instanceFactory; 42 } 43 44 public @property preDestructor() { 45 return _preDestructor; 46 } 47 48 protected @property preDestructor(void delegate() preDestructor) { 49 _preDestructor = preDestructor; 50 } 51 52 this(TypeInfo registeredType, TypeInfo_Class instanceType, 53 InstanceFactory instanceFactory, shared(DependencyContainer) originatingContainer) { 54 this._registeredType = registeredType; 55 this._instanceType = instanceType; 56 this._originatingContainer = originatingContainer; 57 this._instanceFactory = instanceFactory; 58 } 59 60 public Object getInstance(InstantiationContext context = new InstantiationContext()) { 61 if (linkedRegistration !is null) { 62 return linkedRegistration.getInstance(context); 63 } 64 65 if (instanceFactory is null) { 66 throw new InstanceCreationException( 67 "No instance factory defined for registration of type " ~ registeredType.toString()); 68 } 69 70 return instanceFactory.getInstance(); 71 } 72 73 public Registration linkTo(Registration registration) { 74 this.linkedRegistration = registration; 75 return this; 76 } 77 78 Registration onConstructed(InstanceEventHandler handler) { 79 if (instanceFactory !is null) 80 instanceFactory.onConstructed(handler); 81 return this; 82 } 83 } 84 85 private InstanceFactoryParameters copyFactoryParameters(Registration registration) { 86 return registration.instanceFactory.factoryParameters; 87 } 88 89 private void setFactoryParameters(Registration registration, InstanceFactoryParameters newParameters) { 90 registration.instanceFactory.factoryParameters = newParameters; 91 } 92 93 /** 94 * Sets the registration's instance factory type the same as the registration's. 95 * 96 * This is not a registration scope. Typically used by Poodinis internally only. 97 */ 98 public Registration initializeFactoryType(Registration registration) { 99 auto params = registration.copyFactoryParameters(); 100 params.instanceType = registration.instanceType; 101 registration.setFactoryParameters(params); 102 return registration; 103 } 104 105 /** 106 * Scopes registrations to return the same instance every time a given registration is resolved. 107 * 108 * Effectively makes the given registration a singleton. 109 */ 110 public Registration singleInstance(Registration registration) { 111 auto params = registration.copyFactoryParameters(); 112 params.createsSingleton = CreatesSingleton.yes; 113 registration.setFactoryParameters(params); 114 return registration; 115 } 116 117 /** 118 * Scopes registrations to return a new instance every time the given registration is resolved. 119 */ 120 public Registration newInstance(Registration registration) { 121 auto params = registration.copyFactoryParameters(); 122 params.createsSingleton = CreatesSingleton.no; 123 params.existingInstance = null; 124 registration.setFactoryParameters(params); 125 return registration; 126 } 127 128 /** 129 * Scopes registrations to return the given instance every time the given registration is resolved. 130 */ 131 public Registration existingInstance(Registration registration, Object instance) { 132 auto params = registration.copyFactoryParameters(); 133 params.createsSingleton = CreatesSingleton.yes; 134 params.existingInstance = instance; 135 registration.setFactoryParameters(params); 136 return registration; 137 } 138 139 /** 140 * Scopes registrations to create new instances using the given initializer delegate. 141 */ 142 public Registration initializedBy(T)(Registration registration, T delegate() initializer) 143 if (is(T == class) || is(T == interface)) { 144 auto params = registration.copyFactoryParameters(); 145 params.createsSingleton = CreatesSingleton.no; 146 params.factoryMethod = () => cast(Object) initializer(); 147 registration.setFactoryParameters(params); 148 return registration; 149 } 150 151 /** 152 * Scopes registrations to create a new instance using the given initializer delegate. On subsequent resolves the same instance is returned. 153 */ 154 public Registration initializedOnceBy(T : Object)(Registration registration, T delegate() initializer) { 155 auto params = registration.copyFactoryParameters(); 156 params.createsSingleton = CreatesSingleton.yes; 157 params.factoryMethod = () => cast(Object) initializer(); 158 registration.setFactoryParameters(params); 159 return registration; 160 } 161 162 public string toConcreteTypeListString(Registration[] registrations) { 163 auto concreteTypeListString = ""; 164 foreach (registration; registrations) { 165 if (concreteTypeListString.length > 0) { 166 concreteTypeListString ~= ", "; 167 } 168 concreteTypeListString ~= registration.instanceType.toString(); 169 } 170 return concreteTypeListString; 171 } 172 173 class InstantiationContext { 174 }