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