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.factory.wrapping_factory;
31 
32 import aermicioi.aedi.factory.factory;
33 import aermicioi.aedi.factory.generic_factory;
34 import aermicioi.aedi.storage.decorator;
35 import aermicioi.aedi.storage.locator;
36 import aermicioi.aedi.storage.wrapper;
37 import std.traits;
38 
39 /**
40 Wraps up the result of some factory in Wrapper object if component is not
41 derived from Object.
42 **/
43 class WrappingFactory(T : Factory!Z, Z) : ObjectFactory, MutableDecorator!T {
44     
45     private {
46         T decorated_;
47     }
48     
49     public {
50 
51         /**
52         Constructor for WrappingFactory!(T, Z)
53         
54         Params: 
55             factory = factory that is wrapped
56         **/
57         this(T factory) {
58             this.decorated = factory;
59         }
60         
61         @property {
62             
63             /**
64             Set the decorated object for decorator.
65             
66             Params:
67                 decorated = decorated data
68             
69             Returns:
70             	this
71             **/
72         	WrappingFactory!(T, Z) decorated(T decorated) @safe nothrow {
73         		this.decorated_ = decorated;
74         	
75         		return this;
76         	}
77         	
78             /**
79             Get the decorated object.
80             
81             Returns:
82             	T decorated object
83             **/
84         	T decorated() @safe nothrow {
85         		return this.decorated_;
86         	}
87         	
88             /**
89     		Get the type info of T that is created.
90     		
91     		Returns:
92     			TypeInfo object of created component.
93     		**/
94         	TypeInfo type() {
95         	    return this.decorated.type;
96         	}
97         	
98             /**
99             Set a locator to object.
100             
101             Params:
102                 locator = the locator that is set to oject.
103             
104             Returns:
105                 LocatorAware.
106             **/
107         	WrappingFactory!T locator(Locator!() locator) {
108         		this.decorated.locator = locator;
109         	
110         		return this;
111         	}
112         	
113         }
114         
115         /**
116 		Instantiates component of type T.
117 		
118 		Returns:
119 			Object instantiated component and probably wrapped if not derived from Object.
120 		**/
121         Object factory() {
122             static if (is(Z : Object)) {
123                 
124                 return this.decorated.factory;
125             } else {
126                 import aermicioi.aedi.storage.wrapper : WrapperImpl;
127                 return new WrapperImpl!Z(this.decorated.factory);
128             }
129         }
130     }
131 }
132 
133 /**
134 Wrapping factory that will wrap the result depending on runtime type information
135 instead of compile time information.
136 **/
137 class RuntimeWrappingFactory(T : Factory!Z, Z) : WrappingFactory!(T) {
138     
139     public {
140         
141         /**
142         Constructor for RuntimeWrappingFactory!(T, Z)
143         
144         Params: 
145             factory = factory that is to be wrapped up in
146         **/
147         this(T factory) {
148             super(factory);
149         }
150         
151         /**
152 		Instantiates component of type T.
153 		
154 		Returns:
155 			Object instantiated component and probably wrapped if not derived from Object.
156 		**/
157         override Object factory() {
158             static if (is(Z == interface) || is(Z == class)) {
159                 if (this.decorated.type.isDerived(typeid(Object))) {
160                     return cast(Object) this.decorated.factory;
161                 }
162             }
163             
164             {
165                 return new WrapperImpl!Z(this.decorated.factory);
166             }
167         }
168     }
169 }
170 
171 /**
172 A factory that coerces an object from object factory to
173 some T type.
174 
175 A factory that coerces an object from object factory to
176 some T type. If T is not rooted in Object class it is
177 assumed by convention that Wrapper!T object is returned
178 by object factory.
179 **/
180 class UnwrappingFactory(T) : Factory!T {
181     
182     private {
183         ObjectFactory decorated_;
184     }
185     
186     public {
187         
188         /**
189         Constructor for UnwrappingFactory
190         
191         Params: 
192             factory = factory from which created components will be coerced to T type if possible
193         **/
194         this(ObjectFactory factory) {
195             this.decorated = factory;
196         }
197         
198         @property {
199             /**
200             Set the decorated object for decorator.
201             
202             Throws:
203                 InvalidCastException when created type of object factory mismatches type of unwrapping factory.
204             
205             Params:
206                 decorated = decorated data
207             
208             Returns:
209             	this
210             **/
211         	UnwrappingFactory!T decorated(ObjectFactory decorated)
212             in {
213                 if (decorated.type != typeid(T)) {
214         	        import aermicioi.aedi.exception.invalid_cast_exception : InvalidCastException;
215         	        
216         	        throw new InvalidCastException(
217                         "Cannot unwrap a type " ~
218                          decorated.type.toString() ~ 
219                          " and cast it to " ~ 
220                          typeid(T).toString()
221                     );
222         	    }
223             }
224             body {
225         		this.decorated_ = decorated;
226         	
227         		return this;
228         	}
229         	
230         	/**
231             Get the decorated object.
232             
233             Returns:
234             	ObjectFactory decorated object
235             **/
236         	ObjectFactory decorated() {
237         		return this.decorated_;
238         	}
239         	
240         	/**
241     		Get the type info of T that is created.
242     		
243     		Returns:
244     			TypeInfo object of created object.
245     		**/
246         	TypeInfo type() {
247         	    return this.decorated.type;
248         	}
249         	
250         	/**
251     		Set a locator to object.
252     		
253     		Params:
254     			locator = the locator that is set to oject.
255     		
256     		Returns:
257     			LocatorAware.
258     		**/
259         	UnwrappingFactory!T locator(Locator!() locator) {
260         	    this.decorated.locator = locator;
261         	    
262         	    return this;
263         	}
264         }
265         
266         /**
267 		Instantiates something of type T.
268 		
269 		Returns:
270 			T instantiated data of type T.
271 		**/
272         T factory() {
273             Object wrapped = this.decorated.factory;
274             
275             static if (is(T : Object)) {
276                 T component = cast(T) wrapped;
277                 
278                 if (component !is null) {
279                     return component;
280                 }
281             } else {
282                 Wrapper!T component = cast(Wrapper!T) wrapped;
283                 
284                 if (component !is null) {
285                     return component;
286                 }
287             }
288             
289             assert(0, "Fatal error, application logic never should reach this region");
290         }
291     }
292 }
293 
294 /**
295 A factory that coerces an object from object factory to
296 some T type.
297 
298 A factory that coerces an object from object factory to
299 some T type. It will attempt as well to safely object to
300 type T if it is possible to prove that created object
301 is a derivation of type T. If T is not rooted in Object 
302 class it is assumed by convention that Wrapper!T object 
303 is returned by object factory.
304 **/
305 class ClassUnwrappingFactory(T) : Factory!T {
306     
307     private {
308         ObjectFactory decorated_;
309     }
310     
311     public {
312 
313         /**
314         Constructor for ClassUnwrappingFactory
315         
316         Params: 
317             factory = factory from which created components will be coerced to T type if possible
318         **/
319         this(ObjectFactory factory) {
320             this.decorated = factory;
321         }
322         
323         @property {
324             /**
325             Set the decorated object for decorator.
326             
327             Throws:
328                 InvalidCastException when created type of object factory mismatches type of unwrapping factory.
329             
330             Params:
331                 decorated = decorated data
332             
333             Returns:
334             	this
335             **/
336         	ClassUnwrappingFactory!T decorated(ObjectFactory decorated)
337             in {
338                 if (!decorated.type.isDerived(typeid(T))) {
339         	        import aermicioi.aedi.exception.invalid_cast_exception;
340         	        
341         	        throw new InvalidCastException("Cannot unwrap a type " ~ decorated.type.toString() ~ " and cast it to " ~ typeid(T).toString());
342         	    }
343             }
344             body {
345         		this.decorated_ = decorated;
346         	
347         		return this;
348         	}
349         	
350         	/**
351             Get the decorated object.
352             
353             Returns:
354             	ObjectFactory decorated object
355             **/
356         	ObjectFactory decorated() {
357         		return this.decorated_;
358         	}
359         	
360         	/**
361     		Get the type info of T that is created.
362     		
363     		Returns:
364     			TypeInfo object of created object.
365     		**/
366         	TypeInfo type() {
367         	    return this.decorated.type;
368         	}
369         	
370         	/**
371     		Set a locator to object.
372     		
373     		Params:
374     			locator = the locator that is set to oject.
375     		
376     		Returns:
377     			LocatorAware.
378     		**/
379         	ClassUnwrappingFactory!T locator(Locator!() locator) {
380         	    this.decorated.locator = locator;
381         	    
382         	    return this;
383         	}
384         }
385         
386         /**
387 		Instantiates something of type T.
388 		
389 		Returns:
390 			T instantiated data of type T.
391 		**/
392         T factory() {
393             Object wrapped = this.decorated.factory;
394             
395             {
396                 static if (is(T : Object)) {
397                     
398                     T component = cast(T) wrapped;
399                     
400                     if (component !is null) {
401                         return component;
402                     }
403                 } 
404             }
405              
406             {
407                 static if (is(T == interface) || is(T == class)) {
408                     
409                     T component = cast(T) wrapped;
410                     
411                     if (component !is null) {
412                         return component;
413                     }
414                 }
415             }
416              
417             Wrapper!T component = cast(Wrapper!T) wrapped;
418             
419             if (component !is null) {
420                 return component;
421             }
422             
423             assert(0, "Fatal error, application logic never should reach this region");
424         }
425     }
426 }
427 
428 private {
429     import std.stdio;
430     
431     bool isDerived(TypeInfo subject, TypeInfo derivation) {
432         if (subject == derivation) {
433             return true;
434         }
435         
436         if ((cast(ClassInfo) subject !is null) && (cast(ClassInfo) derivation !is null)) {
437             return isDerived(cast(ClassInfo) subject, cast(ClassInfo) derivation);
438         }
439         
440         if ((cast(ClassInfo) subject !is null) && (cast(TypeInfo_Interface) derivation !is null)) {
441             return isDerived(cast(ClassInfo) subject, cast(TypeInfo_Interface) derivation);
442         }
443         
444         if ((cast(TypeInfo_Interface) subject !is null) && (cast(TypeInfo_Interface) derivation !is null)) {
445             return isDerived(cast(TypeInfo_Interface) subject, cast(TypeInfo_Interface) derivation);
446         }
447         
448         return false;
449     }
450     
451     bool isDerived(ClassInfo subject, ClassInfo derivation) {
452         if (
453             (subject == derivation) ||
454             (
455                 (subject.base !is null) && 
456                 subject.base.isDerived(derivation)
457             )
458         ) {
459             return true;
460         }
461         
462         foreach (iface; subject.interfaces) {
463             if (iface.classinfo.isDerived(derivation)) {
464                 return true;
465             }
466         }
467         
468         return false;
469     }
470     
471     bool isDerived(ClassInfo subject, TypeInfo_Interface iface) {
472         return subject.isDerived(iface.info);
473     }
474     
475     bool isDerived(TypeInfo_Interface subject, TypeInfo_Interface iface) {
476         return subject.info.isDerived(iface.info);
477     }
478 }