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    }