1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, 13 * software distributed under the License is distributed on an 14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 * KIND, either express or implied. See the License for the 16 * specific language governing permissions and limitations 17 * under the License. 18 */ 19 module hunt.shiro.subject.SimplePrincipalMap; 20 21 import hunt.shiro.subject.PrincipalMap; 22 import hunt.shiro.util.CollectionUtils; 23 24 import hunt.collection; 25 import hunt.Exceptions; 26 import hunt.Object; 27 import hunt.util.ObjectUtils; 28 29 import std.array; 30 import std.range; 31 32 /** 33 * Default implementation of the {@link PrincipalMap} interface. 34 * 35 * *EXPERIMENTAL for Shiro 1.2 - DO NOT USE YET* 36 * 37 * @author Les Hazlewood 38 */ 39 class SimplePrincipalMap : PrincipalMap { 40 41 //Key: realm name, Value: map of principals specific to that realm 42 // internal map - key: principal name, value: principal 43 private Map!(string, Map!(string, Object)) realmPrincipals; 44 45 //maintains the principals from all realms plus any that are modified via the Map modification methods 46 //this ensures a fast lookup of any named principal instead of needing to iterate over 47 //the realmPrincipals for each lookup. 48 private Map!(string, Object) combinedPrincipals; 49 50 this() { 51 this(null); 52 } 53 54 this(Map!(string, Map!(string, Object)) backingMap) { 55 if (!CollectionUtils.isEmpty(backingMap)) { 56 this.realmPrincipals = backingMap; 57 foreach (Map!(string, Object) principals; this.realmPrincipals.byValue()) { 58 if (!CollectionUtils.isEmpty(principals) ) { 59 ensureCombinedPrincipals().putAll(principals); 60 } 61 } 62 } 63 } 64 65 int size() { 66 return CollectionUtils.size!(string, Object)(this.combinedPrincipals); 67 } 68 69 protected Map!(string, Object) ensureCombinedPrincipals() { 70 if (this.combinedPrincipals is null) { 71 this.combinedPrincipals = new HashMap!(string, Object)(); 72 } 73 return this.combinedPrincipals; 74 } 75 76 bool containsKey(string o) { 77 return this.combinedPrincipals !is null && this.combinedPrincipals.containsKey(o); 78 } 79 80 bool containsValue(Object o) { 81 return this.combinedPrincipals !is null && this.combinedPrincipals.containsValue(o); 82 } 83 84 Object get(string o) { 85 implementationMissing(false); 86 return null; 87 // return this.combinedPrincipals !is null && this.combinedPrincipals.containsKey(o); 88 } 89 90 Object put(string s, Object o) { 91 return ensureCombinedPrincipals().put(s, o); 92 } 93 94 Object remove(string o) { 95 return this.combinedPrincipals !is null ? this.combinedPrincipals.remove(o) : null; 96 } 97 98 void putAll(Map!(string, Object) map) { 99 if (!CollectionUtils.isEmpty(map)) { 100 ensureCombinedPrincipals().putAll(map); 101 } 102 } 103 104 // Set!(string) keySet() { 105 // return CollectionUtils.isEmpty(this.combinedPrincipals) ? 106 // Collections.emptySet!string() : 107 // Collections.unmodifiableSet(this.combinedPrincipals.keySet()); 108 // } 109 110 // Collection!(Object) values() { 111 // return CollectionUtils.isEmpty(this.combinedPrincipals) ? 112 // Collections.emptySet() : 113 // Collections.unmodifiableCollection(this.combinedPrincipals.values()); 114 // } 115 116 // Set!(Entry!(string, Object)) entrySet() { 117 // return CollectionUtils.isEmpty(this.combinedPrincipals) ? 118 // Collections.<Entry!(string,Object)>emptySet() : 119 // Collections.unmodifiableSet(this.combinedPrincipals.entrySet()); 120 // } 121 122 void clear() { 123 this.realmPrincipals = null; 124 this.combinedPrincipals = null; 125 } 126 127 Object getPrimaryPrincipal() { 128 //heuristic - just use the first one we come across: 129 if(CollectionUtils.isEmpty(this.combinedPrincipals)) 130 return null; 131 else { 132 return this.combinedPrincipals.values()[0]; 133 } 134 } 135 136 T oneByType(T)() if(is(T == class) || is(T == interface)) { 137 if (CollectionUtils.isEmpty(this.combinedPrincipals)) { 138 return null; 139 } 140 foreach(Object value; this.combinedPrincipals.values()) { 141 T v = cast(T)value; 142 if (value !is null && v !is null) { 143 return v; 144 } 145 } 146 return null; 147 } 148 149 Collection!(T) byType(T)() { 150 if (CollectionUtils.isEmpty(this.combinedPrincipals)) { 151 return Collections.emptySet!T(); 152 } 153 Collection!(T) instances = new ArrayList!(T)(); 154 foreach(Object value; this.combinedPrincipals.values()) { 155 T v = cast(T)value; 156 if (value !is null && v !is null) { 157 instances.add(v); 158 } 159 } 160 return instances; 161 } 162 163 List!(Object) asList() { 164 if (CollectionUtils.isEmpty(this.combinedPrincipals)) { 165 return Collections.emptyList!Object(); 166 } 167 List!(Object) list = new ArrayList!(Object)(this.combinedPrincipals.size()); 168 list.addAll(this.combinedPrincipals.values()); 169 return list; 170 } 171 172 Set!(Object) asSet() { 173 if (CollectionUtils.isEmpty(this.combinedPrincipals)) { 174 return Collections.emptySet!Object(); 175 } 176 Set!(Object) set = new HashSet!(Object)(this.combinedPrincipals.size()); 177 set.addAll(this.combinedPrincipals.values()); 178 return set; 179 } 180 181 Object[] fromRealm(string realmName) { 182 if (CollectionUtils.isEmpty(this.realmPrincipals)) { 183 return null; 184 } 185 Map!(string,Object) principals = this.realmPrincipals.get(realmName); 186 if (CollectionUtils.isEmpty(principals)) { 187 return null; 188 } 189 return principals.values(); 190 } 191 192 string[] getRealmNames() { 193 if (CollectionUtils.isEmpty(this.realmPrincipals)) { 194 return null; 195 } 196 return this.realmPrincipals.byKey.array(); 197 } 198 199 bool isEmpty() { 200 return CollectionUtils.isEmpty(this.combinedPrincipals); 201 } 202 203 // Iterator iterator() { 204 // return asList().iterator(); 205 // } 206 207 Map!(string, Object) getRealmPrincipals(string name) { 208 if (this.realmPrincipals is null) { 209 return null; 210 } 211 Map!(string,Object) principals = this.realmPrincipals.get(name); 212 if (principals is null) { 213 return null; 214 } 215 return principals; 216 } 217 218 Map!(string,Object) setRealmPrincipals(string realmName, Map!(string, Object) principals) { 219 if (realmName is null) { 220 throw new NullPointerException("realmName argument cannot be null."); 221 } 222 if (this.realmPrincipals is null) { 223 if (!CollectionUtils.isEmpty(principals)) { 224 this.realmPrincipals = new HashMap!(string,Map!(string,Object))(); 225 return this.realmPrincipals.put(realmName, new HashMap!(string,Object)(principals)); 226 } else { 227 return null; 228 } 229 } else { 230 Map!(string,Object) existingPrincipals = this.realmPrincipals.remove(realmName); 231 if (!CollectionUtils.isEmpty(principals)) { 232 this.realmPrincipals.put(realmName, new HashMap!(string,Object)(principals)); 233 } 234 return existingPrincipals; 235 } 236 } 237 238 Object setRealmPrincipal(string realmName, string principalName, Object principal) { 239 if (realmName is null) { 240 throw new NullPointerException("realmName argument cannot be null."); 241 } 242 if (principalName is null) { 243 throw new NullPointerException(("principalName argument cannot be null.")); 244 } 245 if (principal is null) { 246 return removeRealmPrincipal(realmName, principalName); 247 } 248 if (this.realmPrincipals is null) { 249 this.realmPrincipals = new HashMap!(string,Map!(string,Object))(); 250 } 251 Map!(string,Object) principals = this.realmPrincipals.get(realmName); 252 if (principals is null) { 253 principals = new HashMap!(string,Object)(); 254 this.realmPrincipals.put(realmName, principals); 255 } 256 return principals.put(principalName, principal); 257 } 258 259 Object getRealmPrincipal(string realmName, string principalName) { 260 if (realmName is null) { 261 throw new NullPointerException("realmName argument cannot be null."); 262 } 263 if (principalName is null) { 264 throw new NullPointerException(("principalName argument cannot be null.")); 265 } 266 if (this.realmPrincipals is null) { 267 return null; 268 } 269 Map!(string,Object) principals = this.realmPrincipals.get(realmName); 270 if (principals !is null) { 271 return principals.get(principalName); 272 } 273 return null; 274 } 275 276 Object removeRealmPrincipal(string realmName, string principalName) { 277 if (realmName is null) { 278 throw new NullPointerException("realmName argument cannot be null."); 279 } 280 if (principalName is null) { 281 throw new NullPointerException(("principalName argument cannot be null.")); 282 } 283 if (this.realmPrincipals is null) { 284 return null; 285 } 286 Map!(string,Object) principals = this.realmPrincipals.get(realmName); 287 if (principals !is null) { 288 return principals.remove(principalName); 289 } 290 return null; 291 } 292 293 bool remove(string key, Object value) { 294 Object curValue = get(key); 295 if (curValue != value || !containsKey(key)) 296 return false; 297 remove(key); 298 return true; 299 } 300 301 // void putAll(Map!(string, Object) map) { 302 // realmPrincipals.putAll(map); 303 // } 304 305 // void clear() { 306 // realmPrincipals.clear(); 307 // } 308 309 bool replace(string key, Object oldValue, Object newValue) { 310 Object curValue = get(key); 311 if (curValue != oldValue || !containsKey(key)) { 312 return false; 313 } 314 put(key, newValue); 315 return true; 316 } 317 318 Object replace(string key, Object value) { 319 Object curValue = Object.init; 320 if (containsKey(key)) { 321 curValue = put(key, value); 322 } 323 return curValue; 324 } 325 326 override string toString() { 327 if (isEmpty()) 328 return "{}"; 329 330 Appender!string sb; 331 sb.put("{"); 332 bool isFirst = true; 333 foreach (string key, Object value; this) { 334 if (!isFirst) { 335 sb.put(", "); 336 } 337 sb.put(key ~ "=" ~ value.toString()); 338 isFirst = false; 339 } 340 sb.put("}"); 341 342 return sb.data; 343 } 344 345 Object putIfAbsent(string key, Object value) { 346 Object v = Object.init; 347 348 if (!containsKey(key)) 349 v = put(key, value); 350 351 return v; 352 } 353 354 Object[] values() { 355 return byValue().array(); 356 } 357 358 Object opIndex(string key) { 359 return get(key); 360 } 361 362 363 int opApply(scope int delegate(ref Object) dg) { 364 throw new NotImplementedException(); 365 } 366 367 int opApply(scope int delegate(ref string, ref Object) dg) { 368 throw new NotImplementedException(); 369 } 370 371 int opApply(scope int delegate(MapEntry!(string, Object) entry) dg) { 372 throw new NotImplementedException(); 373 } 374 375 InputRange!string byKey() { 376 throw new NotImplementedException(); 377 } 378 379 InputRange!Object byValue() { 380 throw new NotImplementedException(); 381 } 382 383 override bool opEquals(Object o) { 384 throw new UnsupportedOperationException(); 385 } 386 387 bool opEquals(IObject o) { 388 return opEquals(cast(Object) o); 389 } 390 391 override size_t toHash() @trusted nothrow { 392 size_t h = 0; 393 try { 394 foreach (MapEntry!(string, Object) i; this) { 395 h += i.toHash(); 396 } 397 } catch (Exception ex) { 398 } 399 return h; 400 } 401 402 mixin CloneMemberTemplate!(typeof(this)); 403 }