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.*;
013: import org.mmbase.util.logging.*;
014:
015: /**
016: * An abstract representation of a piece of functionality (a 'function'). A function has a name, a
017: * return type, and a parameter-definition (which is a {@link Parameter} array).
018: *
019: * The goal of a Function object is to call its {@link #getFunctionValue(Parameters)} method, which
020: * executes it, given the specified parameters.
021: *
022: *
023: * @author Daniel Ockeloen
024: * @author Michiel Meeuwissen
025: * @version $Id: AbstractFunction.java,v 1.20 2007/06/21 15:50:21 nklasens Exp $
026: * @since MMBase-1.8
027: * @see Parameter
028: * @see Parameters
029: */
030: abstract public class AbstractFunction<R> implements Function<R>,
031: Comparable<Function<R>>, java.io.Serializable {
032: private static final Logger log = Logging
033: .getLoggerInstance(AbstractFunction.class);
034: protected String name;
035: protected ReturnType<R> returnType;
036: protected boolean autoReturnType = false;
037:
038: private Parameter<?>[] parameterDefinition;
039: private String description;
040:
041: /**
042: * Constructor for Function objects.
043: * @param name Every function must have a name
044: * @param def Every function must have a parameter definition. It can be left <code>null</code> and then filled later by {@link #setParameterDefinition}
045: * @param returnType Every function must also specify its return type. It can be left <code>null</code> and then filled later by {@link #setReturnType}
046: */
047: public AbstractFunction(String name, Parameter<?>[] def,
048: ReturnType<R> returnType) {
049: this .name = name;
050: if (def != null) {
051: this .parameterDefinition = Functions.define(def).toArray(
052: (Parameter.emptyArray()));
053: }
054: this .returnType = returnType;
055: }
056:
057: /**
058: * Determines the ReturnType automaticly using the return type of {@link #getFunctionValue(Parameters)}.
059: * @since MMBase-1.9
060: */
061: public AbstractFunction(String name, Parameter<?>... def) {
062: this (name, def, null);
063: // what would be nice:
064: // this(name, def, ReturnType.getReturnType(R.class));
065: // but java sucks.
066:
067: autoReturnType = true;
068: }
069:
070: /**
071: * Creates an empty 'Parameters' object for you, which you have to fill and feed back to getFunctionValue
072: * @see #getFunctionValue(Parameters)
073: */
074: public Parameters createParameters() {
075: if (parameterDefinition == null) {
076: throw new IllegalStateException("Definition is not set yet");
077: }
078: return new Parameters(parameterDefinition);
079: }
080:
081: /**
082: * Executes the defined function supplying the given arguments.
083: * @see #createParameters
084: * @param parameters The parameters for the function. To specify an empty parameter list use {@link Parameters#VOID}.
085: * Implementors are encouraged to support <code>null</code> too.
086: * @return The function value, which can be of any type compatible to {@link #getReturnType}
087: */
088: abstract public R getFunctionValue(Parameters parameters);
089:
090: /**
091: * Executes the defined function supplying the given List of arguments.
092: * This is a convenience method, as the List is mapped to a Parameters type and passed to {@link #getFunctionValue(Parameters)}.
093: * @param parameters The parameters for the function. To specify an empty parameter list use {@link Parameters#VOID}.
094: *
095: * @return The function value, which can be of any type compatible to {@link #getReturnType}
096: */
097: public final R getFunctionValueWithList(List<?> parameters) {
098: if (parameters instanceof Parameters) {
099: return getFunctionValue((Parameters) parameters);
100: } else {
101: return getFunctionValue(new Parameters(parameterDefinition,
102: parameters));
103: }
104: }
105:
106: /**
107: * @since MMBase-1.9
108: */
109: public final R getFunctionValue(Object... parameters) {
110: return getFunctionValue(new Parameters(parameterDefinition,
111: parameters));
112: }
113:
114: /**
115: * For documentational purposes a function object needs a description too.
116: */
117: public void setDescription(String description) {
118: this .description = description;
119: }
120:
121: /**
122: * @see #setDescription(String)
123: */
124: public String getDescription() {
125: return description;
126: }
127:
128: /**
129: * A function <em>must</em> have a name. This is the name which was used to aquire the function object.
130: * @return The function's name, never <code>null</code>
131: */
132: public String getName() {
133: return name;
134: }
135:
136: /**
137: * @return The currently set Parameter definition array, or <code>null</code> if not set already.
138: */
139: public Parameter<?>[] getParameterDefinition() {
140: return parameterDefinition;
141: }
142:
143: /**
144: * A function object is of no use, as long as it lacks a definition.
145: * @param params An array of Parameter objects.
146: * @throws IllegalStateException if there was already set a parameter defintion for this function object.
147: */
148: public void setParameterDefinition(Parameter<?>[] params) {
149: if (parameterDefinition != null) {
150: throw new IllegalStateException("Definition is set already");
151: }
152: parameterDefinition = Functions.define(params).toArray(
153: Parameter.emptyArray());
154: }
155:
156: /**
157: * @return The currently set ReturnType, or <code>null</code> if not set already.
158: */
159: @SuppressWarnings("unchecked")
160: public ReturnType<R> getReturnType() {
161: if (returnType == null && autoReturnType) {
162: try {
163: returnType = (ReturnType<R>) ReturnType
164: .getReturnType(getClass().getDeclaredMethod(
165: "getFunctionValue", Parameters.class)
166: .getReturnType());
167: } catch (Exception e) {
168: log.error(e.getMessage(), e);
169: }
170: }
171: return returnType;
172: }
173:
174: /**
175: * Sets the ReturnType for this function if not set already.
176: * @param type A ReturnType object. For void functions that could be {@link ReturnType#VOID}.
177: * @throws IllegalStateException if there was already set a return type for this function object.
178: */
179: public void setReturnType(ReturnType<R> type) {
180: if (returnType != null) {
181: throw new IllegalStateException("Returntype is set already");
182: }
183: returnType = type;
184: }
185:
186: public int compareTo(Function<R> fun) {
187: return name.compareTo(fun.getName());
188: }
189:
190: public boolean equals(Object o) {
191: if (o == this )
192: return true;
193: if (o == null)
194: return false;
195: return (o instanceof Function)
196: && ((Function<?>) o).getName().equals(name);
197: }
198:
199: /**
200: * @see java.lang.Object#hashCode()
201: */
202: public int hashCode() {
203: return name.hashCode();
204: }
205:
206: public String toString() {
207: return "" + getReturnType() + " " + getName()
208: + Arrays.asList(parameterDefinition);
209: }
210:
211: }
|