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 module aermicioi.aedi.configurer.register.context; 31 32 import aermicioi.aedi.configurer.register.configuration_context_factory; 33 import aermicioi.aedi.factory.factory; 34 import aermicioi.aedi.factory.generic_factory; 35 import aermicioi.aedi.factory.wrapping_factory; 36 import aermicioi.aedi.storage.locator; 37 import aermicioi.aedi.storage.storage; 38 import std.experimental.allocator : RCIAllocator, theAllocator; 39 import std.traits; 40 import std.meta : AliasSeq; 41 42 @safe: 43 44 struct RegistrationContext(Policies...) 45 if (Policies.length > 1) { 46 /** 47 Storage into which to store components; 48 **/ 49 Storage!(ObjectFactory, string) storage; 50 51 /** 52 Locator used for fetching components dependencies; 53 **/ 54 Locator!(Object, string) locator; 55 56 /** 57 Allocator used for registered components. 58 **/ 59 RCIAllocator allocator; 60 61 alias ConfigurableFactoryType(T) = ConfigurableFactory!(T, FactoryPolicyExtractor!Policies); 62 63 ref typeof(this) initialize() { 64 static foreach (Policy; Policies) { 65 Policy.initialize(storage, locator, allocator); 66 } 67 68 return this; 69 } 70 71 /** 72 Register a component of type T by identity, type, or interface it implements. 73 74 Register a component of type T by identity, type, or interface it implements. 75 76 Params: 77 Interface = interface of registered component that it implements 78 T = type of registered component 79 identity = identity by which component is stored in storage 80 81 Returns: 82 GenericFactory!T factory for component for further configuration 83 **/ 84 ConfigurableFactoryType!T register(T, string file = __FILE__, size_t line = __LINE__)(string identity) { 85 ConfigurableFactoryType!T factory = new ConfigurableFactoryType!T(); 86 static if (is(typeof(factory) : Class!(ComponentType, FactoryPolicies), alias Class, ComponentType, FactoryPolicies...)) { 87 static foreach (FactoryPolicy; FactoryPolicies) { 88 static if (__traits(isSame, FactoryPolicy, StoragePolicy)) { 89 factory.storage = storage; 90 factory.identity = identity; 91 } 92 93 static if (__traits(isSame, FactoryPolicy, DecoratingFactoryPolicy)) { 94 factory.locator = locator; 95 factory.allocator = allocator; 96 } 97 98 static if (__traits(isSame, FactoryPolicy, RegistrationStorePolicy)) { 99 factory.file = file; 100 factory.line = line; 101 } 102 } 103 } 104 105 static foreach (Policy; Policies) { 106 Policy.apply(factory); 107 } 108 109 return factory; 110 } 111 112 /** 113 ditto 114 **/ 115 ConfigurableFactoryType!T register(T, string file = __FILE__, size_t line = __LINE__)() { 116 return register!(T, file, line)(fullyQualifiedName!T); 117 } 118 119 /** 120 ditto 121 **/ 122 ConfigurableFactoryType!T register(Interface, T : Interface, string file = __FILE__, size_t line = __LINE__)() 123 if (!is(T == Interface)) { 124 return register!(T, file, line)(fullyQualifiedName!Interface); 125 } 126 127 /** 128 Register a component of type T by identity, type, or interface it implements with a default value. 129 130 Register a component of type T by identity, type, or interface it implements with a default value. 131 132 Params: 133 Interface = interface of registered component that it implements 134 T = type of registered component 135 identity = identity by which component is stored in storage 136 value = initial value of component; 137 138 Returns: 139 GenericFactory!T factory for component for further configuration 140 **/ 141 ConfigurableFactoryType!T register(T, string file = __FILE__, size_t line = __LINE__)(auto ref T value, string identity) { 142 import aermicioi.aedi.configurer.register.factory_configurer : val = value; 143 144 ConfigurableFactoryType!T factory = register!(T, file, line)(identity); 145 146 factory.val(value); 147 148 return factory; 149 } 150 151 /** 152 ditto 153 **/ 154 ConfigurableFactoryType!T register(T, string file = __FILE__, size_t line = __LINE__)(auto ref T value) 155 if (!is(T == string)) { 156 157 return register!(T, file, line)(value, fullyQualifiedName!T); 158 } 159 160 /** 161 ditto 162 **/ 163 ConfigurableFactoryType!T register(Interface, T : Interface, string file = __FILE__, size_t line = __LINE__)(auto ref T value) 164 if (!is(T == Interface)) { 165 166 return register!(T, file, line)(value, fullyQualifiedName!Interface); 167 } 168 } 169 170 /** 171 Policy responsible for creation of generic factory that will create component T. 172 **/ 173 struct GenericFactoryPolicy { 174 175 alias FactoryPolicy = DecoratingFactoryPolicy; 176 177 static void initialize(Storage!(ObjectFactory, string) storage, Locator!(Object, string) locator, RCIAllocator allocator) { 178 179 } 180 181 static void apply(Z : ConfigurableFactory!(T, Policies), T, Policies...)(Z factory) { 182 factory.decorated = new GenericFactoryImpl!T(factory.locator); 183 factory.decorated.allocator = factory.allocator; 184 } 185 } 186 187 /** 188 Policy responsible for creation of factory wrapper suitable for storing into storage. 189 **/ 190 struct WrappingFactoryPolicy { 191 192 alias FactoryPolicy = WrapperStorePolicy; 193 194 static void initialize(Storage!(ObjectFactory, string) storage, Locator!(Object, string) locator, RCIAllocator allocator) { 195 196 } 197 198 static void apply(Z : ConfigurableFactory!(T, Policies), T, Policies...)(Z factory) { 199 factory.wrapper = new WrappingFactory!(Factory!T)(factory); 200 } 201 } 202 203 /** 204 Policy responsible for persisting wrapper into storage by some identity. 205 **/ 206 struct PersistingFactoryPolicy { 207 208 alias FactoryPolicy = StoragePolicy; 209 210 static void initialize(Storage!(ObjectFactory, string) storage, Locator!(Object, string) locator, RCIAllocator allocator) { 211 212 } 213 214 static void apply(Z : ConfigurableFactory!(T, Policies), T, Policies...)(Z factory) { 215 factory.storage.set(factory.wrapper, factory.identity); 216 } 217 } 218 219 /** 220 Start registering components using a storage and a locator. 221 222 Start registering components using a storage and a locator. 223 224 Params: 225 storage = store registered components into it. 226 locator = locator of dependencies for registered components 227 allocator = default allocation strategy for registered components 228 229 Returns: 230 RegistrationContext context with registration interface used to register components. 231 **/ 232 RegistrationContext!Policies configure(Policies...) 233 (Storage!(ObjectFactory, string) storage, Locator!(Object, string) locator, RCIAllocator allocator = theAllocator) 234 if (Policies.length > 0) { 235 return RegistrationContext!(Policies)(storage, locator, allocator).initialize(); 236 } 237 238 /** 239 ditto 240 **/ 241 RegistrationContext!Policies configure(Policies...) 242 (Locator!(Object, string) locator, Storage!(ObjectFactory, string) storage, RCIAllocator allocator = theAllocator) 243 if (Policies.length > 0) { 244 return RegistrationContext!(Policies)(storage, locator, allocator).initialize(); 245 } 246 247 /** 248 ditto 249 **/ 250 RegistrationContext!( 251 GenericFactoryPolicy, 252 WrappingFactoryPolicy, 253 DeferredFactoryPolicy, 254 RegistrationAwarePolicy, 255 PersistingFactoryPolicy 256 ) configure( 257 Storage!(ObjectFactory, string) storage, 258 Locator!(Object, string) locator, 259 RCIAllocator allocator = theAllocator) 260 { 261 return storage.configure!( 262 GenericFactoryPolicy, 263 WrappingFactoryPolicy, 264 DeferredFactoryPolicy, 265 RegistrationAwarePolicy, 266 PersistingFactoryPolicy)(locator, allocator); 267 } 268 269 /** 270 ditto 271 **/ 272 RegistrationContext!( 273 GenericFactoryPolicy, 274 WrappingFactoryPolicy, 275 DeferredFactoryPolicy, 276 RegistrationAwarePolicy, 277 PersistingFactoryPolicy 278 ) configure( 279 Locator!(Object, string) locator, 280 Storage!(ObjectFactory, string) storage, 281 RCIAllocator allocator = theAllocator) 282 { 283 return storage.configure!( 284 GenericFactoryPolicy, 285 WrappingFactoryPolicy, 286 DeferredFactoryPolicy, 287 RegistrationAwarePolicy, 288 PersistingFactoryPolicy)(locator, allocator); 289 } 290 291 /** 292 Start registering components using a container. 293 294 Start registering components using a container. 295 296 Params: 297 container = storage and locator of components. 298 allocator = default allocation strategy for registered components 299 300 Returns: 301 RegistrationContext context with registration interface used to register components. 302 **/ 303 auto configure(T)(T container, RCIAllocator allocator = theAllocator) 304 if (is(T : Storage!(ObjectFactory, string)) && is(T : Locator!(Object, string))) { 305 306 return configure(cast(Storage!(ObjectFactory, string)) container, container, allocator); 307 } 308 309 /** 310 Start registering components using a storage and a locator. 311 312 Start registering components using a storage and a locator. 313 314 Params: 315 storage = identity of a storage located in locator used by registration context to store components. 316 locator = locator of dependencies for registered components 317 allocator = default allocation strategy for registered components 318 319 Returns: 320 RegistrationContext!Policies context with registration interface used to register components. 321 **/ 322 RegistrationContext!Policies configure(Policies...)(Locator!(Object, string) locator, string storage, RCIAllocator allocator = theAllocator) 323 if (Policies.length > 1) { 324 return configure!Policies(locator, locator.locate!(Storage!(ObjectFactory, string))(storage), allocator); 325 } 326 327 auto configure(Locator!(Object, string) locator, string storage, RCIAllocator allocator = theAllocator) { 328 return configure(locator, locator.locate!(Storage!(ObjectFactory, string))(storage), allocator); 329 } 330 331 /** 332 Use locator/storage/allocator as basis for registering components. 333 334 Use locator/storage/allocator as basis for registering components. 335 336 Params: 337 context = context for which to set new configured storage, or used locator 338 storage = store registered components into it. 339 locator = locator of dependencies for registered components 340 allocator = allocator used as default allocation strategy for components. 341 342 Returns: 343 RegistrationContext!Policies context with registration interface used to register components. 344 **/ 345 RegistrationContext!Policies along(Policies...)(RegistrationContext!Policies context, Storage!(ObjectFactory, string) storage) { 346 context.storage = storage; 347 348 return context.initialize; 349 } 350 351 /** 352 ditto 353 **/ 354 RegistrationContext!Policies along(Policies...)(RegistrationContext!Policies context, Locator!(Object, string) locator) { 355 context.locator = locator; 356 357 return context.initialize; 358 } 359 360 /** 361 ditto 362 **/ 363 RegistrationContext!Policies along(Policies...)(RegistrationContext!Policies context, RCIAllocator allocator) { 364 context.allocator = allocator; 365 366 return context.initialize; 367 } 368 369 /** 370 Use storage as basis for registering components. 371 372 Use storage as basis for registering components. 373 374 Params: 375 context = context for which to set new configured storage, or used locator 376 storage = identity of a storage located in locator that should be used by registrationContext to store components. 377 378 Returns: 379 RegistrationContext context with registration interface used to register components. 380 **/ 381 RegistrationContext!Policies along(Policies...)(RegistrationContext!Policies context, string storage) { 382 import aermicioi.aedi.exception.invalid_cast_exception : InvalidCastException; 383 384 context.storage = context.locator.locate!(Storage!(ObjectFactory, string))(storage); 385 386 return context.initialize; 387 } 388 389 /** 390 Apply a policy after existing policies in a registration context, or at a position if specified. 391 392 Params: 393 context = context to which add a new policy 394 at = position at whicht to apply policy 395 Policy = new policy to inject into registration context 396 397 Returns: 398 RegistrationContext!(Policies, Policy) 399 **/ 400 RegistrationContext!(Policies, Policy) applying(Policy, Policies...)(RegistrationContext!Policies context) { 401 return RegistrationContext!(Policies, Policy)(context.storage, context.locator, context.allocator).initialize; 402 } 403 404 /** 405 ditto 406 **/ 407 RegistrationContext!(Policies[0 .. at], Policy, Policies[at .. $]) applying(size_t at, Policy, Policies...)(RegistrationContext!Policies context) { 408 return RegistrationContext!(Policies[0 .. at], Policy, Policies[at .. $])(context.storage, context.locator, context.allocator).initialize; 409 } 410 411 /** 412 A registration interface for components already created. 413 414 Value registration context, provides a nice registration 415 api over Object containers, to store already instantiated 416 components into container. 417 **/ 418 struct ValueRegistrationContext { 419 420 public { 421 /** 422 Storage for already instantiated components. 423 **/ 424 Storage!(Object, string) storage; 425 426 /** 427 Locator used for configuration purposes of features outside value container, yet related to the managed components. 428 **/ 429 Locator!() locator; 430 431 /** 432 Register a component into value container by identity, type or interface. 433 434 Register a component into value container by identity, type or interface. 435 436 Params: 437 value = component to be registered in container 438 identity = identity of component in container 439 T = type of component 440 Interface = interface that T component implements 441 442 Returns: 443 ValueRegistrationContext 444 **/ 445 ValueContext register(T)(auto ref T value, string identity) { 446 static if (is(T : Object)) { 447 storage.set(value, identity); 448 } else { 449 import aermicioi.aedi.storage.wrapper : WrapperImpl; 450 451 storage.set(new WrapperImpl!T(value), identity); 452 } 453 454 return ValueContext(identity, storage, locator); 455 } 456 457 /** 458 ditto 459 **/ 460 ValueContext register(T)(auto ref T value) { 461 return register!T(value, fullyQualifiedName!T); 462 } 463 464 /** 465 ditto 466 **/ 467 ValueContext register(Interface, T : Interface)(auto ref T value) { 468 return register!T(value, fullyQualifiedName!Interface); 469 } 470 } 471 472 /** 473 Value context useable for further configuration of container 474 **/ 475 static struct ValueContext { 476 477 /** 478 Identity of managed component 479 **/ 480 string identity; 481 482 /** 483 Storage of component 484 **/ 485 Storage!(Object, string) storage; 486 487 /** 488 Locator of components. Used for configuration of features not directly related to value container. 489 **/ 490 Locator!() locator; 491 } 492 } 493 494 /** 495 Start registering instantiated components into a value container. 496 497 Start registering instantiated components into a value container. 498 Description 499 500 Params: 501 storage = value container used to store instantiated components 502 503 Returns: 504 ValueRegistrationContext context that provides register api, using storage to store registered components. 505 **/ 506 ValueRegistrationContext configure(Storage!(Object, string) storage) { 507 return ValueRegistrationContext(storage); 508 } 509 510 /** 511 Start registering instantiated components into a value container. 512 513 Start registering instantiated components into a value container. 514 Description 515 516 Params: 517 locator = container that has the storage 518 storage = identity of storage to use 519 520 Returns: 521 ValueRegistrationContext context that provides register api, using storage to store registered components. 522 **/ 523 ValueRegistrationContext configureValueContainer(Locator!() locator, string storage) { 524 return ValueRegistrationContext(locator.locate!(Storage!(Object, string))(storage), locator); 525 } 526 527 /** 528 Adds registration location information in component's factory for easier debugging. 529 530 Params: 531 context = original preconfigured registration context to use as basis. 532 **/ 533 struct RegistrationAwarePolicy { 534 535 alias FactoryPolicy = RegistrationStorePolicy; 536 537 static void initialize(Storage!(ObjectFactory, string) storage, Locator!(Object, string) locator, RCIAllocator allocator) { 538 539 } 540 541 static void apply(Z : ConfigurableFactory!(T, Policies), T, Policies...)(Z factory) { 542 import aermicioi.aedi.factory.decorating_factory : RegistrationAwareDecoratingFactory; 543 RegistrationAwareDecoratingFactory!Object wrapper = new RegistrationAwareDecoratingFactory!Object(); 544 wrapper.file = factory.file; 545 wrapper.line = factory.line; 546 547 wrapper.decorated = factory.wrapper; 548 factory.wrapper = wrapper; 549 } 550 } 551 552 struct DeferredFactoryPolicy { 553 import aermicioi.aedi.factory.deferring_factory : DeferralContext; 554 555 alias FactoryPolicy = AliasSeq!(); 556 557 static void initialize(Storage!(ObjectFactory, string) storage, Locator!(Object, string) locator, RCIAllocator allocator) 558 in (storage !is null, "Storage is required for initialization of deferred policy.") 559 in (locator !is null, "Locator is required for initialization of deferred policy.") 560 in (!allocator.isNull, "Allocator is required for initialization of deferred policy.") { 561 562 } 563 564 static void apply(Z : ConfigurableFactory!(T, Policies), T, Policies...)(Z factory) { 565 import aermicioi.aedi.exception.not_found_exception : NotFoundException; 566 import aermicioi.aedi.factory.deferring_factory; 567 import aermicioi.aedi.util.typecons : optional; 568 import aermicioi.aedi.factory.reference : lref; 569 570 if (factory.locator.has(fullyQualifiedName!DeferralContext)) { 571 DeferringFactory!T deferring = new DeferringFactory!T(factory.decorated, factory.locator.locate!DeferralContext); 572 factory.decorated = deferring; 573 } 574 } 575 } 576 577 private template FactoryPolicyExtractor(Policies...) { 578 579 static if (Policies.length > 1) { 580 alias FactoryPolicyExtractor = AliasSeq!(Policies[0].FactoryPolicy, FactoryPolicyExtractor!(Policies[1 .. $])); 581 } else { 582 alias FactoryPolicyExtractor = Policies[0].FactoryPolicy; 583 } 584 }