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.locator;
37 import aermicioi.aedi.storage.decorator;
38 import std.traits;
39 import std.typecons;
40 import std.range;
41 import std.algorithm;
42 import std.meta;
43 
44 import aermicioi.util.traits;
45 
46 /**
47 Creates a proxy to an object or interface of type T,
48 that is located in source locator by some identity.
49 **/
50 class ProxyFactory(T) : Factory!T
51     if (
52         (
53             is(T == class) && 
54             !isFinalClass!T &&
55             !isAbstractClass!T
56         ) ||
57         (is(T == interface))
58     ) {
59     
60     private {
61         string identity_;
62         Locator!() source_;
63     }
64     
65     public {
66         
67         this(string identity, Locator!() original) {
68             this.identity = identity;
69             this.source = source;
70         }
71         
72         T factory() {
73             auto proxy = new Proxy!T;
74             proxy.__id__ = this.identity;
75             proxy.__locator__ = this.source;
76             
77             return proxy;
78         }
79         
80         @property {
81             /**
82             Set the identity of proxied object
83 
84             Params:
85             	identity = the identity of proxied object
86             
87             Returns:
88             	this
89             **/
90             ProxyFactory!T identity(string identity) {
91             	this.identity_ = identity;
92             
93             	return this;
94             }
95             
96             /**
97             Get the identity of proxied object.
98             
99             Returns:
100             	string identity
101             **/
102             string identity() {
103             	return this.identity_;
104             }
105             
106             /**
107             Set the source of proxied object.
108             
109             Params:
110             	source = source locator where proxied object resides.
111             
112             Returns:
113             	this
114             **/
115             ProxyFactory!T source(Locator!() source) {
116             	this.source_ = source;
117             
118             	return this;
119             }
120             
121             /**
122             Get the source of proxied object.
123             
124             Returns:
125             	Locator!() source
126             **/
127             Locator!() source() {
128             	return this.source_;
129             }
130         }
131     }
132 }
133 
134 /**
135 Auto implements a proxy for object or interface of type T which
136 is not a final or abstract class.
137 
138 Warning:
139     Current implmentation uses AutoImplement from phobos which
140     has some unfixed bugs.
141 **/
142 template ProxyImpl(T)
143     if (
144         (
145             is(T == class) && 
146             !isFinalClass!T &&
147             !isAbstractClass!T
148         ) ||
149         is(T == interface)
150     ) {
151     
152     static class ProxyImpl : T {
153         private {
154         
155             Locator!() __locator_;
156             string __id_;
157         }
158         
159         public {
160             
161             this() {
162                 super();
163             }
164         }
165         
166         @property public {
167             ProxyImpl __locator__(Locator!() locator) @safe nothrow @nogc {
168             	this.__locator_ = locator;
169             
170             	return this;
171             }
172             
173             Locator!() __locator__() @safe nothrow @nogc {
174             	return this.__locator_;
175             }
176             
177             ProxyImpl __id__(string id) @safe nothrow @nogc {
178             	this.__id_ = id;
179             
180             	return this;
181             }
182             
183             string __id__() @safe nothrow @nogc {
184             	return this.__id_;
185             }
186         }
187     }
188 }
189 
190 template how(T) {
191     static string how(C, alias fun)() {
192         string stmt = "
193             import aermicioi.aedi.storage.locator;
194             import aermicioi.aedi.exception.di_exception;
195             import aermicioi.aedi.factory.proxy_factory;
196         " ~  identifier!C ~ " original;
197             try {
198                 original = this.__locator__.locate!(" ~ fullyQualifiedName!T ~ ")(this.__id__);
199             } catch (AediException e) {
200                 assert(false, \"Failed to fetch \" ~ __id__ ~ \" in proxy object.\");
201             }
202         ";
203             
204         static if (!is(ReturnType!fun == void)) {
205             stmt ~= "
206                 return original." ~ __traits(identifier, fun) ~ "(args);
207             ";
208         } else {
209             stmt ~= "
210                 original." ~ __traits(identifier, fun) ~ "(args);
211             ";
212         }
213         
214         return stmt;
215     }
216 }
217     
218 alias Proxy(T) = AutoImplement!(ProxyImpl!T, how!T, templateAnd!(
219         templateNot!isFinalFunction
220 ));
221     
222 /**
223 A ProxyObjectFactory instantiates a proxy to some type of object located in source locator.
224 **/
225 interface ProxyObjectFactory : ObjectFactory {
226     
227     @property {
228         
229         /**
230         Get the identity of original object that proxy factory will intantiate proxy object.
231         
232         Returns:
233         	string the original object identity
234         **/
235         string identity() @safe nothrow;
236         
237         /**
238         Get the original locator that is used by proxy to fetch the proxied object.
239         
240         Returns:
241         	Locator!() original locator containing the proxied object.
242         **/
243         Locator!() source() @safe nothrow;
244     }
245 }
246 
247 class ProxyObjectWrappingFactory(T) : ProxyObjectFactory, MutableDecorator!(Factory!T)
248     if (is(T : Object) && !isFinalClass!T) {
249     
250     private {
251         ProxyFactory!T decorated_;
252         
253         string identity_;
254         Locator!() source_;
255         Locator!() locator_;
256     }
257     
258     public {
259         this(ProxyFactory!T factory) {
260             this.decorated = factory;
261         }
262         
263         @property {
264             ProxyObjectWrappingFactory!T identity(string identity) @safe nothrow {
265             	this.identity_ = identity;
266             
267             	return this;
268             }
269             
270             string identity() @safe nothrow {
271             	return this.identity_;
272             }
273             
274             ProxyObjectWrappingFactory!T source(Locator!() source) @safe nothrow {
275             	this.source_ = source;
276             
277             	return this;
278             }
279             
280             Locator!() source() @safe nothrow {
281             	return this.source_;
282             }
283             
284             ProxyObjectWrappingFactory!T decorated(ProxyFactory!T decorated) @safe nothrow {
285             	this.decorated_ = decorated;
286             
287             	return this;
288             }
289             
290             ProxyFactory!T decorated() @safe nothrow {
291             	return this.decorated_;
292             }
293             
294             ProxyObjectWrappingFactory!T locator(Locator!() locator) @safe nothrow {
295             	this.locator_ = locator;
296             
297             	return this;
298             }
299             
300             Locator!() locator() @safe nothrow {
301             	return this.locator_;
302             }
303             
304             TypeInfo type() {
305                 return this.decorated.type;
306             }
307         }
308         
309         Object factory() {
310             return this.decorated.factory();
311         }
312     }
313 }