001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.apache.shiro.subject; 020 021import org.apache.shiro.util.CollectionUtils; 022 023import java.util.ArrayList; 024import java.util.Collection; 025import java.util.Collections; 026import java.util.HashMap; 027import java.util.HashSet; 028import java.util.Iterator; 029import java.util.List; 030import java.util.Map; 031import java.util.Set; 032 033/** 034 * Default implementation of the {@link PrincipalMap} interface. 035 * <p> 036 * *EXPERIMENTAL for Shiro 1.2 - DO NOT USE YET* 037 * 038 * @since 1.2 039 */ 040public class SimplePrincipalMap implements PrincipalMap { 041 042 //Key: realm name, Value: map of principals specific to that realm 043 // internal map - key: principal name, value: principal 044 private Map<String, Map<String, Object>> realmPrincipals; 045 046 //maintains the principals from all realms plus any that are modified via the Map modification methods 047 //this ensures a fast lookup of any named principal instead of needing to iterate over 048 //the realmPrincipals for each lookup. 049 private Map<String, Object> combinedPrincipals; 050 051 public SimplePrincipalMap() { 052 this(null); 053 } 054 055 public SimplePrincipalMap(Map<String, Map<String, Object>> backingMap) { 056 if (!CollectionUtils.isEmpty(backingMap)) { 057 this.realmPrincipals = backingMap; 058 for (Map<String, Object> principals : this.realmPrincipals.values()) { 059 if (!CollectionUtils.isEmpty(principals)) { 060 ensureCombinedPrincipals().putAll(principals); 061 } 062 } 063 } 064 } 065 066 public int size() { 067 return CollectionUtils.size(this.combinedPrincipals); 068 } 069 070 protected Map<String, Object> ensureCombinedPrincipals() { 071 if (this.combinedPrincipals == null) { 072 this.combinedPrincipals = new HashMap<String, Object>(); 073 } 074 return this.combinedPrincipals; 075 } 076 077 public boolean containsKey(Object o) { 078 return this.combinedPrincipals != null && this.combinedPrincipals.containsKey(o); 079 } 080 081 public boolean containsValue(Object o) { 082 return this.combinedPrincipals != null && this.combinedPrincipals.containsKey(o); 083 } 084 085 public Object get(Object o) { 086 return this.combinedPrincipals != null && this.combinedPrincipals.containsKey(o); 087 } 088 089 public Object put(String s, Object o) { 090 return ensureCombinedPrincipals().put(s, o); 091 } 092 093 public Object remove(Object o) { 094 return this.combinedPrincipals != null ? this.combinedPrincipals.remove(o) : null; 095 } 096 097 public void putAll(Map<? extends String, ?> map) { 098 if (!CollectionUtils.isEmpty(map)) { 099 ensureCombinedPrincipals().putAll(map); 100 } 101 } 102 103 public Set<String> keySet() { 104 return CollectionUtils.isEmpty(this.combinedPrincipals) ? Collections.<String>emptySet() 105 : Collections.unmodifiableSet(this.combinedPrincipals.keySet()); 106 } 107 108 public Collection<Object> values() { 109 return CollectionUtils.isEmpty(this.combinedPrincipals) ? Collections.emptySet() 110 : Collections.unmodifiableCollection(this.combinedPrincipals.values()); 111 } 112 113 public Set<Entry<String, Object>> entrySet() { 114 return CollectionUtils.isEmpty(this.combinedPrincipals) 115 ? Collections.<Entry<String, Object>>emptySet() : Collections.unmodifiableSet(this.combinedPrincipals.entrySet()); 116 } 117 118 public void clear() { 119 this.realmPrincipals = null; 120 this.combinedPrincipals = null; 121 } 122 123 public Object getPrimaryPrincipal() { 124 //heuristic - just use the first one we come across: 125 return !CollectionUtils.isEmpty(this.combinedPrincipals) ? this.combinedPrincipals.values().iterator().next() : null; 126 } 127 128 public <T> T oneByType(Class<T> type) { 129 if (CollectionUtils.isEmpty(this.combinedPrincipals)) { 130 return null; 131 } 132 for (Object value : this.combinedPrincipals.values()) { 133 if (type.isInstance(value)) { 134 return type.cast(value); 135 } 136 } 137 return null; 138 } 139 140 public <T> Collection<T> byType(Class<T> type) { 141 if (CollectionUtils.isEmpty(this.combinedPrincipals)) { 142 return Collections.emptySet(); 143 } 144 Collection<T> instances = null; 145 for (Object value : this.combinedPrincipals.values()) { 146 if (type.isInstance(value)) { 147 if (instances == null) { 148 instances = new ArrayList<T>(); 149 } 150 instances.add(type.cast(value)); 151 } 152 } 153 return instances != null ? instances : Collections.<T>emptyList(); 154 } 155 156 public List asList() { 157 if (CollectionUtils.isEmpty(this.combinedPrincipals)) { 158 return Collections.emptyList(); 159 } 160 List<Object> list = new ArrayList<Object>(this.combinedPrincipals.size()); 161 list.addAll(this.combinedPrincipals.values()); 162 return list; 163 } 164 165 public Set asSet() { 166 if (CollectionUtils.isEmpty(this.combinedPrincipals)) { 167 return Collections.emptySet(); 168 } 169 Set<Object> set = new HashSet<Object>(this.combinedPrincipals.size()); 170 set.addAll(this.combinedPrincipals.values()); 171 return set; 172 } 173 174 public Collection fromRealm(String realmName) { 175 if (CollectionUtils.isEmpty(this.realmPrincipals)) { 176 return Collections.emptySet(); 177 } 178 Map<String, Object> principals = this.realmPrincipals.get(realmName); 179 if (CollectionUtils.isEmpty(principals)) { 180 return Collections.emptySet(); 181 } 182 return Collections.unmodifiableCollection(principals.values()); 183 } 184 185 public Set<String> getRealmNames() { 186 if (CollectionUtils.isEmpty(this.realmPrincipals)) { 187 return Collections.emptySet(); 188 } 189 return Collections.unmodifiableSet(this.realmPrincipals.keySet()); 190 } 191 192 public boolean isEmpty() { 193 return CollectionUtils.isEmpty(this.combinedPrincipals); 194 } 195 196 public Iterator iterator() { 197 return asList().iterator(); 198 } 199 200 public Map<String, Object> getRealmPrincipals(String name) { 201 if (this.realmPrincipals == null) { 202 return null; 203 } 204 Map<String, Object> principals = this.realmPrincipals.get(name); 205 if (principals == null) { 206 return null; 207 } 208 return Collections.unmodifiableMap(principals); 209 } 210 211 public Map<String, Object> setRealmPrincipals(String realmName, Map<String, Object> principals) { 212 if (realmName == null) { 213 throw new NullPointerException("realmName argument cannot be null."); 214 } 215 if (this.realmPrincipals == null) { 216 if (!CollectionUtils.isEmpty(principals)) { 217 this.realmPrincipals = new HashMap<String, Map<String, Object>>(); 218 return this.realmPrincipals.put(realmName, new HashMap<String, Object>(principals)); 219 } else { 220 return null; 221 } 222 } else { 223 Map<String, Object> existingPrincipals = this.realmPrincipals.remove(realmName); 224 if (!CollectionUtils.isEmpty(principals)) { 225 this.realmPrincipals.put(realmName, new HashMap<String, Object>(principals)); 226 } 227 return existingPrincipals; 228 } 229 } 230 231 public Object setRealmPrincipal(String realmName, String principalName, Object principal) { 232 if (realmName == null) { 233 throw new NullPointerException("realmName argument cannot be null."); 234 } 235 if (principalName == null) { 236 throw new NullPointerException(("principalName argument cannot be null.")); 237 } 238 if (principal == null) { 239 return removeRealmPrincipal(realmName, principalName); 240 } 241 if (this.realmPrincipals == null) { 242 this.realmPrincipals = new HashMap<String, Map<String, Object>>(); 243 } 244 Map<String, Object> principals = this.realmPrincipals.get(realmName); 245 if (principals == null) { 246 principals = new HashMap<String, Object>(); 247 this.realmPrincipals.put(realmName, principals); 248 } 249 return principals.put(principalName, principal); 250 } 251 252 public Object getRealmPrincipal(String realmName, String principalName) { 253 if (realmName == null) { 254 throw new NullPointerException("realmName argument cannot be null."); 255 } 256 if (principalName == null) { 257 throw new NullPointerException(("principalName argument cannot be null.")); 258 } 259 if (this.realmPrincipals == null) { 260 return null; 261 } 262 Map<String, Object> principals = this.realmPrincipals.get(realmName); 263 if (principals != null) { 264 return principals.get(principalName); 265 } 266 return null; 267 } 268 269 public Object removeRealmPrincipal(String realmName, String principalName) { 270 if (realmName == null) { 271 throw new NullPointerException("realmName argument cannot be null."); 272 } 273 if (principalName == null) { 274 throw new NullPointerException(("principalName argument cannot be null.")); 275 } 276 if (this.realmPrincipals == null) { 277 return null; 278 } 279 Map<String, Object> principals = this.realmPrincipals.get(realmName); 280 if (principals != null) { 281 return principals.remove(principalName); 282 } 283 return null; 284 } 285}