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.locator; 37 import aermicioi.aedi.factory.generic_factory; 38 import aermicioi.aedi.storage.decorator; 39 import aermicioi.aedi.exception.di_exception; 40 41 alias ObjectFactoryDecorator = Decorator!ObjectFactory; 42 43 /** 44 A base class for generic factory decorators that channels calls 45 to decorated generic factory. 46 **/ 47 abstract class DecoratableGenericFactory(T) : GenericFactory!T, MutableDecorator!(GenericFactory!T) { 48 49 private { 50 Locator!() locator_; 51 GenericFactory!T decorated_; 52 } 53 54 public { 55 @property { 56 57 /** 58 Set locator 59 60 Params: 61 locator = locator used to search for created object dependencies 62 Returns: 63 typeof(this) 64 **/ 65 DecoratableGenericFactory!T locator(Locator!() locator) @safe nothrow { 66 this.locator_ = locator; 67 68 return this; 69 } 70 71 /** 72 Get locator 73 74 Returns: 75 Locator!() 76 **/ 77 Locator!() locator() { 78 return this.locator_; 79 } 80 81 /** 82 Set the decorated object for decorator. 83 84 Params: 85 decorated = decorated data 86 87 Returns: 88 this 89 **/ 90 DecoratableGenericFactory!T decorated(GenericFactory!T decorated) @safe nothrow { 91 this.decorated_ = decorated; 92 93 return this; 94 } 95 96 /** 97 Get the decorated object. 98 99 Returns: 100 GenericFactory!T decorated object 101 **/ 102 GenericFactory!T decorated() @safe nothrow { 103 return this.decorated_; 104 } 105 106 /** 107 Sets the constructor of new object. 108 109 Params: 110 factory = a factory of objects of type T. 111 112 Returns: 113 The GenericFactoryInstance 114 **/ 115 GenericFactory!T setInstanceFactory(InstanceFactory!T factory) { 116 this.decorated.setInstanceFactory(factory); 117 118 return this; 119 } 120 } 121 122 /** 123 Instantiates something of type T. 124 125 Returns: 126 T instantiated data of type T. 127 **/ 128 T factory() { 129 return this.decorated.factory(); 130 } 131 132 /** 133 Get the type info of T that is created. 134 135 Returns: 136 TypeInfo object of created object. 137 **/ 138 TypeInfo type() { 139 return this.decorated.type(); 140 } 141 142 /** 143 Adds an configurer to the GenericFactory. 144 145 Params: 146 configurer = a configurer that will be invoked after factory of an object. 147 148 Returns: 149 The GenericFactoryInstance 150 **/ 151 GenericFactory!T addPropertyConfigurer(PropertyConfigurer!T configurer) { 152 this.decorated.addPropertyConfigurer(configurer); 153 154 return this; 155 } 156 } 157 } 158 159 /** 160 An object that can be tagged with some information. 161 **/ 162 interface Taggable(T) { 163 import std.range.interfaces : InputRange; 164 public { 165 166 /** 167 Tag object with some information 168 169 Params: 170 tag = information that object should be tagged with. 171 172 Returns: 173 this 174 **/ 175 Taggable!T tag(T tag); 176 177 /** 178 Remove tagged information from object. 179 180 Params: 181 tag = tagged information that should be removed 182 183 Returns: 184 this 185 **/ 186 Taggable!T untag(T tag); 187 188 /** 189 Get all tagged information from this object. 190 191 Returns: 192 T[] a list of tags. 193 **/ 194 T[] tags(); 195 } 196 } 197 198 /** 199 Decorates a factory with tagging functionality. 200 **/ 201 class TaggableFactoryDecorator(T, Z) : Factory!T, Taggable!Z, Decorator!(Factory!T) { 202 203 private { 204 Factory!T decorated_; 205 206 Z[] tags_; 207 } 208 209 public { 210 @property { 211 212 /** 213 Set the decorated object for decorator. 214 215 Params: 216 decorated = decorated data 217 218 Returns: 219 this 220 **/ 221 TaggableFactoryDecorator!(T, Z) decorated(Factory!T decorated) @safe nothrow { 222 this.decorated_ = decorated; 223 224 return this; 225 } 226 227 /** 228 Get the decorated object. 229 230 Returns: 231 GenericFactory!T decorated object 232 **/ 233 Factory!T decorated() @safe nothrow { 234 return this.decorated_; 235 } 236 237 /** 238 Set tags 239 240 Params: 241 tags = set all tags for this factory 242 Returns: 243 typeof(this) 244 **/ 245 TaggableFactoryDecorator tags(Z[] tags) @safe nothrow { 246 this.tags_ = tags; 247 248 return this; 249 } 250 251 /** 252 Get all tagged information from this object. 253 254 Returns: 255 T[] a list of tags. 256 **/ 257 Z[] tags() @safe nothrow { 258 return this.tags_; 259 } 260 261 /** 262 Set locator 263 264 Params: 265 locator = locator used to search for created object dependencies 266 Returns: 267 typeof(this) 268 **/ 269 TaggableFactoryDecorator locator(Locator!() locator) { 270 this.decorated.locator = locator; 271 272 return this; 273 } 274 275 /** 276 Get the type info of T that is created. 277 278 Returns: 279 TypeInfo object of created object. 280 **/ 281 TypeInfo type() { 282 return this.decorated.type; 283 } 284 } 285 286 /** 287 Tag object with some information 288 289 Params: 290 tag = information that object should be tagged with. 291 292 Returns: 293 this 294 **/ 295 TaggableFactoryDecorator tag(Z tag) { 296 this.tags_ ~= tag; 297 298 return this; 299 } 300 301 /** 302 Remove tagged information from object. 303 304 Params: 305 tag = tagged information that should be removed 306 307 Returns: 308 this 309 **/ 310 TaggableFactoryDecorator untag(Z tag) { 311 import std.algorithm : filter; 312 import std.array : array; 313 314 this.tags_ = this.tags_.filter!(t => t != tag).array; 315 316 return this; 317 } 318 319 /** 320 Instantiates something of type T. 321 322 Returns: 323 T instantiated data of type T. 324 **/ 325 T factory() { 326 return this.decorated.factory; 327 } 328 } 329 } 330 331 /** 332 Interface for object that can provide some location in 333 code/file that is associated with some kind of registration event 334 **/ 335 interface RegistrationLocation { 336 public { 337 @property { 338 339 /** 340 Get file in which registration occurred. 341 342 Returns: 343 string file in which a registration occured 344 **/ 345 string file() @safe nothrow; 346 347 /** 348 Get line in file on which registration occurred. 349 350 Returns: 351 size_t line in file on which registration occurred. 352 **/ 353 size_t line() @safe nothrow; 354 } 355 } 356 } 357 358 /** 359 A decorating factory, that adds component registration information 360 when decorated factory threws some kind of exception. 361 **/ 362 class RegistrationAwareDecoratingFactory(T) : Factory!T, MutableDecorator!(Factory!T), RegistrationLocation { 363 364 private { 365 366 Factory!T decorated_; 367 368 string file_; 369 size_t line_; 370 } 371 372 public { 373 374 @property { 375 376 /** 377 Set file in which registration occurred. 378 379 Params: 380 file = file in which a registration occured 381 382 Returns: 383 this 384 **/ 385 RegistrationAwareDecoratingFactory!T file(string file) @safe nothrow { 386 this.file_ = file; 387 388 return this; 389 } 390 391 /** 392 Get file in which registration occurred. 393 394 Returns: 395 string file in which a registration occured 396 **/ 397 string file() @safe nothrow { 398 return this.file_; 399 } 400 401 /** 402 Set line in file on which registration occurred. 403 404 Params: 405 line = line in file on which registration occurred. 406 407 Returns: 408 this 409 **/ 410 RegistrationAwareDecoratingFactory!T line(size_t line) @safe nothrow { 411 this.line_ = line; 412 413 return this; 414 } 415 416 /** 417 Get line in file on which registration occurred. 418 419 Returns: 420 size_t line in file on which registration occurred. 421 **/ 422 size_t line() @safe nothrow { 423 return this.line_; 424 } 425 426 /** 427 Set the decorated factory for decorator. 428 429 Params: 430 decorated = decorated factory 431 432 Returns: 433 this 434 **/ 435 RegistrationAwareDecoratingFactory!T decorated(Factory!T decorated) @safe nothrow { 436 this.decorated_ = decorated; 437 438 return this; 439 } 440 441 /** 442 Get the decorated object. 443 444 Returns: 445 Factory!T decorated factory 446 **/ 447 Factory!T decorated() @safe nothrow { 448 return this.decorated_; 449 } 450 451 /** 452 Get the type info of T that is created. 453 454 Returns: 455 TypeInfo object of created object. 456 **/ 457 TypeInfo type() { 458 return this.decorated.type; 459 } 460 461 /** 462 Set a locator for depedencies. 463 464 Params: 465 locator = the locator that is set to oject. 466 467 Returns: 468 this 469 **/ 470 RegistrationAwareDecoratingFactory!T locator(Locator!() locator) { 471 this.decorated.locator = locator; 472 473 return this; 474 } 475 } 476 477 /** 478 Instantiates component of type T. 479 480 Instantiates component of type T. In case of some thrown exception, 481 it will chain any thrown exception with an exception that has information 482 about location where component was registered. 483 484 Throws: 485 AediException when another exception occurred during construction 486 487 Returns: 488 T instantiated data of type T. 489 **/ 490 T factory() { 491 492 try { 493 return this.decorated.factory; 494 } catch (Exception e) { 495 import std.conv; 496 throw new AediException( 497 "An error occured during instantiation of component registered in file: " ~ 498 this.file ~ 499 " at line " ~ 500 this.line.to!string, 501 this.file, 502 this.line, 503 e 504 ); 505 } 506 } 507 } 508 }