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 
42 /**
43 Decorating container adding ability to alias contained element a new identity.
44 **/
45 template AliasingContainer(T) {
46     import std.meta;
47     import std.traits;
48     import aermicioi.aedi.util.traits;
49 
50     /**
51     Set which the aliasing decorated will decorate for T. By default
52     Locator!() and Switchable is included.
53     **/
54     alias InheritanceSet = NoDuplicates!(Filter!(
55         templateOr!(
56             partialSuffixed!(
57                 isDerived,
58                 Storage!(ObjectFactory, string)
59             ),
60             partialSuffixed!(
61                 isDerived,
62                 FactoryLocator!ObjectFactory
63             ),
64             partialSuffixed!(
65                 isDerived,
66                 Container
67             )
68         ),
69         InterfacesTuple!T),
70         Locator!(),
71         AliasAware!string,
72         Decorator!Container
73     );
74 
75     /**
76     Templated aliasing decorated.
77     **/
78     @safe class AliasingContainer : InheritanceSet {
79         private {
80             string[const(string)] aliasings;
81         }
82 
83         public {
84             import aermicioi.aedi.storage.decorator : MutableDecoratorMixin;
85             mixin MutableDecoratorMixin!T;
86 
87             alias decorated this;
88 
89             static if (is(T : Container)) {
90                 import aermicioi.aedi.container.container : ContainerMixin;
91                 mixin ContainerMixin!(typeof(this));
92             }
93 
94             static if (is(T : Storage!(ObjectFactory, string))) {
95                 /**
96         		Set factory in decorated by identity.
97 
98         		Params:
99         			identity = identity of factory.
100         			element = factory that is to be saved in decorated.
101 
102         		Return:
103         			AliasingContainer!T decorating decorated.
104         		**/
105                 AliasingContainer!T set(ObjectFactory element, string identity) {
106                     decorated.set(element, identity);
107 
108                     return this;
109                 }
110 
111                 /**
112                 Remove factory from decorated with identity.
113 
114                 Remove factory from decorated with identity.
115 
116                 Params:
117                 	identity = the identity of factory to be removed.
118 
119             	Return:
120             		AliasingContainer!T decorating decorated
121                 **/
122                 AliasingContainer!T remove(string identity) {
123                     decorated.remove(identity);
124 
125                     return this;
126                 }
127             }
128 
129             /**
130             Alias an identity with alias_/
131 
132             Params:
133             	identity = identity which will be aliased
134             	alias_ = the new alias of identity.
135 
136             Returns:
137             	AliasingContainer
138             **/
139             AliasingContainer link(string identity, string alias_) {
140 
141                 this.aliasings[alias_] = identity;
142 
143                 return this;
144             }
145 
146             /**
147             Removes alias.
148 
149             Params:
150             	alias_ = alias to remove.
151 
152             Returns:
153                 this
154 
155             **/
156             AliasingContainer unlink(string alias_) {
157                 this.aliasings.remove(alias_);
158 
159                 return this;
160             }
161 
162             /**
163             Resolve the alias to an element identity.
164 
165             Params:
166             	alias_ = the alias to an identity.
167             Returns:
168             	string the last found identity in alias chain.
169             **/
170             const(string) resolve(in string alias_) const {
171                 string aliased = alias_[];
172 
173                 while ((aliased in this.aliasings) !is null) {
174                     aliased = this.aliasings[aliased][];
175                 }
176 
177                 return aliased;
178             }
179 
180             static if (is(T : FactoryLocator!ObjectFactory)) {
181 
182                 mixin FactoryLocatorMixin!(typeof(this)) DefaultFactoryMixin;
183 
184                 /**
185                 Get factory for constructed component identified by identity.
186 
187                 Get factory for constructed component identified by identity.
188                 Params:
189                 	identity = the identity of component that factory constructs.
190 
191                 Throws:
192                 	NotFoundException when factory for it is not found.
193 
194                 Returns:
195                 	T the factory for constructed component.
196                 **/
197                 ObjectFactory getFactory(string identity) {
198                     return this.decorated.getFactory(this.resolve(identity));
199                 }
200             }
201 
202             /**
203     		Get an Object that is associated with key.
204 
205     		Params:
206     			identity = the element id.
207 
208     		Throws:
209     			NotFoundException in case if the element wasn't found.
210 
211     		Returns:
212     			Object element if it is available.
213     		**/
214             Object get(string identity) {
215                 return decorated.get(this.resolve(identity));
216             }
217 
218             /**
219             Check if an element is present in Locator by key id.
220 
221             Note:
222             	This check should be done for elements that locator actually contains, and
223             	not in chained locator.
224             Params:
225             	identity = identity of element.
226 
227         	Returns:
228         		bool true if an element by key is present in Locator.
229             **/
230             bool has(in string identity) inout {
231                 return decorated_.has(this.resolve(identity));
232             }
233 
234         }
235     }
236 }