/* * 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.util.List; import org.aopalliance.aop.Advice; import org.springframework.aop.framework.ProxyFactory; import org.springframework.beans.factory.BeanClassLoaderAware; import org.springframework.integration.handler.advice.HandleMessageAdvice; import org.springframework.messaging.Message; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.CollectionUtils; /** * Base class for MessageHandlers that are capable of producing replies. * * @author Mark Fisher * @author Iwein Fuld * @author Oleg Zhurakousky * @author Gary Russell * @author Artem Bilan * @author David Liu */ public abstract class AbstractReplyProducingMessageHandler extends AbstractMessageProducingHandler implements BeanClassLoaderAware { private volatile RequestHandler advisedRequestHandler; private volatile List<Advice> adviceChain; private volatile ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader(); private volatile boolean requiresReply = false; /** * Flag whether a reply is required. If true an incoming message MUST result in a reply message being sent. * If false an incoming message MAY result in a reply message being sent. Default is false. * @param requiresReply true if a reply is required. */ public void setRequiresReply(boolean requiresReply) { this.requiresReply = requiresReply; } protected boolean getRequiresReply() { return this.requiresReply; } public void setAdviceChain(List<Advice> adviceChain) { Assert.notNull(adviceChain, "adviceChain cannot be null"); this.adviceChain = adviceChain; } protected boolean hasAdviceChain() { return this.adviceChain != null && this.adviceChain.size() > 0; } @Override public void setBeanClassLoader(ClassLoader beanClassLoader) { this.beanClassLoader = beanClassLoader; } @Override protected final void onInit() throws Exception { super.onInit(); if (!CollectionUtils.isEmpty(this.adviceChain)) { ProxyFactory proxyFactory = new ProxyFactory(new AdvisedRequestHandler()); boolean advised = false; for (Advice advice : this.adviceChain) { if (!(advice instanceof HandleMessageAdvice)) { proxyFactory.addAdvice(advice); advised = true; } } if (advised) { this.advisedRequestHandler = (RequestHandler) proxyFactory.getProxy(this.beanClassLoader); } } doInit(); } protected void doInit() { } /** * {@inheritDoc} */ @Override protected final void handleMessageInternal(Message<?> message) { Object result; if (this.advisedRequestHandler == null) { result = handleRequestMessage(message); } else { result = doInvokeAdvisedRequestHandler(message); } if (result != null) { sendOutputs(result, message); } else if (this.requiresReply && !isAsync()) { throw new ReplyRequiredException(message, "No reply produced by handler '" + getComponentName() + "', and its 'requiresReply' property is set to true."); } else if (!isAsync() && logger.isDebugEnabled()) { logger.debug("handler '" + this + "' produced no reply for request Message: " + message); } } protected Object doInvokeAdvisedRequestHandler(Message<?> message) { return this.advisedRequestHandler.handleRequestMessage(message); } /** * Subclasses must implement this method to handle the request Message. The return * value may be a Message, a MessageBuilder, or any plain Object. The base class * will handle the final creation of a reply Message from any of those starting * points. If the return value is null, the Message flow will end here. * @param requestMessage The request message. * @return The result of handling the message, or {@code null}. */ protected abstract Object handleRequestMessage(Message<?> requestMessage); /** * An implementation of this interface is used to wrap the * {@link AbstractReplyProducingMessageHandler#handleRequestMessage(Message)} * method. Also allows access to the underlying * {@link AbstractReplyProducingMessageHandler} to obtain properties. * * @author Gary Russell * @since 2.2 * * @see #getAdvisedHandler() * */ public interface RequestHandler { Object handleRequestMessage(Message<?> requestMessage); @Override String toString(); /** * Utility method, intended for use in message handler advice classes to get * information about the advised object. For example: * <p> * {@code ((AbstractReplyProducingMessageHandler.RequestHandler) * invocation.getThis()).getAdvisedHandler().getComponentName()} * @return the outer class instance. * * @since 4.3.2 */ AbstractReplyProducingMessageHandler getAdvisedHandler(); } private class AdvisedRequestHandler implements RequestHandler { AdvisedRequestHandler() { super(); } @Override public Object handleRequestMessage(Message<?> requestMessage) { return AbstractReplyProducingMessageHandler.this.handleRequestMessage(requestMessage); } @Override public String toString() { return AbstractReplyProducingMessageHandler.this.toString(); } @Override public AbstractReplyProducingMessageHandler getAdvisedHandler() { return AbstractReplyProducingMessageHandler.this; } } }