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