Project

General

Profile

Download (5.16 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

    
10
package eu.etaxonomy.cdm.persistence.dao;
11

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

    
19
import org.apache.log4j.Logger;
20
import org.springframework.stereotype.Component;
21

    
22
/**
23
 * @author n.hoffmann
24
 * @since Mar 11, 2010
25
 * @version 1.0
26
 */
27
@Component
28
public class MethodCacheImpl implements IMethodCache {
29
	
30
//	MethodUtils
31
	
32
	private Map<MethodDescriptor, Method> methodMap = new HashMap<MethodDescriptor, Method>();
33

    
34
	/*
35
	 * (non-Javadoc)
36
	 * @see eu.etaxonomy.cdm.persistence.dao.IMethodCache#getMethod(java.lang.Class, java.lang.String, java.lang.Class)
37
	 */
38
	public Method getMethod(Class clazz, String methodName, Class parameterType) {
39
		MethodDescriptor methodDescriptor = new MethodDescriptor(clazz, methodName, new Class[]{parameterType}); 
40
		
41
		if(methodMap.containsKey(methodDescriptor)){
42
			return methodMap.get(methodDescriptor);
43
		}
44
		
45
		Method method = getMethodInternal(clazz, methodName, parameterType);
46
		if(method != null){
47
			method.setAccessible(true);
48
		}
49
		// we also put null methods into the map to benefit from caching
50
		put(methodDescriptor, method);
51
		
52
		return method; 
53
	}
54
	
55
	/**
56
	 * Checks class hierarchy of the given class for a method that fits to the given name and parameter type
57
	 * 
58
	 * @param clazz
59
	 * @param methodName
60
	 * @param parameterType
61
	 * @return
62
	 */
63
	private Method getMethodInternal(Class clazz, String methodName,
64
			Class parameterType){
65
		// stop recursing when there are no more superclasses
66
		if(clazz == null){
67
			return null;
68
		}
69
		
70
		Method method = null;
71
		
72
		for(Class includedType : getIncludedTypes(parameterType, new ArrayList<Class>())){
73
			try {
74
				method = clazz.getDeclaredMethod(methodName, includedType);
75
			}catch (NoSuchMethodException e) {
76
				;
77
			} 
78
		}
79
		
80
		// if we have a method return it
81
		if(method != null){
82
			return method;
83
		}
84
			
85
		// recurse into superclass if no method was found
86
		return getMethodInternal(clazz.getSuperclass(), methodName, parameterType);
87
	}
88
	
89
	/**
90
	 * Create a list containing the type and all supertypes of a given type
91
	 * 
92
	 * @param clazz
93
	 * @param classList
94
	 * @return
95
	 */
96
	private List<Class> getIncludedTypes(Class clazz, List<Class> classList){
97
		if(clazz == null){
98
			return classList;
99
		}
100
		classList.add(clazz);
101
		Class[] interfaces = clazz.getInterfaces();
102
		if(interfaces != null){
103
			classList.addAll(Arrays.asList(interfaces));
104
		}
105
		return getIncludedTypes(clazz.getSuperclass(), classList);
106
	}
107
	
108
	/**
109
	 * Fill the cache
110
	 * 
111
	 * @param methodDescriptor
112
	 * @param method
113
	 */
114
	private void put(MethodDescriptor methodDescriptor, Method method) {
115
		methodMap.put(methodDescriptor, method);
116
	}
117
	
118
	/**
119
	 * 
120
	 * @author n.hoffmann
121
	 * @since Mar 11, 2010
122
	 * @version 1.0
123
	 */
124
	private static class MethodDescriptor{
125
		private static final Logger logger = Logger
126
				.getLogger(MethodDescriptor.class);
127
		
128
		/** An empty class array */
129
	    private static final Class[] emptyClassArray = new Class[0];
130
		
131
		private Class clazz;
132
	    private String methodName;
133
	    private Class[] parameterTypes;
134
	    private int hashCode;
135

    
136
	    /**
137
	     * The sole constructor.
138
	     *
139
	     * @param clazz  the class to reflect, must not be null
140
	     * @param methodName  the method name to obtain
141
	     * @param paramTypes the array of classes representing the paramater types
142
	     * @param exact whether the match has to be exact.
143
	     */
144
	    public MethodDescriptor(Class clazz, String methodName, Class[] paramTypes) {
145
	        if (clazz == null) {
146
	            throw new IllegalArgumentException("Class cannot be null");
147
	        }
148
	        if (methodName == null) {
149
	            throw new IllegalArgumentException("Method Name cannot be null");
150
	        }
151
	        if (paramTypes == null) {
152
	            paramTypes = emptyClassArray;
153
	        }
154

    
155
	        this.clazz = clazz;
156
	        this.methodName = methodName;
157
	        this.parameterTypes = paramTypes;
158

    
159
	        this.hashCode = methodName.length();
160
	    }
161
	    /**
162
	     * Checks for equality.
163
	     * @param object object to be tested for equality
164
	     * @return true, if the object describes the same Method.
165
	     */
166
	    public boolean equals(Object object) {
167
	        if (!(object instanceof MethodDescriptor)) {
168
	            return false;
169
	        }
170
	        MethodDescriptor methodDescriptor = (MethodDescriptor)object;
171

    
172
	        return (
173
	            methodName.equals(methodDescriptor.methodName) &&
174
	            clazz.equals(methodDescriptor.clazz) &&
175
	            java.util.Arrays.equals(parameterTypes, methodDescriptor.parameterTypes)
176
	        );
177
	    }
178
	    /**
179
	     * Returns the string length of method name. I.e. if the
180
	     * hashcodes are different, the objects are different. If the
181
	     * hashcodes are the same, need to use the equals method to
182
	     * determine equality.
183
	     * @return the string length of method name.
184
	     */
185
	    public int hashCode() {
186
	        return hashCode;
187
	    }		
188
	}	
189
}
(3-3/4)