1 /** 2 Contains factories that are used for decorational purposes like tagging with additional 3 information, or wrapping result of a factory in some container. 4 5 License: 6 Boost Software License - Version 1.0 - August 17th, 2003 7 8 Permission is hereby granted, free of charge, to any person or organization 9 obtaining a copy of the software and accompanying documentation covered by 10 this license (the "Software") to use, reproduce, display, distribute, 11 execute, and transmit the Software, and to prepare derivative works of the 12 Software, and to permit third-parties to whom the Software is furnished to 13 do so, all subject to the following: 14 15 The copyright notices in the Software and this entire statement, including 16 the above license grant, this restriction and the following disclaimer, 17 must be included in all copies of the Software, in whole or in part, and 18 all derivative works of the Software, unless such copies or derivative 19 works are solely in the form of machine-executable object code generated by 20 a source language processor. 21 22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 25 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 26 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 27 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 28 DEALINGS IN THE SOFTWARE. 29 30 Authors: 31 aermicioi 32 **/ 33 module aermicioi.aedi.factory.decorating_factory; 34 35 import aermicioi.aedi.factory.factory; 36 import aermicioi.aedi.storage.allocator_aware : AllocatorAwareMixin, AllocatorAwareDecoratorMixin; 37 import aermicioi.aedi.storage.locator; 38 import aermicioi.aedi.factory.generic_factory; 39 import aermicioi.aedi.storage.decorator; 40 import aermicioi.aedi.storage.locator_aware; 41 import aermicioi.aedi.exception.invalid_cast_exception; 42 import aermicioi.aedi.exception.di_exception; 43 import aermicioi.aedi.util.typecons : Subscribable, Optional, optional; 44 45 alias ObjectFactoryDecorator = Decorator!ObjectFactory; 46 47 /** 48 A base class for generic factory decorators that channels calls 49 to decorated generic factory. 50 **/ 51 @safe abstract class DecoratableGenericFactory(T) : GenericFactory!T, MutableDecorator!(GenericFactory!T) { 52 53 mixin AllocatorAwareDecoratorMixin!(typeof(this)); 54 mixin DestructDecoratorMixin!(typeof(this)); 55 mixin LocatorAwareDecoratorMixin!(typeof(this)); 56 mixin MutableDecoratorMixin!(GenericFactory!T); 57 mixin InstanceFactoryAwareDecoratorMixin!T; 58 mixin InstanceDestructorAwareDecoratorMixin!T; 59 mixin PropertyConfigurersAwareDecoratorMixin!T; 60 61 public { 62 /** 63 Instantiates something of type T. 64 65 Returns: 66 T instantiated component of type T. 67 **/ 68 T factory() @safe { 69 return this.decorated.factory(); 70 } 71 72 /** 73 Get the type info of T that is created. 74 75 Returns: 76 TypeInfo object of created object. 77 **/ 78 TypeInfo type() @safe nothrow const { 79 return this.decorated.type(); 80 } 81 } 82 } 83 84 /** 85 An object that can be tagged with some information. 86 **/ 87 @safe interface Taggable(T) { 88 import std.range.interfaces : InputRange; 89 public { 90 91 /** 92 Tag object with some information 93 94 Params: 95 tag = information that object should be tagged with. 96 97 Returns: 98 this 99 **/ 100 Taggable!T tag(T tag); 101 102 /** 103 Remove tagged information from object. 104 105 Params: 106 tag = tagged information that should be removed 107 108 Returns: 109 this 110 **/ 111 Taggable!T untag(T tag); 112 113 /** 114 Get all tagged information from this object. 115 116 Returns: 117 T[] a list of tags. 118 **/ 119 T[] tags(); 120 } 121 } 122 123 /** 124 Decorates a factory with tagging functionality. 125 **/ 126 @safe class TaggableFactoryDecorator(T, Z) : Factory!T, Taggable!Z, Decorator!(Factory!T) { 127 128 mixin AllocatorAwareDecoratorMixin!(typeof(this)); 129 mixin DestructDecoratorMixin!(typeof(this)); 130 131 private { 132 Z[] tags_; 133 } 134 135 public { 136 @property { 137 138 mixin MutableDecoratorMixin!(Factory!T); 139 140 /** 141 Set tags 142 143 Params: 144 tags = set all tags for this factory 145 Returns: 146 typeof(this) 147 **/ 148 TaggableFactoryDecorator tags(Z[] tags) @safe nothrow { 149 this.tags_ = tags; 150 151 return this; 152 } 153 154 /** 155 Get all tagged information from this object. 156 157 Returns: 158 T[] a list of tags. 159 **/ 160 Z[] tags() @safe nothrow { 161 return this.tags_; 162 } 163 164 /** 165 Set locator 166 167 Params: 168 locator = locator used to search for created object dependencies 169 Returns: 170 typeof(this) 171 **/ 172 TaggableFactoryDecorator locator(Locator!() locator) { 173 this.decorated.locator = locator; 174 175 return this; 176 } 177 178 /** 179 Get the type info of T that is created. 180 181 Returns: 182 TypeInfo object of created object. 183 **/ 184 TypeInfo type() @safe nothrow const { 185 return this.decorated.type; 186 } 187 } 188 189 /** 190 Tag object with some information 191 192 Params: 193 tag = information that object should be tagged with. 194 195 Returns: 196 this 197 **/ 198 TaggableFactoryDecorator tag(Z tag) { 199 this.tags_ ~= tag; 200 201 return this; 202 } 203 204 /** 205 Remove tagged information from object. 206 207 Params: 208 tag = tagged information that should be removed 209 210 Returns: 211 this 212 **/ 213 TaggableFactoryDecorator untag(Z tag) { 214 import std.algorithm : filter; 215 import std.array : array; 216 217 this.tags_ = this.tags_.filter!(t => t != tag).array; 218 219 return this; 220 } 221 222 /** 223 Instantiates something of type T. 224 225 Returns: 226 T instantiated component of type T. 227 **/ 228 T factory() @safe { 229 return this.decorated.factory; 230 } 231 } 232 } 233 234 /** 235 Interface for object that can provide some location in 236 code/file that is associated with some kind of registration event 237 **/ 238 @safe interface RegistrationLocation { 239 public { 240 @property { 241 242 /** 243 Get file in which registration occurred. 244 245 Returns: 246 string file in which a registration occured 247 **/ 248 string file() @safe nothrow; 249 250 /** 251 Get line in file on which registration occurred. 252 253 Returns: 254 size_t line in file on which registration occurred. 255 **/ 256 size_t line() @safe nothrow; 257 } 258 } 259 } 260 261 /** 262 A decorating factory, that adds component registration information 263 when decorated factory threws some kind of exception. 264 **/ 265 @safe class RegistrationAwareDecoratingFactory(T) : Factory!T, MutableDecorator!(Factory!T), RegistrationLocation { 266 267 mixin AllocatorAwareDecoratorMixin!(typeof(this)); 268 269 private { 270 271 string file_; 272 size_t line_; 273 } 274 275 public { 276 277 @property { 278 279 /** 280 Set file in which registration occurred. 281 282 Params: 283 file = file in which a registration occured 284 285 Returns: 286 this 287 **/ 288 RegistrationAwareDecoratingFactory!T file(string file) @safe nothrow { 289 this.file_ = file; 290 291 return this; 292 } 293 294 /** 295 Get file in which registration occurred. 296 297 Returns: 298 string file in which a registration occured 299 **/ 300 string file() @safe nothrow { 301 return this.file_; 302 } 303 304 /** 305 Set line in file on which registration occurred. 306 307 Params: 308 line = line in file on which registration occurred. 309 310 Returns: 311 this 312 **/ 313 RegistrationAwareDecoratingFactory!T line(size_t line) @safe nothrow { 314 this.line_ = line; 315 316 return this; 317 } 318 319 /** 320 Get line in file on which registration occurred. 321 322 Returns: 323 size_t line in file on which registration occurred. 324 **/ 325 size_t line() @safe nothrow { 326 return this.line_; 327 } 328 329 mixin MutableDecoratorMixin!(Factory!T); 330 331 /** 332 Get the type info of T that is created. 333 334 Returns: 335 TypeInfo object of created object. 336 **/ 337 TypeInfo type() @safe nothrow const { 338 return this.decorated.type; 339 } 340 341 /** 342 Set a locator for depedencies. 343 344 Params: 345 locator = the locator that is set to oject. 346 347 Returns: 348 this 349 **/ 350 RegistrationAwareDecoratingFactory!T locator(Locator!() locator) { 351 this.decorated.locator = locator; 352 353 return this; 354 } 355 } 356 357 /** 358 Instantiates component of type T. 359 360 Instantiates component of type T. In case of some thrown exception, 361 it will chain any thrown exception with an exception that has information 362 about location where component was registered. 363 364 Throws: 365 AediException when another exception occurred during construction 366 367 Returns: 368 T instantiated component of type T. 369 **/ 370 T factory() @safe { 371 372 try { 373 return this.decorated.factory; 374 } catch (Exception e) { 375 import std.conv : to, text; 376 throw new AediException( 377 text( 378 "An error occured during instantiation of component registered in file: ", 379 this.file, 380 ":", 381 this.line 382 ), 383 null, 384 this.file, 385 this.line, 386 e 387 ); 388 } 389 } 390 391 /** 392 Destructs a component of type T. 393 394 Params: 395 component = component that is to be destroyed. 396 **/ 397 void destruct(ref T component) @safe { 398 399 try { 400 401 this.decorated.destruct(component); 402 } catch (Exception e) { 403 import std.conv : to, text; 404 405 throw new AediException( 406 text( 407 "An error occured during destruction of component registered in file: ", 408 this.file, 409 ":", 410 this.line 411 ), 412 null, 413 this.file, 414 this.line, 415 e 416 ); 417 } 418 } 419 } 420 }