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.container.aliasing_container;
31 
32 import aermicioi.aedi.container.container;
33 import aermicioi.aedi.storage.storage;
34 import aermicioi.aedi.storage.locator;
35 import aermicioi.aedi.storage.decorator;
36 import aermicioi.aedi.factory.factory;
37 import aermicioi.aedi.exception.not_found_exception;
38 import aermicioi.aedi.storage.alias_aware;
39 
40 import std.range.interfaces;
41 import std.typecons;
42 
43 /**
44 Decorating container adding ability to alias contained element a new identity.
45 **/
46 template AliasingContainer(T) {
47     import std.meta;
48     import std.traits;
49     import aermicioi.util.traits;
50     
51     /**
52     Set which the aliasing decorated will decorate for T. By default
53     Locator!() and Switchable is included.
54     **/
55     alias InheritanceSet = NoDuplicates!(Filter!(
56         templateOr!(
57             partialSuffixed!(
58                 isDerived,
59                 Storage!(ObjectFactory, string)
60             ),
61             partialSuffixed!(
62                 isDerived,
63                 FactoryLocator!ObjectFactory
64             ),
65             partialSuffixed!(
66                 isDerived,
67                 Container
68             )
69         ),
70         InterfacesTuple!T),
71         Locator!(),
72         AliasAware!string,
73         MutableDecorator!T,
74     );
75 
76     /**
77     Templated aliasing decorated.
78     **/
79     class AliasingContainer : InheritanceSet {
80         private {
81             T decorated_;
82             
83             string[const(string)] aliasings;
84         }
85         
86         public {
87             @property {
88                 
89                 /**
90                 Set the decorated decorated
91                 
92                 Params:
93                     decorated = decorated to be decorated
94                     
95                 Returns:
96                     AliasingContainer!T decorating decorated.
97                 **/
98                 AliasingContainer!T decorated(T decorated) @safe nothrow {
99                 	this.decorated_ = decorated;
100                 
101                 	return this;
102                 }
103                 
104                 
105                 /**
106                 Get the decorated decorated.
107                 
108                 Get the decorated decorated.
109                 
110                 Returns:
111                 	T decorated decorated
112                 **/
113                 T decorated() @safe nothrow {
114                 	return this.decorated_;
115                 }
116             }
117             
118             alias decorated this;
119             
120             static if (is(T : Container)) {
121                 
122                 /**
123                 Prepare decorated to be used.
124                 
125                 Prepare decorated to be used.
126 
127                 Returns:
128                 	AliasingContainer!T decorating decorated
129                 **/
130                 AliasingContainer instantiate() {
131                     this.decorated.instantiate();
132                     
133                     return this;
134                 } 
135             }
136             
137             static if (is(T : Storage!(ObjectFactory, string))) {
138                 /**
139         		Set factory in decorated by identity.
140         		
141         		Params:
142         			identity = identity of factory.
143         			element = factory that is to be saved in decorated.
144         			
145         		Return:
146         			AliasingContainer!T decorating decorated.
147         		**/
148                 AliasingContainer!T set(ObjectFactory element, string identity) {
149                     decorated.set(element, identity);
150                     
151                     return this;
152                 }
153                 
154                 /**
155                 Remove factory from decorated with identity.
156                 
157                 Remove factory from decorated with identity. 
158                 
159                 Params:
160                 	identity = the identity of factory to be removed.
161                 	
162             	Return:
163             		AliasingContainer!T decorating decorated
164                 **/
165                 AliasingContainer!T remove(string identity) {
166                     decorated.remove(identity);
167                     
168                     return this;
169                 }
170             }
171             
172             /**
173             Alias an identity with alias_/
174             
175             Params:
176             	identity = identity which will be aliased
177             	alias_ = the new alias of identity.
178             
179             Returns:
180             	AliasingContainer
181             **/
182             AliasingContainer link(string identity, string alias_) {
183                 
184                 this.aliasings[alias_] = identity;
185                 
186                 return this;
187             }
188             
189             /**
190             Removes alias.
191             
192             Params:
193             	alias_ = alias to remove.
194     
195             Returns:
196                 this
197             	
198             **/
199             AliasingContainer unlink(string alias_) {
200                 this.aliasings.remove(alias_);
201                 
202                 return this;
203             }
204             
205             /**
206             Resolve the alias to an element identity.
207             
208             Params:
209             	alias_ = the alias to an identity.
210             Returns:
211             	string the last found identity in alias chain.
212             **/
213             const(string) resolve(in string alias_) const {
214                 import std.typecons : Rebindable;
215                 Rebindable!(const(string)) aliased = alias_;
216                 
217                 while ((aliased in this.aliasings) !is null) {
218                     aliased = this.aliasings[aliased];
219                 }
220                 
221                 return aliased;
222             }
223             
224             static if (is(T : FactoryLocator!ObjectFactory)) {
225                 
226                 /**
227                 Get factory for constructed data identified by identity.
228                 
229                 Get factory for constructed data identified by identity.
230                 Params:
231                 	identity = the identity of data that factory constructs.
232                 
233                 Throws:
234                 	NotFoundException when factory for it is not found.
235                 
236                 Returns:
237                 	T the factory for constructed data.
238                 **/
239                 ObjectFactory getFactory(string identity) {
240                     return this.decorated.getFactory(this.resolve(identity));
241                 }
242                 
243                 /**
244                 Get all factories available in container.
245                 
246                 Get all factories available in container.
247                 
248                 Returns:
249                 	InputRange!(Tuple!(T, string)) a tuple of factory => identity.
250                 **/
251                 InputRange!(Tuple!(ObjectFactory, string)) getFactories() {
252                     return this.decorated.getFactories();
253                 }
254             }
255             
256             /**
257     		Get an Object that is associated with key.
258     		
259     		Params:
260     			identity = the element id.
261     			
262     		Throws:
263     			NotFoundException in case if the element wasn't found.
264     		
265     		Returns:
266     			Object element if it is available.
267     		**/
268             Object get(string identity) {
269                 return decorated.get(this.resolve(identity));
270             }
271             
272             /**
273             Check if an element is present in Locator by key id.
274             
275             Note:
276             	This check should be done for elements that locator actually contains, and
277             	not in chained locator.
278             Params:
279             	identity = identity of element.
280             	
281         	Returns:
282         		bool true if an element by key is present in Locator.
283             **/
284             bool has(in string identity) inout {
285                 return decorated_.has(this.resolve(identity));
286             }
287             
288         }
289     }
290 }