KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > mmbase > util > functions > BeanFunction


1 /*
2
3 This software is OSI Certified Open Source Software.
4 OSI Certified is a certification mark of the Open Source Initiative.
5
6 The license (Mozilla version 1.0) can be read at the MMBase site.
7 See http://www.MMBase.org/license
8
9 */

10 package org.mmbase.util.functions;
11
12 import org.mmbase.cache.Cache;
13
14 import java.lang.reflect.*;
15 import java.util.*;
16 import org.mmbase.util.logging.*;
17
18 /**
19  * One or more functions based on a Java-bean. Every setter method of the bean corresponds with one
20  * parameter. The default value of the parameter can be defined with the getter method (which will
21  * be called immediately after instantiation of such a Class).
22  *
23  * All other methods (with no arguments) of the class correspond to the functions. So, you can
24  * implement more bean-functions in the same class, as long as they have the same parameters.
25  *
26  * A BeanFunction can be aquired via {@link FunctionFactory#getFunction(Class, String)} (which
27  * delegates to a static method in this class).
28  *
29  * @author Michiel Meeuwissen
30  * @version $Id: BeanFunction.java,v 1.8 2005/12/08 16:18:21 michiel Exp $
31  * @see org.mmbase.util.functions.MethodFunction
32  * @see org.mmbase.util.functions.FunctionFactory
33  * @since MMBase-1.8
34  */

35 public class BeanFunction extends AbstractFunction {
36     private static final Logger log = Logging.getLoggerInstance(BeanFunction.class);
37     /**
38      * Utility function, searches an inner class of a given class. This inner class can perhaps be used as a
39      * bean. Used in JSP/taglib.
40      * @param claz The class to be considered
41      * @param name The name of the inner class
42      * @throws IllegalArgumentException if claz has no inner class with that name
43      */

44     public static Class JavaDoc getClass(Class JavaDoc claz, String JavaDoc name) {
45         Class JavaDoc[] classes = claz.getDeclaredClasses();
46         for (int j=0; j < classes.length; j++) {
47             Class JavaDoc c = classes[j];
48             if (c.getName().endsWith("$" + name)) {
49                 return c;
50             }
51         }
52         throw new IllegalArgumentException JavaDoc("There is no inner class with name '" + name + "' in " + claz);
53     }
54
55     /**
56      * A cache for bean classes. Used to avoid some reflection.
57      */

58     private static Cache beanFunctionCache = new Cache(50) {
59         public String JavaDoc getName() {
60             return "BeanFunctionCache";
61         }
62         public String JavaDoc getDescription() {
63             return "ClassName.FunctionName -> BeanFunction object";
64         }
65     };
66
67     /**
68      * Gives back a Function object based on the 'bean' concept.
69      * Called from {@link FunctionFactory}
70      */

71     public static Function getFunction(Class JavaDoc claz, String JavaDoc name) throws IllegalAccessException JavaDoc, InstantiationException JavaDoc, InvocationTargetException {
72         String JavaDoc key = claz.getName() + '.' + name;
73         BeanFunction result = (BeanFunction) beanFunctionCache.get(key);
74         if (result == null) {
75             result = new BeanFunction(claz, name);
76             beanFunctionCache.put(key, result);
77         }
78         return result;
79     }
80
81     /* ================================================================================
82        Instance methods
83        ================================================================================
84     */

85
86     /**
87      * This class of the bean
88      */

89     private Class JavaDoc claz = null;
90
91     /**
92      * The method corresponding to the function called in getFunctionValue.
93      */

94     private Method method = null;
95
96     /**
97      * A list of all found setter methods. This list 1-1 corresponds with getParameterDefinition. Every Parameter belongs to a setter method.
98      */

99     private List setMethods = new ArrayList();
100
101
102
103     /**
104      * The constructor! Performs reflection to fill 'method' and 'setMethods' members.
105      */

106     private BeanFunction(Class JavaDoc claz, String JavaDoc name) throws IllegalAccessException JavaDoc, InstantiationException JavaDoc, InvocationTargetException {
107         super(name, null, null);
108         this.claz = claz;
109
110         // Finding the methods to be used.
111
Method[] methods = claz.getMethods();
112         for (int i = 0 ; i < methods.length; i++) {
113             Method m = methods[i];
114             String JavaDoc methodName = m.getName();
115             if (methodName.equals(name) && m.getParameterTypes().length == 0) {
116                 method = m;
117                 break;
118             }
119         }
120
121         if (method == null) {
122             throw new IllegalArgumentException JavaDoc("The class " + claz + " does not have method " + name + " (with no argument)");
123         }
124
125         // Now finding the parameters.
126

127
128         // need a sample instance to get the default values from.
129
Object JavaDoc sampleInstance = claz.newInstance();
130
131         List parameters = new ArrayList();
132         for (int i = 0 ; i < methods.length; i++) {
133             Method method = methods[i];
134             String JavaDoc methodName = method.getName();
135             Class JavaDoc[] parameterTypes = method.getParameterTypes();
136             if (parameterTypes.length == 1 && methodName.startsWith("set")) {
137                 String JavaDoc parameterName = methodName.substring(3);
138                 // find a corresponding getter method, which can be used for a default value;
139
Object JavaDoc defaultValue;
140                 try {
141                     Method getter = claz.getMethod("get" + parameterName, new Class JavaDoc[] {});
142                     defaultValue = getter.invoke(sampleInstance, new Object JavaDoc[] {});
143                 } catch (NoSuchMethodException JavaDoc nsme) {
144                     defaultValue = null;
145                 }
146                 if (Character.isUpperCase(parameterName.charAt(0))) {
147                     if (parameterName.length() > 1) {
148                         if (! Character.isUpperCase(parameterName.charAt(1))) {
149                             parameterName = "" + Character.toLowerCase(parameterName.charAt(0)) + parameterName.substring(1);
150                         }
151                     } else {
152                         parameterName = parameterName.toLowerCase();
153                     }
154                 }
155                 if (parameterName.equals("node") && org.mmbase.bridge.Node.class.isAssignableFrom(parameterTypes[0])) {
156                     parameters.add(Parameter.NODE);
157                 } else {
158                     parameters.add(new Parameter(parameterName, parameterTypes[0], defaultValue));
159                 }
160                 setMethods.add(method);
161             }
162         }
163         setParameterDefinition((Parameter[]) parameters.toArray(new Parameter[0]));
164         ReturnType returnType = new ReturnType(method.getReturnType(), "");
165         setReturnType(returnType);
166
167     }
168
169
170     /**
171      * {@inheritDoc}
172      * Instantiates the bean, calls all setters using the parameters, and executes the method associated with this function.
173      */

174     public Object JavaDoc getFunctionValue(Parameters parameters) {
175         try {
176             Object JavaDoc bean = claz.newInstance();
177             Iterator i = parameters.iterator();
178             Iterator j = setMethods.iterator();
179             while(i.hasNext() && j.hasNext()) {
180                 Object JavaDoc value = i.next();
181                 Method method = (Method) j.next();
182                 method.invoke(bean, new Object JavaDoc[] {value});
183             }
184             Object JavaDoc ret = method.invoke(bean, new Object JavaDoc[] {});
185             return ret;
186         } catch (Exception JavaDoc e) {
187             throw new RuntimeException JavaDoc(e);
188         }
189     }
190
191 }
192
Popular Tags