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.util; 020 021import java.io.Serializable; 022import java.util.Collection; 023import java.util.Collections; 024import java.util.HashMap; 025import java.util.Map; 026import java.util.Set; 027 028/** 029 * A {@code MapContext} provides a common base for context-based data storage in a {@link Map}. Type-safe attribute 030 * retrieval is provided for subclasses with the {@link #getTypedValue(String, Class)} method. 031 * 032 * @see org.apache.shiro.subject.SubjectContext SubjectContext 033 * @see org.apache.shiro.session.mgt.SessionContext SessionContext 034 * @since 1.0 035 */ 036public class MapContext implements Map<String, Object>, Serializable { 037 038 private static final long serialVersionUID = 5373399119017820322L; 039 040 private final Map<String, Object> backingMap; 041 042 public MapContext() { 043 this.backingMap = new HashMap<String, Object>(); 044 } 045 046 public MapContext(Map<String, Object> map) { 047 this(); 048 if (!CollectionUtils.isEmpty(map)) { 049 this.backingMap.putAll(map); 050 } 051 } 052 053 /** 054 * Performs a {@link #get get} operation but additionally ensures that the value returned is of the specified 055 * {@code type}. If there is no value, {@code null} is returned. 056 * 057 * @param key the attribute key to look up a value 058 * @param type the expected type of the value 059 * @param <E> the expected type of the value 060 * @return the typed value or {@code null} if the attribute does not exist. 061 */ 062 @SuppressWarnings({"unchecked"}) 063 protected <E> E getTypedValue(String key, Class<E> type) { 064 E found = null; 065 Object o = backingMap.get(key); 066 if (o != null) { 067 if (!type.isAssignableFrom(o.getClass())) { 068 String msg = "Invalid object found in SubjectContext Map under key [" + key + "]. Expected type " 069 + "was [" + type.getName() + "], but the object under that key is of type " 070 + "[" + o.getClass().getName() + "]."; 071 throw new IllegalArgumentException(msg); 072 } 073 found = (E) o; 074 } 075 return found; 076 } 077 078 /** 079 * Places a value in this context map under the given key only if the given {@code value} argument is not null. 080 * 081 * @param key the attribute key under which the non-null value will be stored 082 * @param value the non-null value to store. If {@code null}, this method does nothing and returns immediately. 083 */ 084 protected void nullSafePut(String key, Object value) { 085 if (value != null) { 086 put(key, value); 087 } 088 } 089 090 public int size() { 091 return backingMap.size(); 092 } 093 094 public boolean isEmpty() { 095 return backingMap.isEmpty(); 096 } 097 098 public boolean containsKey(Object o) { 099 return backingMap.containsKey(o); 100 } 101 102 public boolean containsValue(Object o) { 103 return backingMap.containsValue(o); 104 } 105 106 public Object get(Object o) { 107 return backingMap.get(o); 108 } 109 110 public Object put(String s, Object o) { 111 return backingMap.put(s, o); 112 } 113 114 public Object remove(Object o) { 115 return backingMap.remove(o); 116 } 117 118 public void putAll(Map<? extends String, ?> map) { 119 backingMap.putAll(map); 120 } 121 122 public void clear() { 123 backingMap.clear(); 124 } 125 126 public Set<String> keySet() { 127 return Collections.unmodifiableSet(backingMap.keySet()); 128 } 129 130 public Collection<Object> values() { 131 return Collections.unmodifiableCollection(backingMap.values()); 132 } 133 134 public Set<Entry<String, Object>> entrySet() { 135 return Collections.unmodifiableSet(backingMap.entrySet()); 136 } 137}