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     */
019    package org.apache.shiro.subject;
020    
021    import org.apache.shiro.util.CollectionUtils;
022    
023    import 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     */
033    public 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    }