001 /*--------------------------------------------------------------------------+
002 $Id: ClassHierarchyMap.java 26283 2010-02-18 11:18:57Z juergens $
003 | |
004 | Copyright 2005-2010 Technische Universitaet Muenchen |
005 | |
006 | Licensed under the Apache License, Version 2.0 (the "License"); |
007 | you may not use this file except in compliance with the License. |
008 | 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, software |
013 | distributed under the License is distributed on an "AS IS" BASIS, |
014 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
015 | See the License for the specific language governing permissions and |
016 | limitations under the License. |
017 +--------------------------------------------------------------------------*/
018 package edu.tum.cs.commons.collections;
019
020 import java.util.ArrayList;
021 import java.util.Collection;
022 import java.util.HashMap;
023 import java.util.List;
024 import java.util.Set;
025
026 import edu.tum.cs.commons.reflect.ReflectionUtils;
027
028 /**
029 * This class provides a mapping from classes to values. The speciality of this
030 * class lies in its awareness of the class hierarchy: If no value was found
031 * this class tries to retrieve values stored for the super classes of the
032 * provided class. If values are stored for multiple super classes of the class
033 * the one value that maps to the super class closest to the provided class will
034 * be returned.
035 * <p>
036 *
037 * @param <T>
038 * This type parameter allows to specify a lower bound of the classes
039 * used as keys. If this is unnecessary, use {@link Object}.
040 * @author Florian Deissenboeck
041 * @author $Author: juergens $
042 * @version $Rev: 26283 $
043 * @levd.rating GREEN Hash: C47D9975C69CF7FBCB80888A00CE1A9F
044 */
045 public class ClassHierarchyMap<T, V> {
046 /** Underlying map. */
047 private final HashMap<Class<? extends T>, V> map = new HashMap<Class<? extends T>, V>();
048
049 /** @see java.util.Map#clear() */
050 public void clear() {
051 map.clear();
052 }
053
054 /**
055 * Get value stored for a class. If no value was found this method tries to
056 * retrieve values stored for the super classes of the provided class. If
057 * values are stored for multiple super classes of the class the one value
058 * that maps to the super class closest to the provided class will be
059 * returned.
060 * <p>
061 * If a key is stored for the provided class the performance of this method
062 * equals the performance of {@link HashMap#get(Object)}. Otherwise its
063 * worst case performance is O(DIT(key)).
064 *
065 * @param key
066 * the key
067 * @return the value stored for the provided key or one if its super classes
068 * or <code>null</code> if no value was found.
069 */
070 public V get(Class<?> key) {
071 V value = map.get(key);
072 if (value != null) {
073 return value;
074 }
075
076 List<Class<?>> superClasses = ReflectionUtils.getSuperClasses(key);
077
078 for (Class<?> clazz : superClasses) {
079 value = map.get(clazz);
080 if (value != null) {
081 return value;
082 }
083 }
084 return null;
085 }
086
087 /**
088 * Get value stored for the declaring class of the provided element.
089 *
090 * @see #get(Class)
091 */
092 public V get(T element) {
093 return get(element.getClass());
094 }
095
096 /**
097 * Retrieve a list of values stored for the provided class and its super
098 * classes. List starts with the value stored for the provided class (if
099 * present).
100 *
101 * @return the list of values or an empty list of no value was found.
102 */
103 public List<V> getAll(Class<?> key) {
104 ArrayList<V> list = new ArrayList<V>();
105
106 List<Class<?>> classes = ReflectionUtils.getSuperClasses(key);
107
108 classes.add(0, key);
109
110 for (Class<?> clazz : classes) {
111 V value = map.get(clazz);
112
113 if (value != null) {
114 list.add(value);
115 }
116 }
117
118 return list;
119 }
120
121 /**
122 * Get value list for the declaring class of the provided element.
123 *
124 * @see #getAll(Class)
125 */
126 public List<V> getAll(T element) {
127 return getAll(element.getClass());
128 }
129
130 /**
131 * Get value stored for this class. Unlike {@link #get(Class)} this does not
132 * retrieve values stored for super classes.
133 */
134 public V getDeclared(Class<?> key) {
135 return map.get(key);
136 }
137
138 /**
139 * Get value stored for the declaring class of the provided element. Unlike
140 * {@link #get(Object)} this does not retrieve values stored for super
141 * classes.
142 */
143 public V getDeclared(T element) {
144 return getDeclared(element.getClass());
145 }
146
147 /**
148 * @see java.util.Map#isEmpty()
149 */
150 public boolean isEmpty() {
151 return map.isEmpty();
152 }
153
154 /**
155 * @see java.util.Map#keySet()
156 */
157 public Set<Class<? extends T>> keySet() {
158 return map.keySet();
159 }
160
161 /**
162 * Store a key-value-pair.
163 *
164 * @see java.util.Map#put(Object, Object)
165 */
166 public V put(Class<? extends T> key, V value) {
167 return map.put(key, value);
168 }
169
170 /**
171 * @see java.util.Map#remove(Object)
172 */
173 public V remove(Class<?> key) {
174 return map.remove(key);
175 }
176
177 /**
178 * @see java.util.Map#size()
179 */
180 public int size() {
181 return map.size();
182 }
183
184 /**
185 * @see java.util.Map#values()
186 */
187 public Collection<V> values() {
188 return map.values();
189 }
190 }