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