1 /** 2 Contains factories and primitives used for building proxy objects. 3 4 License: 5 Boost Software License - Version 1.0 - August 17th, 2003 6 7 Permission is hereby granted, free of charge, to any person or organization 8 obtaining a copy of the software and accompanying documentation covered by 9 this license (the "Software") to use, reproduce, display, distribute, 10 execute, and transmit the Software, and to prepare derivative works of the 11 Software, and to permit third-parties to whom the Software is furnished to 12 do so, all subject to the following: 13 14 The copyright notices in the Software and this entire statement, including 15 the above license grant, this restriction and the following disclaimer, 16 must be included in all copies of the Software, in whole or in part, and 17 all derivative works of the Software, unless such copies or derivative 18 works are solely in the form of machine-executable object code generated by 19 a source language processor. 20 21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 24 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 25 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 26 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 27 DEALINGS IN THE SOFTWARE. 28 29 Authors: 30 aermicioi 31 **/ 32 module aermicioi.aedi.factory.proxy_factory; 33 34 import aermicioi.aedi.factory.factory; 35 import aermicioi.aedi.factory.generic_factory; 36 import aermicioi.aedi.storage.decorator; 37 import aermicioi.aedi.storage.locator; 38 import aermicioi.aedi.storage.locator_aware; 39 40 import aermicioi.util.traits; 41 42 import std.algorithm; 43 import std.meta; 44 import std.range; 45 import std.traits; 46 import std.typecons; 47 48 49 /** 50 Creates a proxy to an object or interface of type T, 51 that is located in source locator by some identity. 52 **/ 53 class ProxyFactory(T) : Factory!T 54 if ( 55 ( 56 is(T == class) && 57 !isFinalClass!T && 58 !isAbstractClass!T 59 ) || 60 (is(T == interface)) 61 ) { 62 63 private { 64 string identity_; 65 Locator!() source_; 66 } 67 68 public { 69 /** 70 Constructor for ProxyFactory!(T) 71 72 Params: 73 identity = identity of original object stored in a locator 74 original = locator that contains original object that a proxy should proxy. 75 **/ 76 this(string identity, Locator!() original) { 77 this.identity = identity; 78 this.source = original; 79 } 80 81 /** 82 Instantiates component of type T. 83 84 Returns: 85 T instantiated data of type T. 86 **/ 87 T factory() { 88 auto proxy = new Proxy!T; 89 proxy.__id__ = this.identity; 90 proxy.__locator__ = this.source; 91 92 return proxy; 93 } 94 95 @property { 96 /** 97 Set the identity of proxied object 98 99 Params: 100 identity = the identity of proxied object 101 102 Returns: 103 this 104 **/ 105 ProxyFactory!T identity(string identity) @safe nothrow { 106 this.identity_ = identity; 107 108 return this; 109 } 110 111 /** 112 Get the identity of proxied object. 113 114 Returns: 115 string identity 116 **/ 117 string identity() @safe nothrow { 118 return this.identity_; 119 } 120 121 /** 122 Set the source of proxied object. 123 124 Params: 125 source = source locator where proxied object resides. 126 127 Returns: 128 this 129 **/ 130 ProxyFactory!T source(Locator!() source) @safe nothrow { 131 this.source_ = source; 132 133 return this; 134 } 135 136 /** 137 Get the source of proxied object. 138 139 Returns: 140 Locator!() source 141 **/ 142 Locator!() source() @safe nothrow { 143 return this.source_; 144 } 145 146 /** 147 Set locator 148 149 Params: 150 locator = locator or source of original component proxied by proxy 151 Returns: 152 typeof(this) 153 **/ 154 LocatorAware!(Object, string) locator(Locator!(Object, string) locator) @safe nothrow { 155 this.source = locator; 156 157 return this; 158 } 159 160 /** 161 Get locator 162 163 Returns: 164 Locator!() 165 **/ 166 Locator!() locator() @safe nothrow { 167 return this.source; 168 } 169 170 /** 171 Get the type info of T that is created. 172 173 Returns: 174 TypeInfo object of created component. 175 **/ 176 TypeInfo type() @safe nothrow { 177 return typeid(Proxy!T); 178 } 179 180 } 181 } 182 } 183 184 /** 185 Auto implements a proxy for object or interface of type T which 186 is not a final or abstract class. 187 188 Warning: 189 Current implmentation uses AutoImplement from phobos which 190 has some unfixed bugs. 191 **/ 192 template ProxyImpl(T) 193 if ( 194 ( 195 is(T == class) && 196 !isFinalClass!T && 197 !isAbstractClass!T 198 ) || 199 is(T == interface) 200 ) { 201 202 static class ProxyImpl : T { 203 private { 204 205 Locator!() __locator_; 206 string __id_; 207 } 208 209 public { 210 211 this() { 212 super(); 213 } 214 } 215 216 @property public { 217 ProxyImpl!T __locator__(Locator!() locator) @safe nothrow @nogc { 218 this.__locator_ = locator; 219 220 return this; 221 } 222 223 Locator!() __locator__() @safe nothrow @nogc { 224 return this.__locator_; 225 } 226 227 ProxyImpl!T __id__(string id) @safe nothrow @nogc { 228 this.__id_ = id; 229 230 return this; 231 } 232 233 string __id__() @safe nothrow @nogc { 234 return this.__id_; 235 } 236 } 237 } 238 } 239 240 template how(T) { 241 static string how(C, alias fun)() { 242 static if (identifier!fun == "__ctor") { 243 pragma(msg, "here"); 244 return q{super(args)}; 245 } static if (identifier!fun == "__dtor") { 246 return q{}; 247 } else { 248 249 string stmt = q{ 250 import aermicioi.aedi.storage.locator; 251 import aermicioi.aedi.exception.di_exception; 252 import aermicioi.aedi.factory.proxy_factory; 253 } ~ fullyQualifiedName!T ~ " original; 254 try { 255 original = this.__locator__.locate!(" ~ fullyQualifiedName!T ~ ")(this.__id__); 256 } catch (Exception e) { 257 assert(false, \"Failed to fetch \" ~ __id__ ~ \" in proxy object.\"); 258 } 259 "; 260 261 static if (!is(ReturnType!fun == void)) { 262 stmt ~= " 263 return original." ~ __traits(identifier, fun) ~ "(args); 264 "; 265 } else { 266 stmt ~= " 267 original." ~ __traits(identifier, fun) ~ "(args); 268 "; 269 } 270 271 return stmt; 272 } 273 274 } 275 } 276 277 alias Proxy(T) = AutoImplement!(ProxyImpl!T, how!T, templateAnd!( 278 templateNot!isFinalFunction 279 )); 280 281 /** 282 A ProxyObjectFactory instantiates a proxy to some type of object located in source locator. 283 **/ 284 interface ProxyObjectFactory : ObjectFactory { 285 286 @property { 287 288 /** 289 Get the identity of original object that proxy factory will intantiate proxy object. 290 291 Returns: 292 string the original object identity 293 **/ 294 string identity() @safe nothrow; 295 296 /** 297 Get the original locator that is used by proxy to fetch the proxied object. 298 299 Returns: 300 Locator!() original locator containing the proxied object. 301 **/ 302 Locator!() source() @safe nothrow; 303 } 304 } 305 306 /** 307 Proxy factory decorator, that conforms to requirements of a container, exposing as well the ability 308 to set proxied object's identity and locator. 309 **/ 310 class ProxyObjectWrappingFactory(T) : ProxyObjectFactory, MutableDecorator!(ProxyFactory!T) 311 if (is(T : Object) && !isFinalClass!T) { 312 313 private { 314 ProxyFactory!T decorated_; 315 316 } 317 318 public { 319 320 /** 321 Constructor for ProxyObjectWrappingFactory!T 322 323 Params: 324 factory = proxy factory that is decorated 325 **/ 326 this(ProxyFactory!T factory) { 327 this.decorated = factory; 328 } 329 330 @property { 331 /** 332 Get the identity of original object that proxy factory will intantiate proxy object. 333 334 Returns: 335 string the original object identity 336 **/ 337 ProxyObjectWrappingFactory!T identity(string identity) @safe nothrow { 338 this.decorated.identity = identity; 339 340 return this; 341 } 342 343 /** 344 Get identity 345 346 Returns: 347 string 348 **/ 349 string identity() @safe nothrow { 350 return this.decorated.identity; 351 } 352 353 /** 354 Get the original locator that is used by proxy to fetch the proxied object. 355 356 Returns: 357 Locator!() original locator containing the proxied object. 358 **/ 359 ProxyObjectWrappingFactory!T source(Locator!() source) @safe nothrow { 360 this.decorated.source = source; 361 362 return this; 363 } 364 365 /** 366 Get source 367 368 Returns: 369 Locator!() 370 **/ 371 Locator!() source() @safe nothrow { 372 return this.decorated.source; 373 } 374 375 /** 376 Set the decorated object for decorator. 377 378 Params: 379 decorated = decorated data 380 381 Returns: 382 this 383 **/ 384 ProxyObjectWrappingFactory!T decorated(ProxyFactory!T decorated) @safe nothrow { 385 this.decorated_ = decorated; 386 387 return this; 388 } 389 390 /** 391 Get the decorated object. 392 393 Returns: 394 T decorated object 395 **/ 396 ProxyFactory!T decorated() @safe nothrow { 397 return this.decorated_; 398 } 399 400 /** 401 Set a locator to object. 402 403 Params: 404 locator = the locator that is set to oject. 405 406 Returns: 407 LocatorAware. 408 **/ 409 ProxyObjectWrappingFactory!T locator(Locator!() locator) @safe nothrow { 410 this.decorated.locator = locator; 411 412 return this; 413 } 414 415 /** 416 Get locator 417 418 Returns: 419 Locator!() 420 **/ 421 Locator!() locator() @safe nothrow { 422 return this.decorated.locator; 423 } 424 425 /** 426 Get the type info of T that is created. 427 428 Returns: 429 TypeInfo object of created component. 430 **/ 431 TypeInfo type() { 432 return this.decorated.type; 433 } 434 } 435 /** 436 Instantiates component of type Object. 437 438 Returns: 439 Object instantiated component. 440 **/ 441 Object factory() { 442 return this.decorated.factory(); 443 } 444 } 445 }