1 /**
2 
3 License:
4 	Boost Software License - Version 1.0 - August 17th, 2003
5     
6     Permission is hereby granted, free of charge, to any person or organization
7     obtaining a copy of the software and accompanying documentation covered by
8     this license (the "Software") to use, reproduce, display, distribute,
9     execute, and transmit the Software, and to prepare derivative works of the
10     Software, and to permit third-parties to whom the Software is furnished to
11     do so, all subject to the following:
12     
13     The copyright notices in the Software and this entire statement, including
14     the above license grant, this restriction and the following disclaimer,
15     must be included in all copies of the Software, in whole or in part, and
16     all derivative works of the Software, unless such copies or derivative
17     works are solely in the form of machine-executable object code generated by
18     a source language processor.
19     
20     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21     IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22     FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
23     SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
24     FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
25     ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26     DEALINGS IN THE SOFTWARE.
27 
28 Authors:
29 	Alexandru Ermicioi
30 **/
31 module aermicioi.aedi.container.singleton_container;
32 
33 import aermicioi.aedi.container.container;
34 import aermicioi.aedi.storage.object_storage;
35 import aermicioi.aedi.storage.locator_aware;
36 import aermicioi.aedi.storage.locator;
37 import aermicioi.aedi.factory.factory;
38 import aermicioi.aedi.exception;
39 import aermicioi.aedi.container.factory;
40 
41 import std.range.interfaces;
42 import std.typecons;
43 
44 /**
45  Singleton container.
46  
47  It creates objects from ObjectFactory implementations and sets them as long as it lives in application.
48 **/
49 class SingletonContainer : ConfigurableContainer {
50     
51     private {
52         
53         ObjectStorage!() singletons;
54         ObjectStorage!(ObjectFactory, string) factories;
55     }
56     
57     public {
58         
59         /**
60          * Default constructor for SingletonContainer
61         **/
62         this() {
63             this.singletons = new ObjectStorage!();
64             this.factories = new ObjectStorage!(ObjectFactory, string);
65         }
66         
67         /**
68          * Set object factory
69          * 
70          * Params: 
71          * 	object = factory for a object that is to be managed by prototype container.
72          *  key = identity of factory
73          * Returns:
74          * 	typeof(this)
75         **/
76         SingletonContainer set(ObjectFactory object, string key) {
77             this.factories.set(new ExceptionChainingObjectFactory(new InProcessObjectFactoryDecorator(object), key), key);
78             
79             return this;
80         }
81         
82         /**
83          * Remove an object factory from container.
84          * 
85          * Params: 
86          * 	key = identity of factory to be removed
87          * Returns:
88          * 	typeof(this)
89         **/
90         SingletonContainer remove(string key) {
91             this.factories.remove(key);
92             this.singletons.remove(key);
93             
94             return this;
95         }
96         
97         /**
98          * Get object created by a factory identified by key
99          * 
100          * Params:
101          *  key = identity of factory
102          * Returns:
103          * 	Object
104         **/
105         Object get(string key) {
106             
107             if (!this.singletons.has(key)) {
108                 if (!this.factories.has(key)) {
109                     throw new NotFoundException("Object with id " ~ key ~ " not found.");
110                 }
111                 
112                 this.singletons.set( 
113                     this.factories.get(key).factory(),
114                     this.resolve(key),
115                 );
116             }
117             
118             return this.singletons.get(key);
119         }
120         
121         /**
122          * Check if an object factory for it exists in container.
123          * 
124          * Params: 
125          * 	key = identity of factory
126          * Returns:
127          * 	bool
128         **/
129         bool has(in string key) inout {
130             return this.factories.has(key);
131         }
132         
133         /**
134         Sets up the internal state of container.
135         
136         Sets up the internal state of container (Ex, for singleton container it will spawn all objects that locator contains).
137         **/
138         SingletonContainer instantiate() {
139             import std.algorithm : filter;
140             foreach (pair; this.factories.contents.byKeyValue.filter!((pair) => pair.key !in this.singletons.contents)) {
141                 this.singletons.set(
142                     pair.value.factory,
143                     pair.key,
144                 );
145             }
146             
147             return this;
148         }
149         
150         /**
151         Alias a key to an alias_.
152                 
153         Params:
154         	key = the originial identity which is to be aliased.
155         	alias_ = the alias of identity.
156         	
157 		Returns:
158 			this
159         **/
160         SingletonContainer link(string key, string alias_) {
161             this.singletons.link(key, alias_);
162             this.factories.link(key, alias_);
163             
164             return this;
165         }
166         
167         /**
168         Removes alias.
169         
170         Params:
171         	alias_ = alias to remove.
172 
173         Returns:
174             this
175         	
176         **/
177         SingletonContainer unlink(string alias_) {
178             this.singletons.unlink(alias_);
179             this.factories.unlink(alias_);
180             
181             return this;
182         }
183         
184         /**
185         Resolve an alias to original identity, if possible.
186         
187         Params:
188         	key = alias of original identity
189         
190         Returns:
191         	Type the last identity in alias chain.
192         
193         **/
194         const(string) resolve(in string key) const {
195             return this.factories.resolve(key);
196         }
197         
198         /**
199         Get factory for constructed data identified by identity.
200         
201         Get factory for constructed data identified by identity.
202         Params:
203         	identity = the identity of data that factory constructs.
204         
205         Throws:
206         	NotFoundException when factory for it is not found.
207         
208         Returns:
209         	ObjectFactory the factory for constructed data.
210         **/
211         ObjectFactory getFactory(string identity) {
212             return this.factories.get(identity);
213         }
214         
215         /**
216         Get all factories available in container.
217         
218         Get all factories available in container.
219         
220         Returns:
221         	InputRange!(Tuple!(ObjectFactory, string)) a tuple of factory => identity.
222         **/
223         InputRange!(Tuple!(ObjectFactory, string)) getFactories() {
224             import std.algorithm;
225             
226             return this.factories.contents.byKeyValue.map!(
227                 a => tuple(a.value, a.key)
228             ).inputRangeObject;
229         }
230     }
231 }