/*
* 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.config;
import java.util.HashSet;
import java.util.Set;
import org.springframework.aop.TargetSource;
import org.springframework.aop.framework.Advised;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.SpelParserConfiguration;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.integration.handler.AbstractMessageProducingHandler;
import org.springframework.integration.handler.AbstractReplyProducingMessageHandler;
import org.springframework.integration.handler.MessageProcessor;
import org.springframework.messaging.MessageHandler;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* Base class for FactoryBeans that create standard MessageHandler instances.
*
* @author Mark Fisher
* @author Alexander Peters
* @author Gary Russell
* @author Artem Bilan
* @author David Liu
*/
public abstract class AbstractStandardMessageHandlerFactoryBean
extends AbstractSimpleMessageHandlerFactoryBean<MessageHandler> {
private static final ExpressionParser expressionParser = new SpelExpressionParser(new SpelParserConfiguration(true,
true));
private static final Set<MessageHandler> referencedReplyProducers = new HashSet<MessageHandler>();
private volatile Object targetObject;
private volatile String targetMethodName;
private volatile Expression expression;
/**
* Set the target POJO for the message handler.
* @param targetObject the target object.
*/
public void setTargetObject(Object targetObject) {
this.targetObject = targetObject;
}
/**
* Set the method name for the message handler.
* @param targetMethodName the target method name.
*/
public void setTargetMethodName(String targetMethodName) {
this.targetMethodName = targetMethodName;
}
/**
* Set a SpEL expression to use.
* @param expressionString the expression as a String.
*/
public void setExpressionString(String expressionString) {
this.expression = expressionParser.parseExpression(expressionString);
}
/**
* Set a SpEL expression to use.
* @param expression the expression.
*/
public void setExpression(Expression expression) {
this.expression = expression;
}
@Override
protected MessageHandler createHandler() {
MessageHandler handler;
if (this.targetObject == null) {
Assert.isTrue(!StringUtils.hasText(this.targetMethodName),
"The target method is only allowed when a target object (ref or inner bean) is also provided.");
}
if (this.targetObject != null) {
Assert.state(this.expression == null,
"The 'targetObject' and 'expression' properties are mutually exclusive.");
AbstractMessageProducingHandler actualHandler = this.extractTypeIfPossible(this.targetObject,
AbstractMessageProducingHandler.class);
boolean targetIsDirectReplyProducingHandler = actualHandler != null
&& this.canBeUsedDirect(actualHandler) // give subclasses a say
&& this.methodIsHandleMessageOrEmpty(this.targetMethodName);
if (this.targetObject instanceof MessageProcessor<?>) {
handler = this.createMessageProcessingHandler((MessageProcessor<?>) this.targetObject);
}
else if (targetIsDirectReplyProducingHandler) {
if (logger.isDebugEnabled()) {
logger.debug("Wiring handler (" + this.targetObject + ") directly into endpoint");
}
this.checkReuse(actualHandler);
this.postProcessReplyProducer(actualHandler);
handler = (MessageHandler) this.targetObject;
}
else {
handler = this.createMethodInvokingHandler(this.targetObject, this.targetMethodName);
}
}
else if (this.expression != null) {
handler = this.createExpressionEvaluatingHandler(this.expression);
}
else {
handler = this.createDefaultHandler();
}
return handler;
}
protected void checkForIllegalTarget(Object targetObject, String targetMethodName) {
if (targetObject instanceof AbstractReplyProducingMessageHandler
&& this.methodIsHandleMessageOrEmpty(targetMethodName)) {
/*
* If we allow an ARPMH to be the target of another ARPMH, the reply would
* be attempted to be sent by the inner (no output channel) and a reply would
* never be received by the outer (fails if replyRequired).
*/
throw new IllegalArgumentException("AbstractReplyProducingMessageHandler.handleMessage() "
+ "is not allowed for a MethodInvokingHandler");
}
}
private void checkReuse(AbstractMessageProducingHandler replyHandler) {
Assert.isTrue(!referencedReplyProducers.contains(replyHandler),
"An AbstractMessageProducingMessageHandler may only be referenced once (" +
replyHandler.getComponentName() + ") - use scope=\"prototype\"");
referencedReplyProducers.add(replyHandler);
}
/**
* Subclasses must implement this method to create the MessageHandler.
* @param targetObject the object to use for method invocation.
* @param targetMethodName the method name of the target object to invoke.
* @return the method invoking {@link MessageHandler} implementation.
*/
protected abstract MessageHandler createMethodInvokingHandler(Object targetObject, String targetMethodName);
protected MessageHandler createExpressionEvaluatingHandler(Expression expression) {
throw new UnsupportedOperationException(this.getClass().getName() + " does not support expressions.");
}
protected <T> MessageHandler createMessageProcessingHandler(MessageProcessor<T> processor) {
return this.createMethodInvokingHandler(processor, null);
}
protected MessageHandler createDefaultHandler() {
throw new IllegalArgumentException("Exactly one of the 'targetObject' or 'expression' property is required.");
}
@SuppressWarnings("unchecked")
protected <T> T extractTypeIfPossible(Object targetObject, Class<T> expectedType) {
if (targetObject == null) {
return null;
}
if (expectedType.isAssignableFrom(targetObject.getClass())) {
return (T) targetObject;
}
if (targetObject instanceof Advised) {
TargetSource targetSource = ((Advised) targetObject).getTargetSource();
if (targetSource == null) {
return null;
}
try {
return extractTypeIfPossible(targetSource.getTarget(), expectedType);
}
catch (Exception e) {
throw new IllegalStateException(e);
}
}
return null;
}
protected boolean methodIsHandleMessageOrEmpty(String targetMethodName) {
return (!StringUtils.hasText(targetMethodName)
|| "handleMessage".equals(targetMethodName));
}
protected boolean canBeUsedDirect(AbstractMessageProducingHandler handler) {
return false;
}
protected void postProcessReplyProducer(AbstractMessageProducingHandler handler) {
}
}