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