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.*; 024 025/** 026 * Default implementation of the {@link PrincipalMap} interface. 027 * 028 * *EXPERIMENTAL for Shiro 1.2 - DO NOT USE YET* 029 * 030 * @author Les Hazlewood 031 * @since 1.2 032 */ 033public class SimplePrincipalMap implements PrincipalMap { 034 035 //Key: realm name, Value: map of principals specific to that realm 036 // internal map - key: principal name, value: principal 037 private Map<String, Map<String, Object>> realmPrincipals; 038 039 //maintains the principals from all realms plus any that are modified via the Map modification methods 040 //this ensures a fast lookup of any named principal instead of needing to iterate over 041 //the realmPrincipals for each lookup. 042 private Map<String, Object> combinedPrincipals; 043 044 public SimplePrincipalMap() { 045 this(null); 046 } 047 048 public SimplePrincipalMap(Map<String, Map<String, Object>> backingMap) { 049 if (!CollectionUtils.isEmpty(backingMap)) { 050 this.realmPrincipals = backingMap; 051 for (Map<String, Object> principals : this.realmPrincipals.values()) { 052 if (!CollectionUtils.isEmpty(principals) ) { 053 ensureCombinedPrincipals().putAll(principals); 054 } 055 } 056 } 057 } 058 059 public int size() { 060 return CollectionUtils.size(this.combinedPrincipals); 061 } 062 063 protected Map<String, Object> ensureCombinedPrincipals() { 064 if (this.combinedPrincipals == null) { 065 this.combinedPrincipals = new HashMap<String, Object>(); 066 } 067 return this.combinedPrincipals; 068 } 069 070 public boolean containsKey(Object o) { 071 return this.combinedPrincipals != null && this.combinedPrincipals.containsKey(o); 072 } 073 074 public boolean containsValue(Object o) { 075 return this.combinedPrincipals != null && this.combinedPrincipals.containsKey(o); 076 } 077 078 public Object get(Object o) { 079 return this.combinedPrincipals != null && this.combinedPrincipals.containsKey(o); 080 } 081 082 public Object put(String s, Object o) { 083 return ensureCombinedPrincipals().put(s, o); 084 } 085 086 public Object remove(Object o) { 087 return this.combinedPrincipals != null ? this.combinedPrincipals.remove(o) : null; 088 } 089 090 public void putAll(Map<? extends String, ?> map) { 091 if (!CollectionUtils.isEmpty(map)) { 092 ensureCombinedPrincipals().putAll(map); 093 } 094 } 095 096 public Set<String> keySet() { 097 return CollectionUtils.isEmpty(this.combinedPrincipals) ? 098 Collections.<String>emptySet() : 099 Collections.unmodifiableSet(this.combinedPrincipals.keySet()); 100 } 101 102 public Collection<Object> values() { 103 return CollectionUtils.isEmpty(this.combinedPrincipals) ? 104 Collections.emptySet() : 105 Collections.unmodifiableCollection(this.combinedPrincipals.values()); 106 } 107 108 public Set<Entry<String, Object>> entrySet() { 109 return CollectionUtils.isEmpty(this.combinedPrincipals) ? 110 Collections.<Entry<String,Object>>emptySet() : 111 Collections.unmodifiableSet(this.combinedPrincipals.entrySet()); 112 } 113 114 public void clear() { 115 this.realmPrincipals = null; 116 this.combinedPrincipals = null; 117 } 118 119 public Object getPrimaryPrincipal() { 120 //heuristic - just use the first one we come across: 121 return !CollectionUtils.isEmpty(this.combinedPrincipals) ? 122 this.combinedPrincipals.values().iterator().next() : 123 null; 124 } 125 126 public <T> T oneByType(Class<T> type) { 127 if (CollectionUtils.isEmpty(this.combinedPrincipals)) { 128 return null; 129 } 130 for( Object value : this.combinedPrincipals.values()) { 131 if (type.isInstance(value) ) { 132 return type.cast(value); 133 } 134 } 135 return null; 136 } 137 138 public <T> Collection<T> byType(Class<T> type) { 139 if (CollectionUtils.isEmpty(this.combinedPrincipals)) { 140 return Collections.emptySet(); 141 } 142 Collection<T> instances = null; 143 for( Object value : this.combinedPrincipals.values()) { 144 if (type.isInstance(value) ) { 145 if (instances == null) { 146 instances = new ArrayList<T>(); 147 } 148 instances.add(type.cast(value)); 149 } 150 } 151 return instances != null ? instances : Collections.<T>emptyList(); 152 } 153 154 public List asList() { 155 if (CollectionUtils.isEmpty(this.combinedPrincipals)) { 156 return Collections.emptyList(); 157 } 158 List<Object> list = new ArrayList<Object>(this.combinedPrincipals.size()); 159 list.addAll(this.combinedPrincipals.values()); 160 return list; 161 } 162 163 public Set asSet() { 164 if (CollectionUtils.isEmpty(this.combinedPrincipals)) { 165 return Collections.emptySet(); 166 } 167 Set<Object> set = new HashSet<Object>(this.combinedPrincipals.size()); 168 set.addAll(this.combinedPrincipals.values()); 169 return set; 170 } 171 172 public Collection fromRealm(String realmName) { 173 if (CollectionUtils.isEmpty(this.realmPrincipals)) { 174 return Collections.emptySet(); 175 } 176 Map<String,Object> principals = this.realmPrincipals.get(realmName); 177 if (CollectionUtils.isEmpty(principals)) { 178 return Collections.emptySet(); 179 } 180 return Collections.unmodifiableCollection(principals.values()); 181 } 182 183 public Set<String> getRealmNames() { 184 if (CollectionUtils.isEmpty(this.realmPrincipals)) { 185 return Collections.emptySet(); 186 } 187 return Collections.unmodifiableSet(this.realmPrincipals.keySet()); 188 } 189 190 public boolean isEmpty() { 191 return CollectionUtils.isEmpty(this.combinedPrincipals); 192 } 193 194 public Iterator iterator() { 195 return asList().iterator(); 196 } 197 198 public Map<String, Object> getRealmPrincipals(String name) { 199 if (this.realmPrincipals == null) { 200 return null; 201 } 202 Map<String,Object> principals = this.realmPrincipals.get(name); 203 if (principals == null) { 204 return null; 205 } 206 return Collections.unmodifiableMap(principals); 207 } 208 209 public Map<String,Object> setRealmPrincipals(String realmName, Map<String, Object> principals) { 210 if (realmName == null) { 211 throw new NullPointerException("realmName argument cannot be null."); 212 } 213 if (this.realmPrincipals == null) { 214 if (!CollectionUtils.isEmpty(principals)) { 215 this.realmPrincipals = new HashMap<String,Map<String,Object>>(); 216 return this.realmPrincipals.put(realmName, new HashMap<String,Object>(principals)); 217 } else { 218 return null; 219 } 220 } else { 221 Map<String,Object> existingPrincipals = this.realmPrincipals.remove(realmName); 222 if (!CollectionUtils.isEmpty(principals)) { 223 this.realmPrincipals.put(realmName, new HashMap<String,Object>(principals)); 224 } 225 return existingPrincipals; 226 } 227 } 228 229 public Object setRealmPrincipal(String realmName, String principalName, Object principal) { 230 if (realmName == null) { 231 throw new NullPointerException("realmName argument cannot be null."); 232 } 233 if (principalName == null) { 234 throw new NullPointerException(("principalName argument cannot be null.")); 235 } 236 if (principal == null) { 237 return removeRealmPrincipal(realmName, principalName); 238 } 239 if (this.realmPrincipals == null) { 240 this.realmPrincipals = new HashMap<String,Map<String,Object>>(); 241 } 242 Map<String,Object> principals = this.realmPrincipals.get(realmName); 243 if (principals == null) { 244 principals = new HashMap<String,Object>(); 245 this.realmPrincipals.put(realmName, principals); 246 } 247 return principals.put(principalName, principal); 248 } 249 250 public Object getRealmPrincipal(String realmName, String principalName) { 251 if (realmName == null) { 252 throw new NullPointerException("realmName argument cannot be null."); 253 } 254 if (principalName == null) { 255 throw new NullPointerException(("principalName argument cannot be null.")); 256 } 257 if (this.realmPrincipals == null) { 258 return null; 259 } 260 Map<String,Object> principals = this.realmPrincipals.get(realmName); 261 if (principals != null) { 262 return principals.get(principalName); 263 } 264 return null; 265 } 266 267 public Object removeRealmPrincipal(String realmName, String principalName) { 268 if (realmName == null) { 269 throw new NullPointerException("realmName argument cannot be null."); 270 } 271 if (principalName == null) { 272 throw new NullPointerException(("principalName argument cannot be null.")); 273 } 274 if (this.realmPrincipals == null) { 275 return null; 276 } 277 Map<String,Object> principals = this.realmPrincipals.get(realmName); 278 if (principals != null) { 279 return principals.remove(principalName); 280 } 281 return null; 282 } 283}