1 /**
2 Contains primitives related to reference resolving during construction of data
3 (objects, structs, basic types, etc.).
4 
5 License:
6 	Boost Software License - Version 1.0 - August 17th, 2003
7 
8 	Permission is hereby granted, free of charge, to any person or organization
9 	obtaining a copy of the software and accompanying documentation covered by
10 	this license (the "Software") to use, reproduce, display, distribute,
11 	execute, and transmit the Software, and to prepare derivative works of the
12 	Software, and to permit third-parties to whom the Software is furnished to
13 	do so, all subject to the following:
14 	
15 	The copyright notices in the Software and this entire statement, including
16 	the above license grant, this restriction and the following disclaimer,
17 	must be included in all copies of the Software, in whole or in part, and
18 	all derivative works of the Software, unless such copies or derivative
19 	works are solely in the form of machine-executable object code generated by
20 	a source language processor.
21 	
22 	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 	FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
25 	SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
26 	FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
27 	ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 	DEALINGS IN THE SOFTWARE.
29 
30 Authors:
31 	aermicioi
32 **/
33 module aermicioi.aedi.factory.reference;
34 
35 import aermicioi.aedi.exception.invalid_cast_exception;
36 import aermicioi.aedi.factory.factory;
37 import aermicioi.aedi.storage.locator;
38 import aermicioi.aedi.storage.wrapper;
39 import std.traits;
40 
41 /**
42 Represents a reference that some data is dependent on it.
43 
44 Represents a reference that some data is dependent on it. 
45 It will resolve itself to the referenced data, that is
46 subclass of Object, or data that is encapsulated in Wrapper object.
47 **/
48 interface RuntimeReference {
49     
50     /**
51     Resolve the reference, to referenced data.
52     
53     Resolve the reference, to referenced data.
54     
55     Params:
56     	locator = an optional source of data used to resolve reference
57     
58     Returns:
59     	Object the actual object, or data that is wrapped in Wrapper object.
60     **/
61     Object get(Locator!() locator);
62 }
63 
64 /**
65 Represents a reference that is located in locator.
66 
67 Represents a reference that is located in locator.
68 It uses referenced data's identity in locator to
69 find it and serve.
70 **/
71 class LocatorReference : RuntimeReference {
72     private {
73         string identity_;
74     }
75     
76     public {
77         /**
78         Constructor for LocatorReference
79         
80         Params: 
81             id = identity of component that is referenced
82         **/
83         this(string id) {
84             this.identity = id;
85         }
86         
87         @property {
88             
89             /**
90             Set the identity of referenced data.
91             
92             Set the identity of referenced data.
93             Description
94             
95             Params:
96             	identity = the identity of referenced data.
97             
98             Returns:
99             	this
100             **/
101         	LocatorReference identity(string identity) @safe nothrow {
102         		this.identity_ = identity;
103         	
104         		return this;
105         	}
106         	
107         	/**
108         	Get the identity of referenced data.
109         	
110         	Get the identity of referenced data.
111         	
112         	Returns:
113         		string the identity of referenced data
114         	**/
115         	string identity() @safe nothrow {
116         		return this.identity_;
117         	}
118         }
119         
120         /**
121         Resolve the reference, to referenced data.
122         
123         Resolve the reference, to referenced data.
124         
125         Params:
126             locator = an optional source of data used to resolve reference
127         
128         Returns:
129             Object the actual object, or data that is wrapped in Wrapper object.
130         **/
131         Object get(Locator!() locator) {
132             return locator.get(this.identity);
133         }
134     }
135 }
136 
137 /**
138 ditto
139 **/
140 auto lref(string id) {
141     return new LocatorReference(id);
142 }
143 
144 /**
145 ditto
146 **/
147 auto lref(string name)() {
148     return name.lref;
149 }
150 
151 /**
152 Reference to a component stored in a locator by it's type.
153 **/
154 class TypeLocatorReference(T) : RuntimeReference {
155     
156     public {
157         /**
158         Resolve the reference, to referenced data.
159         
160         Resolve the reference, to referenced data.
161         
162         Params:
163             locator = an optional source of data used to resolve reference
164         
165         Returns:
166             Object the actual object, or data that is wrapped in Wrapper object.
167         **/
168         Object get(Locator!() locator) {
169             auto type = typeid(T);
170             
171             if (locator.has(type.toString())) {
172                 
173                 return locator.get(type.toString());
174             } else {
175                 
176                 return locator.get(fullyQualifiedName!T);
177             }
178         }
179     }
180 }
181 
182 /**
183 ditto
184 **/
185 auto lref(T)() {
186     return new TypeLocatorReference!T;
187 }
188 
189 /**
190 Represents a reference to data yet to be constructed.
191 
192 Represents a reference to data yet to be constructed.
193 It will instantiate the referenced data using an object
194 factory, and will serve it to requestor.
195 **/
196 class AnonymousFactoryReference : RuntimeReference {
197 
198     private {
199         ObjectFactory factory_;
200     }
201     
202     public {
203         @property {
204             /**
205             Set factory
206             
207             Params: 
208                 factory = factory used by anonymous reference to create component
209             Returns:
210                 typeof(this)
211             **/
212         	AnonymousFactoryReference factory(ObjectFactory factory) @safe nothrow {
213         		this.factory_ = factory;
214         	
215         		return this;
216         	}
217         	
218             /**
219             Get factory
220             
221             Returns:
222                 ObjectFactory
223             **/
224         	ObjectFactory factory() @safe nothrow {
225         		return this.factory_;
226         	}
227         }
228         
229         /**
230         Resolve the reference, to referenced data.
231         
232         Resolve the reference, to referenced data.
233         
234         Params:
235             locator = an optional source of data used to resolve reference
236         
237         Returns:
238             Object the actual object, or data that is wrapped in Wrapper object.
239         **/
240         Object get(Locator!() locator) {
241             return this.factory.factory;
242         }
243     }
244 }
245 
246 /**
247 ditto
248 **/
249 auto anonymous(T : Factory!X, X)(T factory) {
250     import aermicioi.aedi.factory.wrapping_factory : WrappingFactory;
251     return anonymous(new WrappingFactory!T(factory));
252 }
253 
254 /**
255 ditto
256 **/
257 auto anonymous(ObjectFactory factory) {
258     auto anonymous = new AnonymousFactoryReference();
259     anonymous.factory = factory;
260     
261     return anonymous;
262 }
263 
264 /**
265 Resolve a reference, and attempt to convert to data of type T.
266 
267 Resolve a reference, and attempt to convert to data of type T.
268 
269 Params:
270 	T = the expected type of resolved data.
271 	locator = optional source of data for resolving reference
272 
273 Throws:
274 	InvalidCastException when resolved data is not of expected type.
275 
276 Returns:
277 	T referenced object
278 	Wrapper!T referenced data that is not of Object subclass.
279 **/
280 auto resolve(T : Object)(RuntimeReference reference, Locator!() locator)
281 body {
282     T result = cast(T) reference.get(locator);
283     
284     if (result !is null) {
285         return result;
286     }
287     
288     throw new InvalidCastException(
289         "Resolved runtime reference " ~ 
290         typeid(reference.get(locator)).toString() ~ 
291         " is not of expected type: " ~ 
292         fullyQualifiedName!T
293     );
294 }
295 
296 /**
297 ditto
298 **/
299 auto resolve(T)(RuntimeReference reference, Locator!() locator)
300     if (is(T == interface)) {
301     
302     Object obj = reference.get(locator);
303     {
304         T result = cast(T) obj;
305         
306         if (result !is null) {
307             return result;
308         }
309     }
310     
311     {
312         Wrapper!T result = cast(Wrapper!T) obj;
313         
314         if (result !is null) {
315             return result;
316         }
317     }
318     
319     throw new InvalidCastException(
320         "Resolved runtime reference " ~ 
321         typeid(reference.get(locator)).toString() ~ 
322         " is not of expected type: " ~ 
323         fullyQualifiedName!T
324         );
325 }
326 
327 /**
328 ditto
329 **/
330 auto resolve(T)(RuntimeReference reference, Locator!() locator)
331     if (!is(T == interface)) {
332     
333     Wrapper!T result = cast(Wrapper!T) reference.get(locator);
334     
335     if (result !is null) {
336         return result;
337     }
338     
339     throw new InvalidCastException(
340         "Resolved runtime reference " ~ 
341         typeid(reference.get(locator)).toString() ~ 
342         " is not of expected type: " ~ 
343         fullyQualifiedName!T
344         );
345 }
346 
347 /**
348 ditto
349 **/
350 auto ref Z resolve(T, Z)(auto ref Z reference, Locator!() locator)
351     if (!is(Z : RuntimeReference)) {
352     return reference; 
353 }
354 
355 /**
356 Alias to fullyQualifiedName from std.traits, for shorter notation.
357 **/
358 template name(alias T)
359     if (is(typeof(T))) {
360     alias name = fullyQualifiedName!(typeof(T));
361 }
362 
363 /**
364 ditto
365 **/
366 template name(T) {
367     alias name = fullyQualifiedName!T;
368 }
369 
370 /**
371 Convert a type into a locator reference by type's name.
372 **/
373 template toLref(Type) {
374     auto toLref() {
375         return name!Type.lref;
376     }
377 }
378 
379 /**
380 ditto
381 **/
382 template toLrefType(Type) {
383     alias toLrefType = LocatorReference;
384 }