Project

General

Profile

Download (4.88 KB) Statistics
| Branch: | Tag: | Revision:
1
/**
2
* Copyright (C) 2007 EDIT
3
* European Distributed Institute of Taxonomy
4
* http://www.e-taxonomy.eu
5
*
6
* The contents of this file are subject to the Mozilla Public License Version 1.1
7
* See LICENSE.TXT at the top of this package for the full license terms.
8
*/
9
package eu.etaxonomy.cdm.persistence.dao;
10

    
11
import java.lang.reflect.Method;
12
import java.util.ArrayList;
13
import java.util.Arrays;
14
import java.util.HashMap;
15
import java.util.List;
16
import java.util.Map;
17

    
18
import org.springframework.stereotype.Component;
19

    
20
/**
21
 * @author n.hoffmann
22
 * @since Mar 11, 2010
23
 */
24
@Component
25
public class MethodCacheImpl implements IMethodCache {
26

    
27
    //	MethodUtils
28

    
29
	private Map<MethodDescriptor, Method> methodMap = new HashMap<MethodDescriptor, Method>();
30

    
31
	@Override
32
    public Method getMethod(Class clazz, String methodName, Class parameterType) {
33
		MethodDescriptor methodDescriptor = new MethodDescriptor(clazz, methodName, new Class[]{parameterType});
34

    
35
		if(methodMap.containsKey(methodDescriptor)){
36
			return methodMap.get(methodDescriptor);
37
		}
38

    
39
		Method method = getMethodInternal(clazz, methodName, parameterType);
40
		if(method != null){
41
			method.setAccessible(true);
42
		}
43
		// we also put null methods into the map to benefit from caching
44
		put(methodDescriptor, method);
45

    
46
		return method;
47
	}
48

    
49
	/**
50
	 * Checks class hierarchy of the given class for a method that fits to the given name and parameter type
51
	 *
52
	 * @param clazz
53
	 * @param methodName
54
	 * @param parameterType
55
	 * @return
56
	 */
57
	private Method getMethodInternal(Class clazz, String methodName,
58
			Class parameterType){
59
		// stop recursing when there are no more superclasses
60
		if(clazz == null){
61
			return null;
62
		}
63

    
64
		Method method = null;
65

    
66
		for(Class includedType : getIncludedTypes(parameterType, new ArrayList<Class>())){
67
			try {
68
				method = clazz.getDeclaredMethod(methodName, includedType);
69
			}catch (NoSuchMethodException e) {
70

    
71
			}
72
		}
73

    
74
		// if we have a method return it
75
		if(method != null){
76
			return method;
77
		}
78

    
79
		// recurse into superclass if no method was found
80
		return getMethodInternal(clazz.getSuperclass(), methodName, parameterType);
81
	}
82

    
83
	/**
84
	 * Create a list containing the type and all supertypes of a given type
85
	 *
86
	 * @param clazz
87
	 * @param classList
88
	 * @return
89
	 */
90
	private List<Class> getIncludedTypes(Class clazz, List<Class> classList){
91
		if(clazz == null){
92
			return classList;
93
		}
94
		classList.add(clazz);
95
		Class[] interfaces = clazz.getInterfaces();
96
		if(interfaces != null){
97
			classList.addAll(Arrays.asList(interfaces));
98
		}
99
		return getIncludedTypes(clazz.getSuperclass(), classList);
100
	}
101

    
102
	/**
103
	 * Fill the cache
104
	 *
105
	 * @param methodDescriptor
106
	 * @param method
107
	 */
108
	private void put(MethodDescriptor methodDescriptor, Method method) {
109
		methodMap.put(methodDescriptor, method);
110
	}
111

    
112
	/**
113
	 * @author n.hoffmann
114
	 * @since Mar 11, 2010
115
	 */
116
	private static class MethodDescriptor{
117

    
118
		/** An empty class array */
119
	    private static final Class[] emptyClassArray = new Class[0];
120

    
121
		private Class clazz;
122
	    private String methodName;
123
	    private Class[] parameterTypes;
124
	    private int hashCode;
125

    
126
	    /**
127
	     * The sole constructor.
128
	     *
129
	     * @param clazz  the class to reflect, must not be null
130
	     * @param methodName  the method name to obtain
131
	     * @param paramTypes the array of classes representing the paramater types
132
	     * @param exact whether the match has to be exact.
133
	     */
134
	    public MethodDescriptor(Class clazz, String methodName, Class[] paramTypes) {
135
	        if (clazz == null) {
136
	            throw new IllegalArgumentException("Class cannot be null");
137
	        }
138
	        if (methodName == null) {
139
	            throw new IllegalArgumentException("Method Name cannot be null");
140
	        }
141
	        if (paramTypes == null) {
142
	            paramTypes = emptyClassArray;
143
	        }
144

    
145
	        this.clazz = clazz;
146
	        this.methodName = methodName;
147
	        this.parameterTypes = paramTypes;
148

    
149
	        this.hashCode = methodName.length();
150
	    }
151

    
152
	    /**
153
	     * Checks for equality.
154
	     * @param object object to be tested for equality
155
	     * @return true, if the object describes the same Method.
156
	     */
157
	    @Override
158
        public boolean equals(Object object) {
159
	        if (!(object instanceof MethodDescriptor)) {
160
	            return false;
161
	        }
162
	        MethodDescriptor methodDescriptor = (MethodDescriptor)object;
163

    
164
	        return (
165
	            methodName.equals(methodDescriptor.methodName) &&
166
	            clazz.equals(methodDescriptor.clazz) &&
167
	            java.util.Arrays.equals(parameterTypes, methodDescriptor.parameterTypes)
168
	        );
169
	    }
170
	    /**
171
	     * Returns the string length of method name. I.e. if the
172
	     * hashcodes are different, the objects are different. If the
173
	     * hashcodes are the same, need to use the equals method to
174
	     * determine equality.
175
	     * @return the string length of method name.
176
	     */
177
	    @Override
178
        public int hashCode() {
179
	        return hashCode;
180
	    }
181
	}
182
}
(3-3/4)