001: /*
002: * $Id: AbstractArgumentEntryPointResolver.java 10489 2008-01-23 17:53:38Z dfeist $
003: * --------------------------------------------------------------------------------------
004: * Copyright (c) MuleSource, Inc. All rights reserved. http://www.mulesource.com
005: *
006: * The software in this package is published under the terms of the CPAL v1.0
007: * license, a copy of which has been included with this distribution in the
008: * LICENSE.txt file.
009: */
010: package org.mule.model.resolvers;
011:
012: import org.mule.api.MuleEventContext;
013: import org.mule.api.model.InvocationResult;
014: import org.mule.util.ClassUtils;
015: import org.mule.util.StringMessageUtils;
016:
017: import java.lang.reflect.Method;
018: import java.util.Arrays;
019: import java.util.HashSet;
020: import java.util.Iterator;
021: import java.util.List;
022: import java.util.Set;
023:
024: /**
025: * A base class that allows implementing resolvers to define what parameters it is expecting. Currently
026: * there are two implementations of this {@link org.mule.model.resolvers.NoArgumentsEntryPointResolver}, that
027: * allows meothds with no arguments to be invoked and {@link org.mule.model.resolvers.ArrayEntryPointResolver} that
028: * allows for methods that accept an array type to be invoked.
029: * <p/>
030: * Users can set explicit method names on this resolver to control which methods are allowed to be called. Also a set of
031: * 'ingorred' methods are available (and the use can add others) to tell the resolver to not resolve to these methods.
032: * The default ones are:
033: * <ul>
034: * <li>{@link #toString()}
035: * <li>{@link #getClass()}
036: * <li>{@link #notify}
037: * <li>{@link #notifyAll}
038: * <li>{@link #hashCode}
039: * <li>{@link #wait}
040: * <li>{@link Cloneable#clone()}
041: * <li>'is*'
042: * <li>'get*'.
043: * </ul>
044: * <p/> Note that wildcard expressions can be used.
045: */
046: public abstract class AbstractArgumentEntryPointResolver extends
047: ReflectionEntryPointResolver {
048: private Set methods = new HashSet(2);
049:
050: private boolean enableDiscovery = true;
051:
052: public AbstractArgumentEntryPointResolver() {
053: //By default No arg methods without a return type should be supported
054: setAcceptVoidMethods(true);
055: // we don't want to match these methods when looking for a service method
056: //If you add to this list please change the javaDoc above too.
057: setIgnoredMethods(new HashSet(Arrays.asList(new String[] {
058: "toString", "getClass", "notify", "notifyAll", "wait",
059: "hashCode", "clone", "is*", "get*" })));
060: }
061:
062: public Set getMethods() {
063: return methods;
064: }
065:
066: public void setMethods(Set methods) {
067: this .methods = methods;
068: }
069:
070: public void addMethod(String name) {
071: this .methods.add(name);
072: }
073:
074: public boolean removeMethod(String name) {
075: return this .methods.remove(name);
076: }
077:
078: public boolean isEnableDiscovery() {
079: return enableDiscovery;
080: }
081:
082: public void setEnableDiscovery(boolean enableDiscovery) {
083: this .enableDiscovery = enableDiscovery;
084: }
085:
086: public InvocationResult invoke(Object component,
087: MuleEventContext context) throws Exception {
088: Method method = null;
089: Object[] payload = getPayloadFromMessage(context);
090:
091: if (payload == null) {
092: return new InvocationResult(
093: InvocationResult.STATE_INVOKE_NOT_SUPPORTED);
094: }
095:
096: for (Iterator iterator = methods.iterator(); iterator.hasNext();) {
097: String methodName = (String) iterator.next();
098: method = getMethodByName(methodName, context);
099:
100: if (method == null) {
101: method = ClassUtils.getMethod(component.getClass(),
102: methodName, getMethodArgumentTypes(payload));
103: }
104: if (method != null) {
105: addMethodByName(method, context);
106: break;
107: }
108: }
109: //If the method wasn't explicitly set, lets try and discover it
110: if (method == null) {
111: if (isEnableDiscovery()) {
112: Class[] argTypes = getMethodArgumentTypes(payload);
113: List methods = ClassUtils.getSatisfiableMethods(
114: component.getClass(), argTypes,
115: isAcceptVoidMethods(), false,
116: getIgnoredMethods(), filter);
117:
118: if (methods.size() > 1) {
119: InvocationResult result = new InvocationResult(
120: InvocationResult.STATE_INVOKED_FAILED);
121: // too many methods match the payload argument
122: result.setErrorTooManyMatchingMethods(component,
123: argTypes, this );
124: return result;
125: } else if (methods.size() == 1) {
126: // found exact match for payload argument
127: method = this .addMethodByArguments(component,
128: (Method) methods.get(0),
129: getPayloadFromMessage(context));
130: } else {
131: InvocationResult result = new InvocationResult(
132: InvocationResult.STATE_INVOKED_FAILED);
133: // no method for payload argument either - bail out
134: result.setErrorNoMatchingMethods(component,
135: ClassUtils.NO_ARGS_TYPE, this );
136: return result;
137: }
138: } else {
139: InvocationResult result = new InvocationResult(
140: InvocationResult.STATE_INVOKED_FAILED);
141: // no method for the explicit methods either
142: result.setErrorNoMatchingMethodsCalled(component,
143: StringMessageUtils.toString(methods), this );
144: return result;
145: }
146: }
147: return invokeMethod(component, method,
148: getPayloadFromMessage(context));
149: }
150:
151: protected abstract Class[] getMethodArgumentTypes(Object[] payload);
152:
153: public String toString() {
154: final StringBuffer sb = new StringBuffer();
155: sb.append(ClassUtils.getClassName(getClass()));
156: sb.append("{methods=").append(
157: StringMessageUtils.toString(methods));
158: sb.append("{transformFirst=").append(isTransformFirst());
159: sb.append(", acceptVoidMethods=").append(isAcceptVoidMethods());
160: sb.append('}');
161: return sb.toString();
162: }
163: }
|