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.container.proxy_container; 31 32 import aermicioi.aedi.container.container; 33 import aermicioi.aedi.storage.storage; 34 import aermicioi.aedi.storage.object_storage; 35 import aermicioi.aedi.factory.proxy_factory; 36 import aermicioi.aedi.exception.not_found_exception; 37 import aermicioi.aedi.storage.locator; 38 import aermicioi.aedi.storage.decorator; 39 import aermicioi.aedi.storage.alias_aware; 40 import aermicioi.aedi.factory.factory; 41 import std.range; 42 import std.meta; 43 import std.traits; 44 import aermicioi.aedi.util.traits; 45 46 /** 47 TODO: Add description of what this is and why it was designed as such. 48 **/ 49 @safe interface ProxyContainer : Container, Storage!(ProxyObjectFactory, string), 50 Decorator!(Locator!()) 51 { 52 53 } 54 55 /** 56 Templated switchable container. 57 58 Templated switchable container. This container will 59 decorate another container, and add switching logic 60 to it. Depending in which state (on/off) the switching 61 container is. It will instantiate if the container is on, 62 and not if container is in off mode. This container will 63 inherit following interfaces only and only if the 64 T also implements them: 65 $(OL 66 $(LI Storage!(ObjectFactory, string)) 67 $(LI Container) 68 $(LI AliasAware!string) 69 ) 70 71 Params: 72 T = The container that switchable container will decorate. 73 74 **/ 75 template ProxyContainerImpl(T) 76 { 77 /** 78 Set which the switchable container will decorate for T. By default 79 Locator!() and Switchable is included. 80 **/ 81 alias InheritanceSet = 82 NoDuplicates!( 83 Filter!( 84 templateOr!( 85 partialSuffixed!( 86 isDerived, 87 Storage!(ObjectFactory, 88 string) 89 ), 90 partialSuffixed!( 91 isDerived, 92 AliasAware!string 93 ), 94 partialSuffixed!( 95 isDerived, 96 FactoryLocator!ObjectFactory 97 ) 98 ), 99 InterfacesTuple!T 100 ), 101 ProxyContainer, 102 Decorator!Container 103 ); 104 105 /** 106 Templated proxy container. 107 **/ 108 @safe class ProxyContainerImpl : InheritanceSet 109 { 110 private 111 { 112 ObjectStorage!(ProxyObjectFactory, string) proxyFactories; 113 ObjectStorage!(Object, string) proxies; 114 } 115 116 public 117 { 118 119 /** 120 * Default constructor for ProxyContainerImpl 121 **/ 122 this() { 123 124 this.proxyFactories = new ObjectStorage!(ProxyObjectFactory, string); 125 this.proxies = new ObjectStorage!(Object, string); 126 } 127 128 mixin MutableDecoratorMixin!T; 129 130 /** 131 * Set object factory 132 * 133 * Params: 134 * factory = factory for a object that is to be managed by prototype container. 135 * identity = identity by which a factory is identified 136 * Returns: 137 * typeof(this) 138 **/ 139 ProxyContainerImpl set(ProxyObjectFactory factory, string identity) 140 { 141 this.proxyFactories.set(factory, identity); 142 143 return this; 144 } 145 146 static if (is(T : Container)) 147 { 148 149 /** 150 Prepare container to be used. 151 152 Prepare container to be used. 153 154 Returns: 155 ProxyContainer decorating container 156 **/ 157 ProxyContainerImpl instantiate() 158 { 159 decorated.instantiate(); 160 161 return this; 162 } 163 164 /** 165 Destruct all managed components. 166 167 Destruct all managed components. The method denotes the end of container lifetime, and therefore destruction of all managed components 168 by it. 169 **/ 170 ProxyContainerImpl terminate() { 171 172 foreach (pair; this.proxies.contents.byKeyValue) { 173 this.proxyFactories.get(pair.key).destruct(pair.value); 174 } 175 176 (() @trusted scope => this.proxies.contents.clear)(); 177 178 return this; 179 } 180 } 181 182 static if (is(T : Storage!(ObjectFactory, string))) 183 { 184 /** 185 Set factory in container by identity. 186 187 Params: 188 identity = identity of factory. 189 element = factory that is to be saved in container. 190 191 Return: 192 ProxyContainer decorating container. 193 **/ 194 ProxyContainerImpl set(ObjectFactory element, string identity) 195 { 196 decorated.set(element, identity); 197 198 return this; 199 } 200 201 /** 202 Remove factory from container with identity. 203 204 Remove factory from container with identity. 205 206 Params: 207 identity = the identity of factory to be removed. 208 209 Return: 210 ProxyContainer decorating container 211 **/ 212 Storage!(ObjectFactory, string) remove(string identity) 213 { 214 if (this.proxies.has(identity)) { 215 auto temporary = this.proxies.get(identity); 216 this.proxyFactories.get(identity).destruct(temporary); 217 this.proxies.remove(identity); 218 } 219 220 this.decorated.remove(identity); 221 this.proxyFactories.remove(identity); 222 223 return this; 224 } 225 226 /** 227 ditto 228 **/ 229 Storage!(ProxyObjectFactory, string) remove(string identity) 230 { 231 (cast(Storage!(ObjectFactory, string)) this).remove(identity); 232 233 return this; 234 } 235 } 236 else 237 { 238 /** 239 Remove factory from container with identity. 240 241 Remove factory from container with identity. 242 243 Params: 244 identity = the identity of factory to be removed. 245 246 Return: 247 ProxyContainer decorating container 248 **/ 249 ProxyContainerImpl remove(string identity) 250 { 251 if (this.proxies.has(identity)) { 252 auto temporary = this.proxies.get(identity); 253 this.proxyFactories.get(identity).destruct(temporary); 254 this.proxies.remove(identity); 255 } 256 257 this.proxyFactories.remove(identity); 258 259 return this; 260 } 261 } 262 263 static if (is(T : AliasAware!string)) 264 { 265 /** 266 Alias identity to an alias_. 267 268 Params: 269 identity = originial identity which is to be aliased. 270 alias_ = alias of identity. 271 272 Returns: 273 ProxyContainer decorating container 274 **/ 275 ProxyContainerImpl link(string identity, string alias_) 276 { 277 this.decorated.link(identity, alias_); 278 this.proxyFactories.link(identity, alias_); 279 280 return this; 281 } 282 283 /** 284 Removes alias. 285 286 Params: 287 alias_ = alias to remove. 288 289 Returns: 290 ProxyContainer decorating container 291 **/ 292 ProxyContainerImpl unlink(string alias_) 293 { 294 this.decorated.unlink(alias_); 295 this.proxyFactories.unlink(alias_); 296 297 return this; 298 } 299 300 /** 301 Resolve an alias to original identity, if possible. 302 303 Params: 304 alias_ = alias of original identity 305 306 Returns: 307 const(string) the last identity in alias chain if container is enabled, or alias_ when not. 308 309 **/ 310 const(string) resolve(in string alias_) const 311 { 312 return this.proxyFactories.resolve(alias_); 313 } 314 } 315 316 static if (is(T : FactoryLocator!ObjectFactory)) 317 { 318 mixin FactoryLocatorMixin!(typeof(this)); 319 } 320 321 /** 322 Get object that is associated with identity. 323 324 Params: 325 identity = the object identity. 326 327 Throws: 328 NotFoundException in case if the object wasn't found or container is not enabled. 329 330 Returns: 331 Object if it is available. 332 **/ 333 Object get(string identity) 334 { 335 this.proxies.set(proxyFactories.get(identity).factory(), identity); 336 337 return this.proxies.get(identity); 338 } 339 340 /** 341 Check if object is present in ProxyContainer by key identity. 342 343 Note: 344 This check should be done for elements that locator actually contains, and 345 not in chained locator (when locator is also a DelegatingLocator) for example. 346 Params: 347 identity = identity of object. 348 349 Returns: 350 bool true if container is enabled and has object by identity. 351 **/ 352 bool has(in string identity) inout 353 { 354 return proxyFactories.has(identity); 355 } 356 } 357 } 358 }