/* * Copyright (c) MuleSoft, Inc. All rights reserved. http://www.mulesoft.com * The software in this package is published under the terms of the CPAL v1.0 * license, a copy of which has been included with this distribution in the * LICENSE.txt file. */ package org.mule.runtime.core.api.model.resolvers; import static org.mule.runtime.core.api.Event.getVariableValueOrNull; import static org.mule.runtime.core.api.config.MuleProperties.MULE_IGNORE_METHOD_PROPERTY; import org.mule.runtime.core.api.Event; import org.mule.runtime.core.api.MuleEventContext; import org.mule.runtime.core.api.config.MuleProperties; import org.mule.runtime.core.api.lifecycle.Callable; import org.mule.runtime.core.internal.message.InternalMessage; import org.mule.runtime.core.api.model.InvocationResult; import org.mule.runtime.core.config.i18n.CoreMessages; import org.mule.runtime.core.util.ClassUtils; import java.lang.reflect.Method; import org.apache.commons.lang.BooleanUtils; /** * This resolver will look for a {@link org.mule.runtime.core.api.config.MuleProperties#MULE_METHOD_PROPERTY} property on the * incoming event to determine which method to invoke Users can customise the name of the property used to look up the method name * on the event */ public class MethodHeaderPropertyEntryPointResolver extends AbstractEntryPointResolver { private String methodProperty = MuleProperties.MULE_METHOD_PROPERTY; public String getMethodProperty() { return methodProperty; } public void setMethodProperty(String methodProperty) { this.methodProperty = methodProperty; } @Override public InvocationResult invoke(Object component, MuleEventContext context, Event.Builder eventBuilder) throws Exception { // Transports such as SOAP need to ignore the method property boolean ignoreMethod = BooleanUtils.toBoolean(((InternalMessage) context.getMessage()).<Boolean>getInboundProperty(MULE_IGNORE_METHOD_PROPERTY)); if (ignoreMethod) { // TODO: Removed once we have property scoping InvocationResult result = new InvocationResult(this, InvocationResult.State.NOT_SUPPORTED); result.setErrorMessage("Property: " + MuleProperties.MULE_IGNORE_METHOD_PROPERTY + " was set so skipping this resolver"); return result; } // MULE-4874: this is needed in order to execute the transformers before determining the methodProp Object[] payload = getPayloadFromMessage(context); Object methodProp = getVariableValueOrNull(getMethodProperty(), context.getEvent()); eventBuilder.removeVariable(getMethodProperty()); if (methodProp == null) { methodProp = ((InternalMessage) context.getMessage()).getInboundProperty(getMethodProperty()); } if (methodProp == null) { InvocationResult result = new InvocationResult(this, InvocationResult.State.FAILED); // no method for the explicit method header result.setErrorMessage(CoreMessages.propertyIsNotSetOnEvent(getMethodProperty()).toString()); return result; } Method method; String methodName; if (methodProp instanceof Method) { method = (Method) methodProp; methodName = method.getName(); } else { methodName = methodProp.toString(); method = getMethodByName(component, methodName, context); } if (method != null && method.getParameterTypes().length == 0) { return invokeMethod(component, method, ClassUtils.NO_ARGS_TYPE); } if (method == null) { Class<?>[] classTypes = ClassUtils.getClassTypes(payload); method = ClassUtils.getMethod(component.getClass(), methodName, classTypes); if (method == null) { InvocationResult result = new InvocationResult(this, InvocationResult.State.FAILED); result.setErrorNoMatchingMethods(component, classTypes); return result; } } validateMethod(component, method); addMethodByName(component, method, context); return invokeMethod(component, method, payload); } /** * This method can be used to validate that the method exists and is allowed to be executed. * * @param component the service component being invoked * @param method the method to invoke on the component * @throws NoSuchMethodException if the method does not exist on the component */ protected void validateMethod(Object component, Method method) throws NoSuchMethodException { boolean fallback = component instanceof Callable; if (method != null) { // This will throw NoSuchMethodException if it doesn't exist try { component.getClass().getMethod(method.getName(), method.getParameterTypes()); } catch (NoSuchMethodException e) { if (!fallback) { throw e; } } } else { if (!fallback) { throw new NoSuchMethodException(CoreMessages.methodWithParamsNotFoundOnObject("null", "unknown", component.getClass()) .toString()); } } } @Override public String toString() { final StringBuilder sb = new StringBuilder(); sb.append("MethodHeaderPropertyEntryPointResolver"); sb.append("{methodHeader=").append(methodProperty); sb.append(", acceptVoidMethods=").append(isAcceptVoidMethods()); sb.append('}'); return sb.toString(); } }