001: package org.gui4j.core;
002:
003: import java.io.Serializable;
004: import java.lang.reflect.InvocationTargetException;
005: import java.lang.reflect.Method;
006: import java.util.ArrayList;
007: import java.util.HashMap;
008: import java.util.List;
009: import java.util.Map;
010:
011: import org.apache.commons.logging.Log;
012: import org.apache.commons.logging.LogFactory;
013: import org.gui4j.core.util.MethodCall;
014: import org.gui4j.core.util.MethodCallReflection;
015: import org.gui4j.exception.ErrorTags;
016: import org.gui4j.exception.Gui4jUncheckedException;
017:
018: /**
019: * Supports methods to method declarations by most specific argument types
020: * There is always one instance of this manager in order to cache
021: * method declarations.
022: *
023: * @author Joachim Schmid
024: */
025: public final class Gui4jReflectionManager implements ErrorTags,
026: Serializable {
027: private static final Log mLogger = LogFactory
028: .getLog(Gui4jReflectionManager.class);
029: private final Map mMethodsClass;
030: private final Map mMethodsName;
031:
032: private Gui4jReflectionManager() {
033: mMethodsClass = new HashMap();
034: mMethodsName = new HashMap();
035: }
036:
037: public void dispose() {
038: mMethodsClass.clear();
039: mMethodsName.clear();
040: }
041:
042: /**
043: * Returns always the same instance
044: * @return Gui4jReflectionManager
045: */
046: public static Gui4jReflectionManager getNewInstance() {
047: return new Gui4jReflectionManager();
048: }
049:
050: public MethodCall getMethod(String context, Class c,
051: String methodName, Class[] argumentsInit,
052: boolean throwExceptionIfNotFound) {
053: Method[] methods = getMethods(c, methodName);
054: Class[] arguments = new Class[argumentsInit.length];
055: String[] argumentsStr = new String[argumentsInit.length];
056: for (int i = 0; i < argumentsInit.length; i++) {
057: arguments[i] = argumentsInit[i];
058: argumentsStr[i] = argumentsInit[i].getName();
059: /*
060: if (arguments[i].equals(Integer.TYPE))
061: {
062: arguments[i] = Integer.class;
063: }
064: */
065: }
066:
067: Method lastMethod = null;
068: for (int i = 0; i < methods.length; i++) {
069: if (matching(methods[i], arguments)) {
070: if (lastMethod == null) {
071: lastMethod = methods[i];
072: } else {
073: if (moreSpecific(methods[i], lastMethod)) {
074: lastMethod = methods[i];
075: } else if (moreSpecific(lastMethod, methods[i])) {
076: // do nothing
077: } else {
078: String signature = arr2List(argumentsStr)
079: .toString();
080: signature = signature.replace('[', '(');
081: signature = signature.replace(']', ')');
082: Object[] args = { c, methodName, signature };
083: mLogger.warn("Method ambiguous; context "
084: + context);
085: mLogger.info("Method 1 = " + lastMethod);
086: mLogger.info("Method 2 = " + methods[i]);
087: throw new Gui4jUncheckedException.ProgrammingError(
088: PROGRAMMING_ERROR_method_ambiguous,
089: args);
090: }
091: }
092: }
093: }
094: if (lastMethod == null && throwExceptionIfNotFound) {
095: String signature = arr2List(argumentsStr).toString();
096: signature = signature.replace('[', '(');
097: signature = signature.replace(']', ')');
098: Object[] args = { c.getName(), methodName, signature,
099: context };
100: mLogger.warn("Method not defined; context " + context);
101: throw new Gui4jUncheckedException.ProgrammingError(
102: PROGRAMMING_ERROR_method_not_found, args);
103: }
104:
105: /*
106: if (methodName.indexOf("getValue")!=-1 && c.getName().indexOf("Ansprache")!=-1)
107: {
108: String signature = arr2List(argumentsStr).toString();
109: signature = signature.replace('[', '(');
110: signature = signature.replace(']', ')');
111:
112: mLogger.debug("Resolve of "+c.getName()+"."+methodName+signature+" = " +lastMethod);
113: }
114: */
115: return MethodCallReflection.getInstance(lastMethod);
116: }
117:
118: /**
119: * Searches for the given class the most specific method. If no
120: * method is found, or if the result is ambiguous, an exception is raised
121: * @param context
122: * @param c
123: * @param methodName
124: * @param argumentsInit
125: * @return MethodCall
126: */
127: public MethodCall getMethod(String context, Class c,
128: String methodName, Class[] argumentsInit) {
129: return getMethod(context, c, methodName, argumentsInit, true);
130: }
131:
132: private List arr2List(Object[] arr) {
133: List l = new ArrayList();
134: for (int i = 0; i < arr.length; i++) {
135: l.add(arr[i]);
136: }
137: return l;
138: }
139:
140: private boolean moreSpecific(Method m1, Method m2) {
141: Class[] parameterTypes1 = m1.getParameterTypes();
142: Class[] parameterTypes2 = m2.getParameterTypes();
143: int n = parameterTypes1.length;
144: for (int i = 0; i < n; i++) {
145: if (!parameterTypes2[i]
146: .isAssignableFrom(parameterTypes1[i])) {
147: return false;
148: }
149: }
150: return true;
151: }
152:
153: private boolean matching(Method m, Class[] arguments) {
154: Class[] parameterTypes = m.getParameterTypes();
155: if (parameterTypes.length != arguments.length) {
156: return false;
157: }
158: for (int i = 0; i < parameterTypes.length; i++) {
159: if (!parameterTypes[i].isAssignableFrom(arguments[i]))
160: // !arguments[i].isAssignableFrom(parameterTypes[i]))
161: {
162: return false;
163: }
164: }
165: return true;
166: }
167:
168: private synchronized Method[] getMethods(Class c, String methodName) {
169: Method[] m = (Method[]) mMethodsName.get(c + "/" + methodName);
170: if (m == null) {
171: Method[] methods = getMethods(c);
172: List methodList = new ArrayList();
173: for (int i = 0; i < methods.length; i++) {
174: if (methods[i].getName().equals(methodName)) {
175: methodList.add(methods[i]);
176: }
177: }
178: m = new Method[methodList.size()];
179: for (int i = 0; i < m.length; i++) {
180: m[i] = (Method) methodList.get(i);
181: }
182: mMethodsName.put(c + "/" + methodName, m);
183: }
184: return m;
185: }
186:
187: private synchronized Method[] getMethods(Class c) {
188: Method[] methods = (Method[]) mMethodsClass.get(c);
189: if (methods == null) {
190: methods = c.getMethods();
191: /*
192: for (int i = 0; i < methods.length; i++)
193: {
194: Method m = methods[i];
195: try
196: {
197: methods[i] = c.getMethod(m.getName(),m.getParameterTypes());
198: System.out.println("Class: "+c.getName()+": "+methods[i]);
199: }
200: catch (NoSuchMethodException e)
201: {
202: String[] args = { c.getName(), m.getName(), m.toString() };
203: throw new Gui4jUncheckedException.ProgrammingError(PROGRAMMING_ERROR_method_not_found,args);
204: }
205: }
206: */
207: mMethodsClass.put(c, methods);
208: }
209: return methods;
210: }
211:
212: /**
213: * Clear the cache in order to use new method declarations
214: */
215: public synchronized void reload() {
216: mMethodsClass.clear();
217: mMethodsName.clear();
218: }
219:
220: public static void handleInvocationTargetException(
221: InvocationTargetException e) {
222: Throwable t = e.getTargetException();
223: if (t != null) {
224: if (t instanceof RuntimeException) {
225: throw (RuntimeException) t;
226: }
227: if (t instanceof Error) {
228: throw (Error) t;
229: }
230: }
231: }
232:
233: }
|