001: /*
002:
003: This software is OSI Certified Open Source Software.
004: OSI Certified is a certification mark of the Open Source Initiative.
005:
006: The license (Mozilla version 1.0) can be read at the MMBase site.
007: See http://www.MMBase.org/license
008:
009: */
010: package org.mmbase.util.functions;
011:
012: import java.lang.reflect.*;
013: import java.lang.annotation.*;
014:
015: /**
016: * A function based on an abritrary method. Since the name of the parameters cannot be found by
017: * reflection, this is only of limited use. Normally you would probably better use BeanFunction. A
018: * method-function can come in handy on JSP's. With the advent of java 1.5 we can use annotations to
019: * annotate acutal parameter names.
020: *
021: * @author Michiel Meeuwissen
022: * @version $Id: MethodFunction.java,v 1.11 2007/11/25 18:25:49 nklasens Exp $
023: * @see org.mmbase.module.core.MMObjectBuilder#executeFunction
024: * @see org.mmbase.bridge.Node#getFunctionValue
025: * @see org.mmbase.util.functions.BeanFunction
026: * @since MMBase-1.7
027: */
028: public class MethodFunction extends AbstractFunction<Object> {
029:
030: public static Function<Object> getFunction(Method method,
031: String name) {
032: return new MethodFunction(method, name); // could be cached...
033: }
034:
035: /**
036: * @since MMBase-1.9
037: */
038: public static Function<Object> getFunction(Method method,
039: String name, Object instance) {
040: return new MethodFunction(method, name, instance); // could be cached...
041: }
042:
043: /**
044: * Returns the MethodFunction representing the method 'name' in class 'clazz'. If there are more
045: * methods whith that name, the one with the largest number of by name annotated parameters is taken.
046: * @since MMBase-1.9
047: */
048: public static Function<Object> getFunction(Class<?> clazz,
049: String name) {
050: // Finding method to use
051: Method method = getMethod(clazz, name);
052: return getFunction(method, method.getName());
053: }
054:
055: public static Method getMethod(Class<?> clazz, String name) {
056: // Finding method to use
057: Method method = null;
058: float score = -1.0f;
059: for (Method m : clazz.getMethods()) {
060: String methodName = m.getName();
061: if (methodName.equals(name)) {
062: Annotation[][] annots = m.getParameterAnnotations();
063: int found = 0;
064: int total = 1; // avoids division by zero and ensures that methods with more parameters are better.
065: for (Annotation[] anot : annots) {
066: for (Annotation a : anot) {
067: if (a.annotationType().equals(Name.class)) {
068: found++;
069: }
070: }
071: total++;
072: }
073: if ((float) found / total > score) {
074: method = m;
075: score = (float) found / total;
076: }
077: }
078: }
079: return method;
080: }
081:
082: private final Method method;
083: private final Object instance;
084:
085: /**
086: * @since MMBase-1.9
087: */
088: public MethodFunction(Method method) {
089: this (method, method.getName(), null);
090: }
091:
092: public MethodFunction(Method method, String name) {
093: this (method, name, null);
094: }
095:
096: /**
097: * @since MMBase-1.9
098: */
099: public MethodFunction(Method method, Object instance) {
100: this (method, method.getName(), instance);
101: }
102:
103: /**
104: * @since MMBase-1.9
105: */
106: public MethodFunction(Method method, String name, Object instance) {
107: super (name, null, null);
108: this .method = method;
109: this .instance = instance;
110: if (instance == null) {
111: if (!Modifier.isStatic(method.getModifiers())) {
112: throw new IllegalArgumentException("The method "
113: + method + " is not static"); // otherwise NPE in getFunctionValue
114: }
115: } else {
116: if (!method.getDeclaringClass().isInstance(instance)) {
117: throw new IllegalArgumentException("The object "
118: + instance
119: + " is not an instance of the class of "
120: + method);
121: }
122: }
123:
124: Annotation[][] annots = method.getParameterAnnotations();
125: Class[] parameters = method.getParameterTypes();
126: Parameter<?>[] def = new Parameter[parameters.length];
127: for (int i = 0; i < parameters.length; i++) {
128: String paramName = null;
129: for (Annotation annot : annots[i]) {
130: if (annot.annotationType().equals(Name.class)) {
131: paramName = ((Name) annot).value();
132: }
133: }
134: if (paramName == null)
135: paramName = "parameter" + (i + 1);
136:
137: def[i] = new Parameter<String>(paramName, parameters[i]); // no way to find the name of the parameter
138: }
139:
140: setParameterDefinition(def);
141:
142: ReturnType returnType = ReturnType.getReturnType(method
143: .getReturnType());
144: setReturnType(returnType);
145:
146: }
147:
148: public Object getFunctionValue(Parameters parameters) {
149: try {
150: return method.invoke(instance, parameters.toArray());
151: } catch (Exception e) {
152: throw new RuntimeException(e);
153: }
154: }
155:
156: }
|