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.typecons; 43 import std.meta; 44 import std.traits; 45 import aermicioi.util.traits; 46 47 /** 48 TODO: Add description of what this is and why it was designed as such. 49 **/ 50 interface ProxyContainer : Container, Storage!(ProxyObjectFactory, string), Decorator!(Locator!()) { 51 52 } 53 54 /** 55 Templated switchable container. 56 57 Templated switchable container. This container will 58 decorate another container, and add switching logic 59 to it. Depending in which state (on/off) the switching 60 container is. It will instantiate if the container is on, 61 and not if container is in off mode. This container will 62 inherit following interfaces only and only if the 63 T also implements them: 64 $(OL 65 $(LI Storage!(ObjectFactory, string)) 66 $(LI Container) 67 $(LI AliasAware!string) 68 ) 69 70 Params: 71 T = The container that switchable container will decorate. 72 73 **/ 74 template ProxyContainerImpl(T) { 75 /** 76 Set which the switchable container will decorate for T. By default 77 Locator!() and Switchable is included. 78 **/ 79 alias InheritanceSet = AliasSeq!(Filter!( 80 templateOr!( 81 partialSuffixed!( 82 isDerived, 83 Storage!(ObjectFactory, string) 84 ), 85 partialSuffixed!( 86 isDerived, 87 AliasAware!string 88 ), 89 partialSuffixed!( 90 isDerived, 91 FactoryLocator!ObjectFactory 92 ) 93 ), 94 InterfacesTuple!T), 95 ProxyContainer, 96 MutableDecorator!T 97 ); 98 99 /** 100 Templated proxy container. 101 **/ 102 class ProxyContainerImpl : InheritanceSet { 103 private { 104 T decorated_; 105 106 ObjectStorage!(ProxyObjectFactory, string) proxyFactories; 107 } 108 109 public { 110 111 @property { 112 ProxyContainerImpl decorated(T decorated) @safe nothrow { 113 this.decorated_ = decorated; 114 115 return this; 116 } 117 118 T decorated() @safe nothrow { 119 return this.decorated_; 120 } 121 } 122 123 ProxyContainerImpl set(ProxyObjectFactory factory, string identity) { 124 this.proxyFactories.set(factory, identity); 125 126 return this; 127 } 128 129 ProxyContainerImpl remove(string identity) { 130 this.proxyFactories.remove(identity); 131 132 return this; 133 } 134 135 static if (is(T : Container)) { 136 137 /** 138 Prepare container to be used. 139 140 Prepare container to be used. 141 142 Returns: 143 ProxyContainer decorating container 144 **/ 145 ProxyContainerImpl instantiate() { 146 decorated.instantiate(); 147 148 return this; 149 } 150 } 151 152 static if (is(T : Storage!(ObjectFactory, string))) { 153 /** 154 Set factory in container by identity. 155 156 Params: 157 identity = identity of factory. 158 element = factory that is to be saved in container. 159 160 Return: 161 ProxyContainer decorating container. 162 **/ 163 ProxyContainerImpl set(ObjectFactory element, string identity) { 164 decorated.set(element, identity); 165 166 return this; 167 } 168 169 /** 170 Remove factory from container with identity. 171 172 Remove factory from container with identity. 173 174 Params: 175 identity = the identity of factory to be removed. 176 177 Return: 178 ProxyContainer decorating container 179 **/ 180 ProxyContainerImpl remove(string identity) { 181 decorated.remove(identity); 182 183 return this; 184 } 185 } 186 187 static if (is(T : AliasAware!string)) { 188 /** 189 Alias identity to an alias_. 190 191 Params: 192 identity = originial identity which is to be aliased. 193 alias_ = alias of identity. 194 195 Returns: 196 ProxyContainer decorating container 197 **/ 198 ProxyContainerImpl link(string identity, string alias_) { 199 this.decorated.link(identity, alias_); 200 this.proxyFactories.link(identity, alias_); 201 202 return this; 203 } 204 205 /** 206 Removes alias. 207 208 Params: 209 alias_ = alias to remove. 210 211 Returns: 212 ProxyContainer decorating container 213 **/ 214 ProxyContainerImpl unlink(string alias_) { 215 this.decorated.unlink(alias_); 216 this.proxyFactories.unlink(alias_); 217 218 return this; 219 } 220 221 /** 222 Resolve an alias to original identity, if possible. 223 224 Params: 225 alias_ = alias of original identity 226 227 Returns: 228 const(string) the last identity in alias chain if container is enabled, or alias_ when not. 229 230 **/ 231 const(string) resolve(in string alias_) const { 232 return this.proxyFactories.resolve(alias_); 233 } 234 } 235 236 static if (is(T : FactoryLocator!ObjectFactory)) { 237 238 ObjectFactory getFactory(string identity) { 239 return this.decorated.getFactory(identity); 240 } 241 242 InputRange!(Tuple!(ObjectFactory, string)) getFactories() { 243 return this.decorated.getFactories(); 244 } 245 } 246 247 /** 248 Get object that is associated with identity. 249 250 Params: 251 identity = the object identity. 252 253 Throws: 254 NotFoundException in case if the object wasn't found or container is not enabled. 255 256 Returns: 257 Object if it is available. 258 **/ 259 Object get(string identity) { 260 return proxyFactories.get(identity).factory(); 261 } 262 263 /** 264 Check if object is present in ProxyContainer by key identity. 265 266 Note: 267 This check should be done for elements that locator actually contains, and 268 not in chained locator (when locator is also a DelegatingLocator) for example. 269 Params: 270 identity = identity of object. 271 272 Returns: 273 bool true if container is enabled and has object by identity. 274 **/ 275 bool has(in string identity) inout { 276 return proxyFactories.has(identity); 277 } 278 } 279 } 280 }