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.util.typecons : Pair, pair; 35 import aermicioi.aedi.storage.object_storage; 36 import aermicioi.aedi.storage.locator_aware; 37 import aermicioi.aedi.storage.locator; 38 import aermicioi.aedi.factory.factory; 39 import aermicioi.aedi.exception; 40 import aermicioi.aedi.container.factory; 41 42 import std.range.interfaces; 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 @safe 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 92 if (this.singletons.has(key)) { 93 94 auto temporary = this.singletons.get(key); 95 this.factories.get(key).destruct(temporary); 96 } 97 98 this.factories.remove(key); 99 this.singletons.remove(key); 100 101 return this; 102 } 103 104 /** 105 * Get object created by a factory identified by key 106 * 107 * Params: 108 * key = identity of factory 109 * Returns: 110 * Object 111 **/ 112 Object get(string key) { 113 114 if (!this.singletons.has(key)) { 115 if (!this.factories.has(key)) { 116 throw new NotFoundException("Component ${identity} not found.", key); 117 } 118 119 this.singletons.set( 120 this.factories.get(key).factory(), 121 this.resolve(key), 122 ); 123 } 124 125 return this.singletons.get(key); 126 } 127 128 /** 129 * Check if an object factory for it exists in container. 130 * 131 * Params: 132 * key = identity of factory 133 * Returns: 134 * bool 135 **/ 136 bool has(in string key) inout { 137 return this.factories.has(key); 138 } 139 140 /** 141 Sets up the internal state of container. 142 143 Sets up the internal state of container (Ex, for singleton container it will spawn all objects that locator contains). 144 **/ 145 SingletonContainer instantiate() { 146 import std.algorithm : filter; 147 foreach (pair; this.factories.contents.byKeyValue.filter!((pair) => pair.key !in this.singletons.contents)) { 148 this.singletons.set( 149 pair.value.factory, 150 pair.key, 151 ); 152 } 153 154 return this; 155 } 156 157 /** 158 Destruct all managed components. 159 160 Destruct all managed components. The method denotes the end of container lifetime, and therefore destruction of all managed components 161 by it. 162 **/ 163 Container terminate() { 164 foreach (pair; this.singletons.contents.byKeyValue) { 165 this.factories.get(pair.key).destruct(pair.value); 166 } 167 168 (() scope @trusted => this.singletons.contents.clear)(); 169 170 return this; 171 } 172 173 /** 174 Alias a key to an alias_. 175 176 Params: 177 key = the originial identity which is to be aliased. 178 alias_ = the alias of identity. 179 180 Returns: 181 this 182 **/ 183 SingletonContainer link(string key, string alias_) { 184 this.singletons.link(key, alias_); 185 this.factories.link(key, alias_); 186 187 return this; 188 } 189 190 /** 191 Removes alias. 192 193 Params: 194 alias_ = alias to remove. 195 196 Returns: 197 this 198 199 **/ 200 SingletonContainer unlink(string alias_) { 201 this.singletons.unlink(alias_); 202 this.factories.unlink(alias_); 203 204 return this; 205 } 206 207 /** 208 Resolve an alias to original identity, if possible. 209 210 Params: 211 key = alias of original identity 212 213 Returns: 214 Type the last identity in alias chain. 215 216 **/ 217 const(string) resolve(in string key) const { 218 return this.factories.resolve(key); 219 } 220 221 /** 222 Get factory for constructed component identified by identity. 223 224 Get factory for constructed component identified by identity. 225 Params: 226 identity = the identity of component that factory constructs. 227 228 Throws: 229 NotFoundException when factory for it is not found. 230 231 Returns: 232 ObjectFactory the factory for constructed component. 233 **/ 234 ObjectFactory getFactory(string identity) { 235 return this.factories.get(identity); 236 } 237 238 /** 239 Get all factories available in container. 240 241 Get all factories available in container. 242 243 Returns: 244 InputRange!(Pair!(ObjectFactory, string)) a pair of factory => identity. 245 **/ 246 InputRange!(Pair!(ObjectFactory, string)) getFactories() { 247 import std.algorithm : map; 248 249 return this.factories.contents.byKeyValue.map!( 250 a => Pair!(ObjectFactory, string)(a.value, a.key) 251 ).inputRangeObject; 252 } 253 } 254 }