Project

General

Profile

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

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

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

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

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

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

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

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

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

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