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