/* * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.integration.handler; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.springframework.beans.factory.BeanFactory; import org.springframework.core.convert.TypeDescriptor; import org.springframework.expression.AccessException; import org.springframework.expression.EvaluationContext; import org.springframework.expression.EvaluationException; import org.springframework.expression.Expression; import org.springframework.expression.MethodExecutor; import org.springframework.expression.MethodFilter; import org.springframework.expression.MethodResolver; import org.springframework.expression.spel.support.ReflectiveMethodResolver; import org.springframework.messaging.Message; /** * A MessageProcessor implementation that expects an Expression or expressionString * as the Message payload. When processing, it simply evaluates that expression. * * @author Dave Syer * @author Mark Fisher * @author Gary Russell * @since 2.0 */ public class ExpressionCommandMessageProcessor extends AbstractMessageProcessor<Object> { public ExpressionCommandMessageProcessor() { } public ExpressionCommandMessageProcessor(MethodFilter methodFilter) { this(methodFilter, null); } public ExpressionCommandMessageProcessor(MethodFilter methodFilter, BeanFactory beanFactory) { if (beanFactory != null) { this.setBeanFactory(beanFactory); } if (methodFilter != null) { MethodResolver methodResolver = new ExpressionCommandMethodResolver(methodFilter); this.getEvaluationContext(false).setMethodResolvers(Collections.singletonList(methodResolver)); } } /** * Evaluates the Message payload expression as a command. * @throws IllegalArgumentException if the payload is not an Exception or String */ @Override public Object processMessage(Message<?> message) { Object expression = message.getPayload(); if (expression instanceof Expression) { return evaluateExpression((Expression) expression, message); } if (expression instanceof String) { return evaluateExpression((String) expression, message); } throw new IllegalArgumentException("Message payload must be an Expression instance or an expression String."); } private static final class ExpressionCommandMethodResolver extends ReflectiveMethodResolver { private final MethodFilter methodFilter; ExpressionCommandMethodResolver(MethodFilter methodFilter) { this.methodFilter = methodFilter; } @Override public MethodExecutor resolve(EvaluationContext context, Object targetObject, String name, List<TypeDescriptor> argumentTypes) throws AccessException { this.validateMethod(targetObject, name, (argumentTypes != null ? argumentTypes.size() : 0)); return super.resolve(context, targetObject, name, argumentTypes); } private void validateMethod(Object targetObject, String name, int argumentCount) { if (this.methodFilter == null) { return; } Class<?> type = (targetObject instanceof Class ? (Class<?>) targetObject : targetObject.getClass()); Method[] methods = type.getMethods(); List<Method> candidates = new ArrayList<Method>(); for (Method method : methods) { if (method.getName().equals(name) && method.getParameterTypes().length == argumentCount) { candidates.add(method); } } List<Method> supportedMethods = this.methodFilter.filter(candidates); if (supportedMethods.size() == 0) { String methodDescription = (candidates.size() > 0) ? candidates.get(0).toString() : name; throw new EvaluationException("The method '" + methodDescription + "' is not supported by this command processor. " + "If using the Control Bus, consider adding @ManagedOperation or @ManagedAttribute."); } } } }