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),
51     Decorator!(Locator!())
52 {
53 
54 }
55 
56 /**
57 Templated switchable container.
58 
59 Templated switchable container. This container will
60 decorate another container, and add switching logic 
61 to it. Depending in which state (on/off) the switching 
62 container is. It will instantiate if the container is on, 
63 and not if container is in off mode. This container will
64 inherit following interfaces only and only if the 
65 T also implements them:
66     $(OL
67         $(LI Storage!(ObjectFactory, string))
68         $(LI Container)
69         $(LI AliasAware!string)
70     )
71 
72 Params:
73     T = The container that switchable container will decorate.
74    
75 **/
76 template ProxyContainerImpl(T)
77 {
78     /**
79     Set which the switchable container will decorate for T. By default
80     Locator!() and Switchable is included.
81     **/
82     alias InheritanceSet = 
83         NoDuplicates!(
84             Filter!(
85                 templateOr!(
86                     partialSuffixed!(
87                         isDerived,
88                         Storage!(ObjectFactory,
89                         string)
90                     ), 
91                     partialSuffixed!(
92                         isDerived, 
93                         AliasAware!string
94                     ),
95                     partialSuffixed!(
96                         isDerived, 
97                         FactoryLocator!ObjectFactory
98                     )
99                 ),
100                 InterfacesTuple!T
101             ),
102             ProxyContainer, 
103             MutableDecorator!T
104         );
105 
106     /**
107     Templated proxy container.
108     **/
109     class ProxyContainerImpl : InheritanceSet
110     {
111         private
112         {
113             T decorated_;
114 
115             ObjectStorage!(ProxyObjectFactory, string) proxyFactories;
116         }
117 
118         public
119         {
120 
121             /**
122              * Default constructor for ProxyContainerImpl
123             **/
124             this() {
125 
126                 this.proxyFactories = new ObjectStorage!(ProxyObjectFactory, string);
127             }
128 
129             @property
130             {
131                 /**
132                 Set the decorated object for decorator.
133                 
134                 Params:
135                     decorated = decorated data
136                 
137                 Returns:
138                     typeof(this)
139                 **/
140                 ProxyContainerImpl decorated(T decorated) @safe nothrow
141                 {
142                     this.decorated_ = decorated;
143 
144                     return this;
145                 }
146 
147                 /**
148                 Get the decorated object.
149                 
150                 Returns:
151                     T decorated object
152                 **/
153                 T decorated() @safe nothrow
154                 {
155                     return this.decorated_;
156                 }
157             }
158 
159             /**
160             * Set object factory
161             * 
162             * Params: 
163             * 	factory = factory for a object that is to be managed by prototype container.
164             *   identity = identity by which a factory is identified
165             * Returns:
166             * 	typeof(this)
167             **/
168             ProxyContainerImpl set(ProxyObjectFactory factory, string identity)
169             {
170                 this.proxyFactories.set(factory, identity);
171 
172                 return this;
173             }
174 
175             static if (is(T : Container))
176             {
177 
178                 /**
179                 Prepare container to be used.
180                 
181                 Prepare container to be used.
182 
183                 Returns:
184                 	ProxyContainer decorating container
185                 **/
186                 ProxyContainerImpl instantiate()
187                 {
188                     decorated.instantiate();
189 
190                     return this;
191                 }
192             }
193 
194             static if (is(T : Storage!(ObjectFactory, string)))
195             {
196                 /**
197         		Set factory in container by identity.
198         		
199         		Params:
200         			identity = identity of factory.
201         			element = factory that is to be saved in container.
202         			
203         		Return:
204         			ProxyContainer decorating container.
205         		**/
206                 ProxyContainerImpl set(ObjectFactory element, string identity)
207                 {
208                     decorated.set(element, identity);
209 
210                     return this;
211                 }
212 
213                 /**
214                 Remove factory from container with identity.
215                 
216                 Remove factory from container with identity. 
217                 
218                 Params:
219                 	identity = the identity of factory to be removed.
220                 	
221             	Return:
222             		ProxyContainer decorating container
223                 **/
224                 ProxyContainerImpl remove(string identity)
225                 {
226                     this.decorated.remove(identity);
227                     this.proxyFactories.remove(identity);
228 
229                     return this;
230                 }
231             }
232             else
233             {
234                 /**
235                 Remove factory from container with identity.
236                 
237                 Remove factory from container with identity. 
238                 
239                 Params:
240                 	identity = the identity of factory to be removed.
241                 	
242             	Return:
243             		ProxyContainer decorating container
244                 **/
245                 ProxyContainerImpl remove(string identity)
246                 {
247                     this.proxyFactories.remove(identity);
248 
249                     return this;
250                 }
251             }
252 
253             static if (is(T : AliasAware!string))
254             {
255                 /**
256                 Alias identity to an alias_.
257                         
258                 Params:
259                 	identity = originial identity which is to be aliased.
260                 	alias_ = alias of identity.
261                 	
262         		Returns:
263         			ProxyContainer decorating container
264                 **/
265                 ProxyContainerImpl link(string identity, string alias_)
266                 {
267                     this.decorated.link(identity, alias_);
268                     this.proxyFactories.link(identity, alias_);
269 
270                     return this;
271                 }
272 
273                 /**
274                 Removes alias.
275                 
276                 Params:
277                 	alias_ = alias to remove.
278         
279                 Returns:
280                     ProxyContainer decorating container
281                 **/
282                 ProxyContainerImpl unlink(string alias_)
283                 {
284                     this.decorated.unlink(alias_);
285                     this.proxyFactories.unlink(alias_);
286 
287                     return this;
288                 }
289 
290                 /**
291                 Resolve an alias to original identity, if possible.
292                 
293                 Params:
294                 	alias_ = alias of original identity
295                 
296                 Returns:
297                 	const(string) the last identity in alias chain if container is enabled, or alias_ when not.
298                 
299                 **/
300                 const(string) resolve(in string alias_) const
301                 {
302                     return this.proxyFactories.resolve(alias_);
303                 }
304             }
305 
306             static if (is(T : FactoryLocator!ObjectFactory))
307             {
308 
309                 /**
310                 Get factory for constructed data identified by identity.
311                 
312                 Get factory for constructed data identified by identity.
313                 Params:
314                     identity = the identity of data that factory constructs.
315                 
316                 Throws:
317                     NotFoundException when factory for it is not found.
318                 
319                 Returns:
320                     ObjectFactory the factory for constructed data.
321                 **/
322                 ObjectFactory getFactory(string identity)
323                 {
324                     return this.decorated.getFactory(identity);
325                 }
326 
327                 /**
328                 Get all factories available in container.
329                 
330                 Get all factories available in container.
331                 
332                 Returns:
333                     InputRange!(Tuple!(ObjectFactory, string)) a tuple of factory => identity.
334                 **/
335                 InputRange!(Tuple!(ObjectFactory, string)) getFactories()
336                 {
337                     return this.decorated.getFactories();
338                 }
339             }
340 
341             /**
342     		Get object that is associated with identity.
343     		
344     		Params:
345     			identity = the object identity.
346     			
347     		Throws:
348     			NotFoundException in case if the object wasn't found or container is not enabled.
349     		
350     		Returns:
351     			Object if it is available.
352     		**/
353             Object get(string identity)
354             {
355                 return proxyFactories.get(identity).factory();
356             }
357 
358             /**
359             Check if object is present in ProxyContainer by key identity.
360             
361             Note:
362             	This check should be done for elements that locator actually contains, and
363             	not in chained locator (when locator is also a DelegatingLocator) for example.
364             Params:
365             	identity = identity of object.
366             	
367         	Returns:
368         		bool true if container is enabled and has object by identity.
369             **/
370             bool has(in string identity) inout
371             {
372                 return proxyFactories.has(identity);
373             }
374         }
375     }
376 }