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 88 Params: 89 T = The decorated that switchable decorated will decorate. 90 91 **/ 92 template SwitchableContainer(T) { 93 import std.meta; 94 import std.traits; 95 import aermicioi.util.traits; 96 97 /** 98 Set which the switchable decorated will decorate for T. By default 99 Locator!() and Switchable is included. 100 **/ 101 alias InheritanceSet = AliasSeq!(Filter!( 102 templateOr!( 103 partialSuffixed!( 104 isDerived, 105 Storage!(ObjectFactory, string) 106 ), 107 partialSuffixed!( 108 isDerived, 109 AliasAware!string 110 ), 111 partialSuffixed!( 112 isDerived, 113 FactoryLocator!ObjectFactory 114 ), 115 partialSuffixed!( 116 isDerived, 117 Container 118 ) 119 ), 120 InterfacesTuple!T), 121 Locator!(), 122 MutableDecorator!T, 123 Switchable, 124 ); 125 126 /** 127 Templated switchable decorated. 128 **/ 129 class SwitchableContainer : InheritanceSet { 130 private { 131 T decorated_; 132 133 bool enabled_; 134 } 135 136 public { 137 138 /** 139 Set the state of decorated. 140 141 Set the state of decorated. Whether is enabled or disabled. 142 143 Params: 144 enable = true to enable, false to disable. 145 **/ 146 SwitchableContainer!T enabled(bool enabled) @safe nothrow { 147 this.enabled_ = enabled; 148 149 return this; 150 } 151 152 /** 153 Get the state of decorated (enabled/disabled). 154 155 Get the state of decorated (enabled/disabled). 156 157 Returns: 158 bool true if enabled or false if not. 159 **/ 160 inout(bool) enabled() @safe nothrow inout { 161 return this.enabled_; 162 } 163 164 /** 165 Set the decorated decorated 166 167 Params: 168 decorated = decorated to be decorated 169 170 Returns: 171 SwitchableContainer!T decorating decorated. 172 **/ 173 SwitchableContainer!T decorated(T decorated) @safe nothrow { 174 this.decorated_ = decorated; 175 176 return this; 177 } 178 179 180 /** 181 Get the decorated decorated. 182 183 Get the decorated decorated. 184 185 Returns: 186 inout(T) decorated decorated 187 **/ 188 T decorated() @safe nothrow { 189 return this.decorated_; 190 } 191 192 static if (is(T : Container)) { 193 194 /** 195 Prepare decorated to be used. 196 197 Prepare decorated to be used. 198 199 Returns: 200 SwitchableContainer!T decorating decorated 201 **/ 202 SwitchableContainer instantiate() { 203 if (enabled) { 204 decorated.instantiate(); 205 } 206 207 return this; 208 } 209 } 210 211 static if (is(T : Storage!(ObjectFactory, string))) { 212 /** 213 Set factory in decorated by identity. 214 215 Params: 216 identity = identity of factory. 217 element = factory that is to be saved in decorated. 218 219 Return: 220 SwitchableContainer!T decorating decorated. 221 **/ 222 SwitchableContainer!T set(ObjectFactory element, string identity) { 223 decorated.set(element, identity); 224 225 return this; 226 } 227 228 /** 229 Remove factory from decorated with identity. 230 231 Remove factory from decorated with identity. 232 233 Params: 234 identity = the identity of factory to be removed. 235 236 Return: 237 SwitchableContainer!T decorating decorated 238 **/ 239 SwitchableContainer!T remove(string identity) { 240 decorated.remove(identity); 241 242 return this; 243 } 244 } 245 246 static if (is(T : AliasAware!string)) { 247 /** 248 Alias identity to an alias_. 249 250 Params: 251 identity = originial identity which is to be aliased. 252 alias_ = alias of identity. 253 254 Returns: 255 SwitchableContainer!T decorating decorated 256 **/ 257 SwitchableContainer!T link(string identity, string alias_) { 258 decorated.link(identity, alias_); 259 260 return this; 261 } 262 263 /** 264 Removes alias. 265 266 Params: 267 alias_ = alias to remove. 268 269 Returns: 270 SwitchableContainer!T decorating decorated 271 **/ 272 SwitchableContainer!T unlink(string alias_) { 273 decorated.unlink(alias_); 274 275 return this; 276 } 277 278 /** 279 Resolve an alias to original identity, if possible. 280 281 Params: 282 alias_ = alias of original identity 283 284 Returns: 285 const(string) the last identity in alias chain if decorated is enabled, or alias_ when not. 286 287 **/ 288 const(string) resolve(in string alias_) const { 289 if (enabled) { 290 return decorated_.resolve(alias_); 291 } 292 293 return alias_; 294 } 295 } 296 297 static if (is(T : FactoryLocator!ObjectFactory)) { 298 299 ObjectFactory getFactory(string identity) { 300 return this.decorated.getFactory(identity); 301 } 302 303 InputRange!(Tuple!(ObjectFactory, string)) getFactories() { 304 return this.decorated.getFactories(); 305 } 306 } 307 308 /** 309 Get object that is associated with identity. 310 311 Params: 312 identity = the object identity. 313 314 Throws: 315 NotFoundException in case if the object wasn't found or decorated is not enabled. 316 317 Returns: 318 Object if it is available. 319 **/ 320 Object get(string identity) { 321 if (enabled) { 322 return decorated.get(identity); 323 } 324 325 throw new NotFoundException("Object with id " ~ identity ~ " not found."); 326 } 327 328 /** 329 Check if object is present in SwitchableContainer!T by key identity. 330 331 Note: 332 This check should be done for elements that locator actually contains, and 333 not in chained locator (when locator is also a DelegatingLocator) for example. 334 Params: 335 identity = identity of object. 336 337 Returns: 338 bool true if decorated is enabled and has object by identity. 339 **/ 340 bool has(in string identity) inout { 341 return enabled && decorated_.has(identity); 342 } 343 344 } 345 } 346 }