Source code: org/gui4j/core/Gui4jReflectionManager.java
1 package org.gui4j.core;
2
3 import java.io.Serializable;
4 import java.lang.reflect.InvocationTargetException;
5 import java.lang.reflect.Method;
6 import java.util.ArrayList;
7 import java.util.HashMap;
8 import java.util.List;
9 import java.util.Map;
10
11 import org.apache.commons.logging.Log;
12 import org.apache.commons.logging.LogFactory;
13 import org.gui4j.core.util.MethodCall;
14 import org.gui4j.core.util.MethodCallReflection;
15 import org.gui4j.exception.ErrorTags;
16 import org.gui4j.exception.Gui4jUncheckedException;
17
18
19 /**
20 * Supports methods to method declarations by most specific argument types
21 * There is always one instance of this manager in order to cache
22 * method declarations.
23 *
24 * @author Joachim Schmid
25 */
26 public final class Gui4jReflectionManager implements ErrorTags, Serializable
27 {
28 private static final Log mLogger = LogFactory.getLog(Gui4jReflectionManager.class);
29 private final Map mMethodsClass;
30 private final Map mMethodsName;
31
32 private Gui4jReflectionManager()
33 {
34 mMethodsClass = new HashMap();
35 mMethodsName = new HashMap();
36 }
37
38 /**
39 * Returns always the same instance
40 * @return Gui4jReflectionManager
41 */
42 public static Gui4jReflectionManager getNewInstance()
43 {
44 return new Gui4jReflectionManager();
45 }
46
47 public MethodCall getMethod(
48 String context,
49 Class c,
50 String methodName,
51 Class[] argumentsInit,
52 boolean throwExceptionIfNotFound)
53 {
54 Method[] methods = getMethods(c, methodName);
55 Class[] arguments = new Class[argumentsInit.length];
56 String[] argumentsStr = new String[argumentsInit.length];
57 for (int i = 0; i < argumentsInit.length; i++)
58 {
59 arguments[i] = argumentsInit[i];
60 argumentsStr[i] = argumentsInit[i].getName();
61 /*
62 if (arguments[i].equals(Integer.TYPE))
63 {
64 arguments[i] = Integer.class;
65 }
66 */
67 }
68
69 Method lastMethod = null;
70 for (int i = 0; i < methods.length; i++)
71 {
72 if (matching(methods[i], arguments))
73 {
74 if (lastMethod == null)
75 {
76 lastMethod = methods[i];
77 }
78 else
79 {
80 if (moreSpecific(methods[i], lastMethod))
81 {
82 lastMethod = methods[i];
83 }
84 else if (moreSpecific(lastMethod, methods[i]))
85 {
86 // do nothing
87 }
88 else
89 {
90 String signature = arr2List(argumentsStr).toString();
91 signature = signature.replace('[', '(');
92 signature = signature.replace(']', ')');
93 Object[] args = { c, methodName, signature };
94 mLogger.warn("Method ambiguous; context " + context);
95 mLogger.info("Method 1 = " + lastMethod);
96 mLogger.info("Method 2 = " + methods[i]);
97 throw new Gui4jUncheckedException.ProgrammingError(
98 PROGRAMMING_ERROR_method_ambiguous,
99 args);
100 }
101 }
102 }
103 }
104 if (lastMethod == null && throwExceptionIfNotFound)
105 {
106 String signature = arr2List(argumentsStr).toString();
107 signature = signature.replace('[', '(');
108 signature = signature.replace(']', ')');
109 Object[] args = { c.getName(), methodName, signature, context };
110 mLogger.warn("Method not defined; context " + context);
111 throw new Gui4jUncheckedException.ProgrammingError(PROGRAMMING_ERROR_method_not_found, args);
112 }
113
114 /*
115 if (methodName.indexOf("getValue")!=-1 && c.getName().indexOf("Ansprache")!=-1)
116 {
117 String signature = arr2List(argumentsStr).toString();
118 signature = signature.replace('[', '(');
119 signature = signature.replace(']', ')');
120
121 mLogger.debug("Resolve of "+c.getName()+"."+methodName+signature+" = " +lastMethod);
122 }
123 */
124 return MethodCallReflection.getInstance(lastMethod);
125 }
126
127 /**
128 * Searches for the given class the most specific method. If no
129 * method is found, or if the result is ambiguous, an exception is raised
130 * @param context
131 * @param c
132 * @param methodName
133 * @param argumentsInit
134 * @return MethodCall
135 */
136 public MethodCall getMethod(String context, Class c, String methodName, Class[] argumentsInit)
137 {
138 return getMethod(context, c, methodName, argumentsInit, true);
139 }
140
141 private List arr2List(Object[] arr)
142 {
143 List l = new ArrayList();
144 for (int i = 0; i < arr.length; i++)
145 {
146 l.add(arr[i]);
147 }
148 return l;
149 }
150
151 private boolean moreSpecific(Method m1, Method m2)
152 {
153 Class[] parameterTypes1 = m1.getParameterTypes();
154 Class[] parameterTypes2 = m2.getParameterTypes();
155 int n = parameterTypes1.length;
156 for (int i = 0; i < n; i++)
157 {
158 if (!parameterTypes2[i].isAssignableFrom(parameterTypes1[i]))
159 {
160 return false;
161 }
162 }
163 return true;
164 }
165
166 private boolean matching(Method m, Class[] arguments)
167 {
168 Class[] parameterTypes = m.getParameterTypes();
169 if (parameterTypes.length != arguments.length)
170 {
171 return false;
172 }
173 for (int i = 0; i < parameterTypes.length; i++)
174 {
175 if (!parameterTypes[i].isAssignableFrom(arguments[i]))
176 // !arguments[i].isAssignableFrom(parameterTypes[i]))
177 {
178 return false;
179 }
180 }
181 return true;
182 }
183
184 private synchronized Method[] getMethods(Class c, String methodName)
185 {
186 Method[] m = (Method[]) mMethodsName.get(c + "/" + methodName);
187 if (m == null)
188 {
189 Method[] methods = getMethods(c);
190 List methodList = new ArrayList();
191 for (int i = 0; i < methods.length; i++)
192 {
193 if (methods[i].getName().equals(methodName))
194 {
195 methodList.add(methods[i]);
196 }
197 }
198 m = new Method[methodList.size()];
199 for (int i = 0; i < m.length; i++)
200 {
201 m[i] = (Method) methodList.get(i);
202 }
203 mMethodsName.put(c + "/" + methodName, m);
204 }
205 return m;
206 }
207
208 private synchronized Method[] getMethods(Class c)
209 {
210 Method[] methods = (Method[]) mMethodsClass.get(c);
211 if (methods == null)
212 {
213 methods = c.getMethods();
214 /*
215 for (int i = 0; i < methods.length; i++)
216 {
217 Method m = methods[i];
218 try
219 {
220 methods[i] = c.getMethod(m.getName(),m.getParameterTypes());
221 System.out.println("Class: "+c.getName()+": "+methods[i]);
222 }
223 catch (NoSuchMethodException e)
224 {
225 String[] args = { c.getName(), m.getName(), m.toString() };
226 throw new Gui4jUncheckedException.ProgrammingError(PROGRAMMING_ERROR_method_not_found,args);
227 }
228 }
229 */
230 mMethodsClass.put(c, methods);
231 }
232 return methods;
233 }
234
235 /**
236 * Clear the cache in order to use new method declarations
237 */
238 public synchronized void reload()
239 {
240 mMethodsClass.clear();
241 mMethodsName.clear();
242 }
243
244 public static void handleInvocationTargetException(InvocationTargetException e)
245 {
246 Throwable t = e.getTargetException();
247 if (t != null)
248 {
249 if (t instanceof RuntimeException)
250 {
251 throw (RuntimeException) t;
252 }
253 if (t instanceof Error)
254 {
255 throw (Error) t;
256 }
257 }
258 }
259
260 }