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.storage.aggregate_locator; 32 33 import aermicioi.aedi.exception.not_found_exception; 34 import aermicioi.aedi.storage.locator; 35 import aermicioi.aedi.util.typecons : Pair, pair; 36 import std.conv : to; 37 import std.range.interfaces; 38 39 /** 40 An implementation of AggregateLocator. 41 **/ 42 @safe class AggregateLocatorImpl(Type = Object, KeyType = string, LocatorKeyType = KeyType) : 43 MutableAggregateLocator!(Type, KeyType, LocatorKeyType) { 44 45 protected { 46 47 Locator!(Type, KeyType)[LocatorKeyType] locators; 48 } 49 50 public { 51 52 /** 53 Add a Locator by key. 54 55 Params: 56 key = key by which to identify the locator. 57 locator = the Locator that will be added to AggregateLocator 58 **/ 59 AggregateLocatorImpl!(Type, KeyType, LocatorKeyType) set(Locator!(Type, KeyType) locator, LocatorKeyType key) { 60 61 this.locators[key] = locator; 62 63 return this; 64 } 65 66 /** 67 Removes a Locator by key. 68 69 Params: 70 key = the identity of locator that should be removed. 71 **/ 72 AggregateLocatorImpl!(Type, KeyType, LocatorKeyType) remove(LocatorKeyType key) { 73 74 this.locators.remove(key); 75 76 return this; 77 } 78 79 /** 80 Get an Type that is associated with key. 81 82 Params: 83 identity = the element id. 84 85 Throws: 86 NotFoundException in case if the element wasn't found. 87 88 Returns: 89 Type element if it is available. 90 **/ 91 Type get(KeyType identity) { 92 93 foreach (locator; this.locators) { 94 95 if (locator.has(identity)) { 96 return locator.get(identity); 97 } 98 } 99 100 if ((identity in this.locators) !is null) { 101 auto result = (() scope @trusted => cast(Type) this.locators[identity])(); 102 103 if (result !is null) { 104 return result; 105 } 106 } 107 108 throw new NotFoundException("Could not find component with ${identity} identity.", identity.to!string); 109 } 110 111 /** 112 Check if an element is present in Locator by key id. 113 114 Note: 115 This check should be done for elements that locator actually contains, and 116 not in chained locator (when locator is also a DelegatingLocator) for example. 117 Params: 118 identity = identity of element. 119 120 Returns: 121 bool true if an element by key is present in Locator. 122 **/ 123 bool has(in KeyType identity) inout { 124 125 if ((identity in this.locators) !is null) { 126 return true; 127 } 128 129 foreach (locator; this.locators) { 130 131 if (locator.has(identity)) { 132 return true; 133 } 134 } 135 136 return false; 137 } 138 139 /** 140 Get a specific locator. 141 142 Params: 143 key = the locator identity. 144 **/ 145 Locator!(Type, KeyType) getLocator(LocatorKeyType key) { 146 147 if (this.hasLocator(key)) { 148 return this.locators[key]; 149 } 150 151 throw new NotFoundException("Could not find any locator with identity ${identity}", key); 152 } 153 154 /** 155 Get all locators in aggregate locator 156 157 Returns: 158 InputRange!(Pair!(Locator!(Type, KeyType), LocatorKeyType)) a range of locator => identity 159 **/ 160 InputRange!(Pair!(Locator!(Type, KeyType), LocatorKeyType)) getLocators() { 161 import std.algorithm : map; 162 163 return this.locators.byKeyValue.map!( 164 a => pair(a.value, a.key) 165 ).inputRangeObject; 166 } 167 168 /** 169 Check if aggregate locator contains a specific locator. 170 171 Params: 172 key = the identity of locator in aggregate locator 173 **/ 174 bool hasLocator(LocatorKeyType key) inout { 175 176 return (key in this.locators) !is null; 177 } 178 } 179 }