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.util.Arrays;
013: import java.lang.reflect.*;
014:
015: import org.mmbase.util.logging.*;
016:
017: /**
018: * A SetFunction is a {@link Function} which wraps precisely one method of a class. It is used as one function of a 'set' of functions.
019: *
020: * @author Michiel Meeuwissen
021: * @author Daniel Ockeloen
022: * @author Pierre van Rooden
023: * @version $Id: SetFunction.java,v 1.21 2007/11/01 10:11:38 michiel Exp $
024: * @since MMBase-1.8
025: * @see FunctionSets
026: */
027: public class SetFunction extends AbstractFunction<Object> {
028: private static final Logger log = Logging
029: .getLoggerInstance(SetFunction.class);
030:
031: public static enum Type {
032: /**
033: * If type is 'class' the method must be static, or if it is not static, there will be instantiated <em>one</em> object.
034: */
035: CLASS,
036: /**
037: * If type is 'instance' the method must not be static, and on every call to getFunctionValue, a new object is instantiated.
038: */
039: INSTANCE,
040: /**
041: * If type is 'singleton', then the static method 'getInstance' will be called to get the one instance, unless the method is static.
042: */
043: SINGLETON
044: }
045:
046: private final Method functionMethod;
047: private final Object functionInstance;
048: private final Type type;
049: private final int defLength;
050:
051: /**
052: * Simple utility method to convert primitive classes to their 'sophisticated' counterparts.
053: *
054: * @since MMBase-1.8.5
055: */
056: protected static Class sophisticate(Class primitive) {
057:
058: if (primitive.isPrimitive()) {
059: if (primitive.equals(Boolean.TYPE)) {
060: return Boolean.class;
061: } else if (primitive.equals(Character.TYPE)) {
062: return Character.class;
063: } else if (primitive.equals(Byte.TYPE)) {
064: return Byte.class;
065: } else if (primitive.equals(Character.TYPE)) {
066: return Short.class;
067: } else if (primitive.equals(Character.TYPE)) {
068: return Integer.class;
069: } else if (primitive.equals(Character.TYPE)) {
070: return Long.class;
071: } else if (primitive.equals(Character.TYPE)) {
072: return Float.class;
073: } else if (primitive.equals(Character.TYPE)) {
074: return Double.class;
075: } else if (primitive.equals(Character.TYPE)) {
076: return Void.class;
077: }
078: }
079: // already sophisticated
080: return primitive;
081: }
082:
083: SetFunction(String name, Parameter[] def,
084: ReturnType<Object> returnType, Class functionClass,
085: String methodName, Type type) {
086: super (name, def, returnType);
087: this .type = type;
088:
089: try {
090: functionMethod = functionClass.getMethod(methodName,
091: createParameters().toClassArray());
092: } catch (NoSuchMethodException e) {
093: throw new RuntimeException("Function method not found : "
094: + functionClass + "." + methodName + "("
095: + Arrays.asList(getParameterDefinition()) + ")", e);
096: }
097:
098: if (Modifier.isStatic(functionMethod.getModifiers())) {
099: functionInstance = null;
100: } else {
101: switch (type) {
102: case CLASS:
103: try {
104: functionInstance = functionMethod
105: .getDeclaringClass().newInstance();
106: } catch (Exception e) {
107: throw new RuntimeException(
108: "Can't create an function instance : "
109: + functionMethod
110: .getDeclaringClass()
111: .getName(), e);
112: }
113: break;
114: case SINGLETON:
115: try {
116: Method singleton = functionClass
117: .getMethod("getInstance");
118: functionInstance = singleton.invoke(null);
119: } catch (Exception e) {
120: throw new RuntimeException(
121: "Can't create an function instance : "
122: + functionMethod
123: .getDeclaringClass()
124: .getName(), e);
125: }
126: break;
127: case INSTANCE:
128: functionInstance = null;
129: // one will be made on every calle
130: break;
131: default:
132: functionInstance = null;
133: }
134:
135: }
136: if (returnType == null) {
137: setReturnType(new ReturnType<Object>(functionMethod
138: .getReturnType(), functionMethod.getReturnType()
139: .getClass().getName()));
140: returnType = getReturnType();
141: }
142:
143: Class methodReturnType = sophisticate(functionMethod
144: .getReturnType());
145: Class xmlReturnType = sophisticate(returnType.getDataType()
146: .getTypeAsClass());
147:
148: if (!xmlReturnType.isAssignableFrom(methodReturnType)) {
149: log
150: .warn("Return value of function "
151: + functionClass
152: + "."
153: + methodName
154: + "("
155: + methodReturnType
156: + ") does not match method return type as specified in XML: ("
157: + xmlReturnType + ")");
158: }
159: defLength = def.length;
160: }
161:
162: /**
163: * @since MMBase-1.8.5
164: */
165: public SetFunction(String name, Parameter[] def, Class clazz) {
166: this (name, def, null, clazz, name, Type.CLASS);
167: }
168:
169: /**
170: */
171: public Object getFunctionValue(Parameters parameters) {
172: parameters.checkRequiredParameters();
173: try {
174: if (defLength < parameters.size()) {
175: // when wrapping this fucntion, it can happen that the number of parameters increases.
176: return functionMethod.invoke(getInstance(), parameters
177: .subList(0, defLength).toArray());
178: } else {
179: return functionMethod.invoke(getInstance(), parameters
180: .toArray());
181: }
182: } catch (IllegalAccessException iae) {
183: log.error("Function call failed (method not available) : "
184: + name + ", method: " + functionMethod
185: + ", instance: " + getInstance() + ", parameters: "
186: + parameters);
187: return null;
188: } catch (InvocationTargetException ite) {
189: Throwable te = ite.getTargetException();
190: if (te instanceof RuntimeException) {
191: throw (RuntimeException) te;
192: } else {
193: throw new RuntimeException(te); // throw the actual exception that occurred
194: }
195: }
196: }
197:
198: protected Object getInstance() {
199: if (functionInstance != null || type == Type.CLASS)
200: return functionInstance;
201: try {
202: return functionMethod.getDeclaringClass().newInstance();
203: } catch (Exception e) {
204: throw new RuntimeException(
205: "Can't create an function instance : "
206: + functionMethod.getDeclaringClass()
207: .getName(), e);
208: }
209: }
210:
211: }
|