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