package org.sef4j.core.helpers.adapters;
import java.util.HashMap;
import java.util.Map;
import java.util.WeakHashMap;
/**
*
*/
public class TypeHierarchyToObjectMap<T> {
private Map<Class<?>,T> overrideForClassMap = new HashMap<Class<?>,T>();
// private Map<Class<?>,T> overrideForInterfaceMap = new HashMap<Class<?>,T>();
private WeakHashMap<Class<?>,T> cachedPerClassMap = new WeakHashMap<Class<?>,T>();
// ------------------------------------------------------------------------
public TypeHierarchyToObjectMap() {
}
// ------------------------------------------------------------------------
public void putOverride(Class<?> key, T value) {
overrideForClassMap.put(key, value);
cachedPerClassMap.clear();
}
public T getOverride(Class<?> key) {
return overrideForClassMap.get(key);
}
public void removeOverride(Class<?> key) {
overrideForClassMap.remove(key);
cachedPerClassMap.clear();
}
// ------------------------------------------------------------------------
public T get(Class<?> key) {
T res = cachedPerClassMap.get(key);
if (res == null) {
if (key.isInterface()) {
res = doGetPerInterfaceOrSuperInterface(key);
} else {
res = doGetPerClassOrSuperClass(key);
}
cachedPerClassMap.put(key, res);
}
return res;
}
// ------------------------------------------------------------------------
private T doGetPerClassOrSuperClass(Class<?> clss) {
T res = null;
Class<?> currClss = clss;
for(; ; currClss = currClss.getSuperclass()) {
if (currClss == null) {
break; // superclass of Object, or interface
}
res = overrideForClassMap.get(currClss);
if (res != null) {
return res;
}
Class<?>[] interfaces = currClss.getInterfaces();
if (interfaces.length != 0) {
for(int i = 0; i < interfaces.length; i++) {
res = overrideForClassMap.get(interfaces[i]);
if (res != null) {
return res;
}
// cf next to find for super interfaces! (after super class scanning)
}
}
}
// second lookup, per super class -> super interfaces
currClss = clss;
for(; ; currClss = currClss.getSuperclass()) {
if (currClss == null) {
break; // superclass of Object, or interface
}
Class<?>[] interfaces = currClss.getInterfaces();
if (interfaces.length != 0) {
for(int i = 0; i < interfaces.length; i++) {
res = get(interfaces[i]); // => recurse in doGetPerInterfaceOrSuperInterface()
if (res != null) {
return res;
}
// cf next to find for super interfaces! (after super class scanning)
}
}
}
return null;
}
private T doGetPerInterfaceOrSuperInterface(Class<?> clss) {
T res = overrideForClassMap.get(clss);
if (res != null) {
return res;
}
Class<?>[] interfaces = clss.getInterfaces();
if (interfaces.length != 0) {
for(int i = 0; i < interfaces.length; i++) {
res = get(interfaces[i]); // => cache + recurse in doGetPerInterfaceOrSuperInterface()
if (res != null) {
return res;
}
}
}
return null;
}
}