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.util.*;
014:
015: import org.mmbase.util.logging.*;
016:
017: /**
018: * This class defines static methods for defining Function and Parameters objects.
019: * These methods include ways to retrieve Function definitions for a class using reflection,
020: * and methods to convert a List to a Parameters object, and a Parameter array to a
021: * List.
022: *
023: * @since MMBase-1.8
024: * @author Pierre van Rooden
025: * @author Daniel Ockeloen
026: * @author Michiel Meeuwissen
027: * @version $Id: Functions.java,v 1.17 2007/11/25 18:25:49 nklasens Exp $
028: */
029: public class Functions {
030:
031: private static final Logger log = Logging
032: .getLoggerInstance(Functions.class);
033:
034: /**
035: * Converts a certain List to an Parameters if it is not already one.
036: */
037: public static Parameters buildParameters(Parameter<?>[] def,
038: List<?> args) {
039: Parameters a;
040: if (args instanceof Parameters) {
041: a = (Parameters) args;
042: } else {
043: a = new Parameters(def, args);
044: }
045: return a;
046: }
047:
048: /**
049: * Adds the definitions to a List. Resolves the {@link Parameter.Wrapper}'s (recursively).
050: * @return List with only simple Parameter's.
051: */
052: public static List<Parameter<?>> define(Parameter<?>[] def,
053: List<Parameter<?>> list) {
054: if (def == null)
055: return list;
056: for (Parameter d : def) {
057: if (d instanceof Parameter.Wrapper) {
058: define(((Parameter.Wrapper) d).arguments, list);
059: } else {
060: list.add(d);
061: }
062: }
063: return list;
064: }
065:
066: /**
067: * @since MMBase-1.9
068: */
069: public static List<Parameter<?>> define(Parameter<?>[] def) {
070: return define(def, new ArrayList<Parameter<?>>());
071: }
072:
073: /**
074: * @javadoc
075: */
076: public static Method getMethodFromClass(Class<?> claz, String name) {
077: Method method = null;
078: Method[] methods = claz.getMethods();
079: for (Method element : methods) {
080: if (element.getName().equals(name)) {
081: if (method != null) {
082: throw new IllegalArgumentException(
083: "There is more than one method with name '"
084: + name + "' in " + claz);
085: }
086: method = element;
087: }
088: }
089: if (method == null) {
090: throw new IllegalArgumentException(
091: "There is no method with name '" + name + "' in "
092: + claz);
093: }
094: return method;
095: }
096:
097: /**
098: * Generates a map of Parameter[] objects for a given class through reflection.
099: * The map keys are the names of te function the Parameter[] object belongs to.
100: * <br />
101: * The method parses the given class for constants (final static public members)
102: * of type Parameter[]. The member name up to the first underscore in that name
103: * is considered the name for a function supported by that class.
104: * i.e. :
105: * <pre>
106: * public final static Parameter[] AGE_PARAMETERS = {};
107: * </pre>
108: * defines a function 'age' which takes no parameters.
109: * <pre>
110: * public final static Parameter[] GUI_PARAMETERS = {
111: * new Parameter("field", String.class),
112: * Parameter.LANGUAGE
113: * }
114: * </pre>
115: * defines a function 'gui' which two parameters: 'field' and 'language'.
116: * Results form reflection are stored in an internal cache.
117: * The method returns the Parameter[] value (if any) of the function whose
118: * name was given in the call. If the function cannot be derived through
119: * reflection, the method returns <code>null</code>.<br />
120: * Note that, since this way of determining functions cannot determine
121: * return value types, it is advised to use {@link FunctionProvider#addFunction}
122: * instead.
123: *
124: * @see Parameter
125: * @param clazz the class to perform reflection on.
126: * @param map
127: * @return A map of parameter definitions (Parameter[] objects), keys by function name (String)
128: */
129: public static Map<String, Parameter<?>[]> getParameterDefinitonsByReflection(
130: Class<?> clazz, Map<String, Parameter<?>[]> map) {
131:
132: log.debug("Searching " + clazz);
133: Field[] fields = clazz.getDeclaredFields();
134: for (Field field : fields) {
135: int mod = field.getModifiers();
136: // only static public final Parameter[] constants are considered
137: if (Modifier.isStatic(mod) && Modifier.isPublic(mod)
138: && Modifier.isFinal(mod)
139: && field.getType().equals(Parameter[].class)) {
140: // get name (using convention)
141: String name = field.getName().toLowerCase();
142: int underscore = name.indexOf("_");
143: if (underscore > 0) {
144: name = name.substring(0, underscore);
145: }
146: if (!map.containsKey(name)) { // overriding works, but don't do backwards :-)
147: try {
148: Parameter<?>[] params = (Parameter<?>[]) field
149: .get(null);
150: if (log.isDebugEnabled()) {
151: log.debug("Found a function definition '"
152: + name + "' in " + clazz
153: + " with parameters "
154: + Arrays.asList(params));
155: }
156: map.put(name, params);
157: } catch (IllegalAccessException iae) {
158: // should not be thrown!
159: log
160: .error("Found inaccessible parameter[] constant: "
161: + field.getName());
162: }
163: }
164: }
165: }
166: Class<?> sup = clazz.getSuperclass();
167: if (sup != null) {
168: getParameterDefinitonsByReflection(sup, map);
169: }
170: return map;
171: }
172:
173: }
|