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.traits; 39 40 41 /** 42 A component registration interface for storage. 43 44 Registration context registers components into storage, 45 and uses a locator as a source of dependencies for components. 46 47 Params: 48 ObjectWrappingFactory = factory used to wrap components that are not 49 derived from Object. 50 **/ 51 struct RegistrationContext( 52 alias ObjectWrappingFactory = WrappingFactory 53 ) { 54 public { 55 56 /** 57 Storage into which to store components; 58 **/ 59 Storage!(ObjectFactory, string) storage; 60 61 /** 62 Locator used for fetching components dependencies; 63 **/ 64 Locator!(Object, string) locator; 65 66 /** 67 Constructor for RegistrationContext 68 69 Params: 70 storage = storage where to put registered components 71 locator = locator used to get registered component's dependencies 72 **/ 73 this(Storage!(ObjectFactory, string) storage, Locator!(Object, string) locator) { 74 this.storage = storage; 75 this.locator = locator; 76 } 77 78 /** 79 Register a component of type T by identity, type, or interface it implements. 80 81 Register a component of type T by identity, type, or interface it implements. 82 83 Params: 84 Interface = interface of registered component that it implements 85 T = type of registered component 86 identity = identity by which component is stored in storage 87 88 Returns: 89 GenericFactory!T factory for component for further configuration 90 **/ 91 ConfigurationContextFactory!T register(T)(string identity) { 92 ConfigurationContextFactory!T factory = new ConfigurationContextFactory!T(); 93 94 GenericFactoryImpl!T implementation = new GenericFactoryImpl!T(locator); 95 ObjectWrappingFactory!(GenericFactory!T) wrapper = new ObjectWrappingFactory!(GenericFactory!T)(implementation); 96 97 factory.decorated = implementation; 98 factory.wrapper = wrapper; 99 factory.locator = locator; 100 factory.storage = storage; 101 factory.identity = identity; 102 103 storage.set(wrapper, identity); 104 return factory; 105 } 106 107 /** 108 ditto 109 **/ 110 ConfigurationContextFactory!T register(T)() { 111 return register!T(fullyQualifiedName!T); 112 } 113 114 /** 115 ditto 116 **/ 117 ConfigurationContextFactory!T register(Interface, T : Interface)() 118 if (!is(T == Interface)) { 119 return register!T(fullyQualifiedName!Interface); 120 } 121 122 /** 123 Register a component of type T by identity, type, or interface it implements with a default value. 124 125 Register a component of type T by identity, type, or interface it implements with a default value. 126 127 Params: 128 Interface = interface of registered component that it implements 129 T = type of registered component 130 identity = identity by which component is stored in storage 131 value = initial value of component; 132 133 Returns: 134 GenericFactory!T factory for component for further configuration 135 **/ 136 ConfigurationContextFactory!T register(T)(auto ref T value, string identity) { 137 import aermicioi.aedi.configurer.register.factory_configurer : val = value; 138 139 ConfigurationContextFactory!T factory = register!T(identity); 140 141 factory.val(value); 142 143 return factory; 144 } 145 146 /** 147 ditto 148 **/ 149 ConfigurationContextFactory!T register(T)(auto ref T value) 150 if (!is(T == string)) { 151 152 return register(value, fullyQualifiedName!T); 153 } 154 155 /** 156 ditto 157 **/ 158 ConfigurationContextFactory!T register(Interface, T : Interface)(auto ref T value) 159 if (!is(T == Interface)) { 160 161 return register(value, fullyQualifiedName!Interface); 162 } 163 } 164 } 165 166 /** 167 Start registering components using a storage and a locator. 168 169 Start registering components using a storage and a locator. 170 171 Params: 172 storage = store registered components into it. 173 locator = locator of dependencies for registered components 174 175 Returns: 176 RegistrationContext context with registration interface used to register components. 177 **/ 178 RegistrationContext!ObjectWrappingFactory configure 179 (alias ObjectWrappingFactory = WrappingFactory) 180 (Storage!(ObjectFactory, string) storage, Locator!(Object, string) locator) { 181 return RegistrationContext!ObjectWrappingFactory(storage, locator); 182 } 183 184 /** 185 ditto 186 **/ 187 RegistrationContext!ObjectWrappingFactory configure 188 (alias ObjectWrappingFactory = WrappingFactory) 189 (Locator!(Object, string) locator, Storage!(ObjectFactory, string) storage) { 190 return RegistrationContext!ObjectWrappingFactory(storage, locator); 191 } 192 193 /** 194 Start registering components using a container. 195 196 Start registering components using a container. 197 198 Params: 199 container = storage and locator of components. 200 201 Returns: 202 RegistrationContext context with registration interface used to register components. 203 **/ 204 RegistrationContext!ObjectWrappingFactory configure(T, alias ObjectWrappingFactory = WrappingFactory)(T container) 205 if (is(T : Storage!(ObjectFactory, string)) && is(T : Locator!(Object, string))) { 206 207 return configure(cast(Locator!(Object, string)) container, container); 208 } 209 210 /** 211 Start registering components using a storage and a locator. 212 213 Start registering components using a storage and a locator. 214 215 Params: 216 storage = identity of a storage located in locator used by registration context to store components. 217 locator = locator of dependencies for registered components 218 219 Returns: 220 RegistrationContext context with registration interface used to register components. 221 **/ 222 RegistrationContext!ObjectWrappingFactory configure 223 (alias ObjectWrappingFactory = WrappingFactory) 224 (Locator!(Object, string) locator, string storage) { 225 return configure!ObjectWrappingFactory(locator, locator.locate!(Storage!(ObjectFactory, string))(storage)); 226 } 227 228 /** 229 Use locator or storage as basis for registering components. 230 231 Use locator or storage as basis for registering components. 232 233 Params: 234 registrationContext = context for which to set new configured storage, or used locator 235 storage = store registered components into it. 236 locator = locator of dependencies for registered components 237 238 Returns: 239 RegistrationContext context with registration interface used to register components. 240 **/ 241 Context along 242 (Context : RegistrationContext!T, alias T) 243 (Context registrationContext, Storage!(ObjectFactory, string) storage) { 244 registrationContext.storage = storage; 245 246 return registrationContext; 247 } 248 249 /** 250 ditto 251 **/ 252 Context along(Context : RegistrationContext!T, alias T)(Context registrationContext, Locator!(Object, string) locator) { 253 registrationContext.locator = locator; 254 255 return registrationContext; 256 } 257 258 /** 259 Use locator or storage as basis for registering components. 260 261 Use locator or storage as basis for registering components. 262 263 Params: 264 registrationContext = context for which to set new configured storage, or used locator 265 storage = identity of a storage located in locator that should be used by registrationContext to store components. 266 267 Returns: 268 RegistrationContext context with registration interface used to register components. 269 **/ 270 Context along(Context : RegistrationContext!T, alias T)(Context registrationContext, string storage) { 271 registrationContext.storage = registrationContext.locator.locate!(Storage!(ObjectFactory, string))(storage); 272 273 return registrationContext; 274 } 275 276 /** 277 A registration interface for components already created. 278 279 Value registration context, provides a nice registration 280 api over Object containers, to store already instantiated 281 components into container. 282 **/ 283 struct ValueRegistrationContext { 284 285 public { 286 /** 287 Storage for already instantiated components. 288 **/ 289 Storage!(Object, string) storage; 290 291 /** 292 Register a component into value container by identity, type or interface. 293 294 Register a component into value container by identity, type or interface. 295 296 Params: 297 value = component to be registered in container 298 identity = identity of component in container 299 T = type of component 300 Interface = interface that T component implements 301 302 Returns: 303 ValueRegistrationContext 304 **/ 305 ref ValueRegistrationContext register(T)(auto ref T value, string identity) { 306 static if (is(T : Object)) { 307 storage.set(value, identity); 308 } else { 309 import aermicioi.aedi.storage.wrapper : WrapperImpl; 310 311 storage.set(new WrapperImpl!T(value), identity); 312 } 313 314 return this; 315 } 316 317 /** 318 ditto 319 **/ 320 ref ValueRegistrationContext register(T)(auto ref T value) { 321 return register!T(value, fullyQualifiedName!T); 322 } 323 324 /** 325 ditto 326 **/ 327 ref ValueRegistrationContext register(Interface, T : Interface)(auto ref T value) { 328 return register!T(value, fullyQualifiedName!Interface); 329 } 330 } 331 } 332 333 /** 334 Start registering instantiated components into a value container. 335 336 Start registering instantiated components into a value container. 337 Description 338 339 Params: 340 storage = value container used to store instantiated components 341 342 Returns: 343 ValueRegistrationContext context that provides register api, using storage to store registered components. 344 **/ 345 ValueRegistrationContext configure(Storage!(Object, string) storage) { 346 return ValueRegistrationContext(storage); 347 } 348 349 /** 350 Adds registration location information in component's factory for easier debugging. 351 352 Params: 353 context = original preconfigured registration context to use as basis. 354 **/ 355 struct RegistrationInfoTaggedRegistrationContext(T : RegistrationContext!Z, alias Z) { 356 import aermicioi.aedi.factory.decorating_factory : RegistrationAwareDecoratingFactory; 357 358 public { 359 360 /** 361 Underlying registration context. 362 **/ 363 T context; 364 365 alias context this; 366 367 /** 368 Constructor for RegistrationInfoTaggedRegistrationContext 369 370 Params: 371 context = underlying context used for registration 372 **/ 373 this(T context) { 374 this.context = context; 375 } 376 377 /** 378 Register a component of type T by identity, type, or interface it implements. 379 380 Register a component of type T by identity, type, or interface it implements. 381 382 Params: 383 Interface = interface of registered component that it implements 384 T = type of registered component 385 identity = identity by which component is stored in storage 386 387 Returns: 388 GenericFactory!T factory for component for further configuration 389 **/ 390 ConfigurationContextFactory!T register(T, string file = __FILE__, size_t line = __LINE__)(string identity) { 391 auto factory = this.context.register!T(identity); 392 393 this.inject(factory, file, line); 394 return factory; 395 } 396 397 /** 398 ditto 399 **/ 400 ConfigurationContextFactory!T register(T, string file = __FILE__, size_t line = __LINE__)() { 401 auto factory = this.context.register!T(); 402 403 this.inject(factory, file, line); 404 return factory; 405 } 406 407 /** 408 ditto 409 **/ 410 ConfigurationContextFactory!T register 411 (Interface, T : Interface, string file = __FILE__, size_t line = __LINE__)() 412 if (!is(T == Interface)) { 413 auto factory = this.context.register!(Interface, T)(); 414 415 this.inject(factory, file, line); 416 return factory; 417 } 418 419 /** 420 Register a component of type T by identity, type, or interface it implements with a default value. 421 422 Register a component of type T by identity, type, or interface it implements with a default value. 423 424 Params: 425 Interface = interface of registered component that it implements 426 T = type of registered component 427 identity = identity by which component is stored in storage 428 value = initial value of component; 429 430 Returns: 431 GenericFactory!T factory for component for further configuration 432 **/ 433 ConfigurationContextFactory!T register 434 (T, string file = __FILE__, size_t line = __LINE__) 435 (auto ref T value, string identity) { 436 auto factory = this.context.register!T(value, identity); 437 438 this.inject(factory, file, line); 439 return factory; 440 } 441 442 /** 443 ditto 444 **/ 445 ConfigurationContextFactory!T register 446 (T, string file = __FILE__, size_t line = __LINE__) 447 (auto ref T value) 448 if (!is(T == string)) { 449 auto factory = this.context.register!T(value); 450 451 this.inject(factory, file, line); 452 return factory; 453 } 454 455 /** 456 ditto 457 **/ 458 ConfigurationContextFactory!T register 459 (Interface, T : Interface, string file = __FILE__, size_t line = __LINE__) 460 (auto ref T value) 461 if (!is(T == Interface)) { 462 auto factory = this.context.register!(Interface, T)(value); 463 464 this.inject(factory, file, line); 465 return factory; 466 } 467 } 468 469 private { 470 void inject(T)(ConfigurationContextFactory!T factory, string file, size_t line) { 471 RegistrationAwareDecoratingFactory!Object wrapper = new RegistrationAwareDecoratingFactory!Object(); 472 wrapper.file = file; 473 wrapper.line = line; 474 475 wrapper.decorated = factory.wrapper; 476 factory.wrapper = wrapper; 477 478 factory.storage.set(factory.wrapper, factory.identity); 479 } 480 } 481 } 482 483 /** 484 ditto 485 **/ 486 auto withRegistrationInfo(T : RegistrationContext!Z, alias Z)(auto ref T context) { 487 return RegistrationInfoTaggedRegistrationContext!T(context); 488 }