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 31 module aermicioi.aedi.container.factory; 32 33 import aermicioi.aedi.factory.factory; 34 import aermicioi.aedi.factory.decorating_factory; 35 import aermicioi.aedi.exception; 36 import aermicioi.aedi.storage.locator; 37 38 /** 39 A decorating factory that detects circular reference insantiations. 40 **/ 41 class InProcessObjectFactoryDecorator : ObjectFactory, ObjectFactoryDecorator { 42 43 private { 44 ObjectFactory decorated_; 45 bool inProcess; 46 } 47 48 public { 49 /** 50 * Default constructor for InProcessObjectFactoryDecorator 51 **/ 52 this() { 53 54 } 55 56 /** 57 * Constructor for InProcessObjectFactoryDecorator 58 * 59 * Params: 60 * decorated = factory that is decorated with InProcessObjectFactoryDecorator 61 **/ 62 this(ObjectFactory decorated) { 63 this.decorated = decorated; 64 } 65 66 @property { 67 /** 68 Get the decorated object. 69 70 Returns: 71 T decorated object 72 **/ 73 InProcessObjectFactoryDecorator decorated(ObjectFactory decorated) @safe nothrow { 74 this.decorated_ = decorated; 75 76 return this; 77 } 78 79 /** 80 * Get decorated 81 * 82 * Returns: 83 * ObjectFactory 84 **/ 85 ObjectFactory decorated() @safe nothrow { 86 return this.decorated_; 87 } 88 89 /** 90 * Get type of created object 91 * 92 * Returns: 93 * TypeInfo 94 **/ 95 TypeInfo type() { 96 return this.decorated.type(); 97 } 98 99 /** 100 * Set locator 101 * 102 * Params: 103 * locator = ${param-description} 104 * Throws: 105 * Returns: 106 * typeof(this) 107 **/ 108 InProcessObjectFactoryDecorator locator(Locator!() locator) { 109 this.decorated.locator = locator; 110 111 return this; 112 } 113 } 114 115 /** 116 Factory an object. 117 118 Returns: 119 Object created object. 120 **/ 121 Object factory() { 122 if (inProcess) { 123 throw new InProgressException("ObjectFactory is already instantiating, type: " ~ this.decorated.type.toString()); 124 } 125 126 inProcess = true; 127 scope(exit) inProcess = false; 128 129 Object obj = this.decorated.factory(); 130 131 return obj; 132 } 133 } 134 } 135 136 /** 137 A decorating factory that catches any thrown exceptions by decorated factory, 138 and rethrows them with additional information. 139 140 A decorating factory that catches any thrown exceptions by decorated factory, 141 and chains it in a new exception that adds additonal debugging information 142 such as registered identity, and cause of exception. It is useful for chaining 143 component instantiation pipeline and printing it for debugging purposes. 144 **/ 145 class ExceptionChainingObjectFactory : ObjectFactory, ObjectFactoryDecorator { 146 147 private { 148 ObjectFactory decorated_; 149 string id_; 150 } 151 152 public { 153 /** 154 * Default constructor for ExceptionChainingObjectFactory 155 **/ 156 this() { 157 158 } 159 160 /** 161 * Constructor for ExceptionChainingObjectFactory 162 * 163 * Params: 164 * decorated = factory to be decorated 165 * id = identity of created object, used for exception message. 166 **/ 167 this(ObjectFactory decorated, string id) { 168 this.decorated = decorated; 169 this.id = id; 170 } 171 172 @property { 173 /** 174 * Set id 175 * 176 * Params: 177 * id = identity of created object, used for exception message. 178 * Returns: 179 * typeof(this) 180 **/ 181 ExceptionChainingObjectFactory id(string id) @safe nothrow { 182 this.id_ = id; 183 184 return this; 185 } 186 187 /** 188 * Get id 189 * 190 * Returns: 191 * string 192 **/ 193 string id() @safe nothrow { 194 return this.id_; 195 } 196 197 /** 198 * Set decorated 199 * 200 * Params: 201 * decorated = the factory that is to be decorated 202 * Returns: 203 * typeof(this) 204 **/ 205 ExceptionChainingObjectFactory decorated(ObjectFactory decorated) @safe nothrow { 206 this.decorated_ = decorated; 207 208 return this; 209 } 210 211 /** 212 * Get decorated 213 * 214 * Returns: 215 * ObjectFactory 216 **/ 217 ObjectFactory decorated() @safe nothrow { 218 return this.decorated_; 219 } 220 221 /** 222 * Get type of created object 223 * 224 * Returns: 225 * TypeInfo 226 **/ 227 TypeInfo type() { 228 return this.decorated.type(); 229 } 230 231 /** 232 * Set locator 233 * 234 * Params: 235 * locator = the locator used to locate dependencies for created object. 236 * Returns: 237 * typeof(this) 238 **/ 239 ExceptionChainingObjectFactory locator(Locator!() locator) { 240 this.decorated.locator = locator; 241 242 return this; 243 } 244 } 245 246 /** 247 Factory an object, and catch any exception wrapping it in a library exception to be rethrown further. 248 249 Returns: 250 Object created object. 251 **/ 252 Object factory() { 253 254 try { 255 Object obj = this.decorated.factory(); 256 257 return obj; 258 } catch (NotFoundException e) { 259 260 throw new NotFoundException("A dependency for " ~ this.id ~ " could not be found", e); 261 } catch (InProgressException e) { 262 263 throw new CircularReferenceException("Circular reference detected during construction of " ~ this.id, e); 264 } catch(CircularReferenceException e) { 265 266 throw new CircularReferenceException("Circular reference detected during construction of " ~ this.id, e); 267 } catch (AediException e) { 268 269 throw new AediException("A library exception occurred during construction of " ~ this.id, e); 270 } catch (Exception e) { 271 272 throw new Exception("A general exception occurred during construction of " ~ this.id, e); 273 } 274 } 275 } 276 }