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 }