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}