/* * Copyright 2015-2017 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.channel; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.concurrent.Executor; import org.springframework.integration.dispatcher.AbstractDispatcher; import org.springframework.integration.support.MessagingExceptionWrapper; import org.springframework.messaging.Message; import org.springframework.messaging.MessageDeliveryException; import org.springframework.messaging.MessageHandler; import org.springframework.messaging.MessagingException; import org.springframework.messaging.support.ChannelInterceptor; import org.springframework.messaging.support.ExecutorChannelInterceptor; import org.springframework.messaging.support.MessageHandlingRunnable; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; /** * The {@link AbstractSubscribableChannel} base implementation for those inheritors * which logic may be based on the {@link Executor}. * <p> * Utilizes common operations for the {@link AbstractDispatcher}. * <p> * Implements the {@link ExecutorChannelInterceptor}s logic when the message handling * is handed to the {@link Executor#execute(Runnable)}. * * @author Artem Bilan * @author Gary Russell * @see ExecutorChannel * @see PublishSubscribeChannel * @since 4.2 */ public abstract class AbstractExecutorChannel extends AbstractSubscribableChannel implements ExecutorChannelInterceptorAware { protected volatile Executor executor; protected volatile AbstractDispatcher dispatcher; protected volatile Integer maxSubscribers; protected volatile int executorInterceptorsSize; public AbstractExecutorChannel(Executor executor) { this.executor = executor; } /** * Specify the maximum number of subscribers supported by the * channel's dispatcher. * * @param maxSubscribers The maximum number of subscribers allowed. */ public void setMaxSubscribers(int maxSubscribers) { this.maxSubscribers = maxSubscribers; this.dispatcher.setMaxSubscribers(maxSubscribers); } @Override public void setInterceptors(List<ChannelInterceptor> interceptors) { super.setInterceptors(interceptors); for (ChannelInterceptor interceptor : interceptors) { if (interceptor instanceof ExecutorChannelInterceptor) { this.executorInterceptorsSize++; } } } @Override public void addInterceptor(ChannelInterceptor interceptor) { super.addInterceptor(interceptor); if (interceptor instanceof ExecutorChannelInterceptor) { this.executorInterceptorsSize++; } } @Override public void addInterceptor(int index, ChannelInterceptor interceptor) { super.addInterceptor(index, interceptor); if (interceptor instanceof ExecutorChannelInterceptor) { this.executorInterceptorsSize++; } } @Override public boolean removeInterceptor(ChannelInterceptor interceptor) { boolean removed = super.removeInterceptor(interceptor); if (removed && interceptor instanceof ExecutorChannelInterceptor) { this.executorInterceptorsSize--; } return removed; } @Override public ChannelInterceptor removeInterceptor(int index) { ChannelInterceptor interceptor = super.removeInterceptor(index); if (interceptor instanceof ExecutorChannelInterceptor) { this.executorInterceptorsSize--; } return interceptor; } @Override public boolean hasExecutorInterceptors() { return this.executorInterceptorsSize > 0; } protected class MessageHandlingTask implements Runnable { private final MessageHandlingRunnable delegate; public MessageHandlingTask(MessageHandlingRunnable task) { this.delegate = task; } @Override public void run() { Message<?> message = this.delegate.getMessage(); MessageHandler messageHandler = this.delegate.getMessageHandler(); Assert.notNull(messageHandler, "'messageHandler' must not be null"); Deque<ExecutorChannelInterceptor> interceptorStack = null; try { if (AbstractExecutorChannel.this.executorInterceptorsSize > 0) { interceptorStack = new ArrayDeque<ExecutorChannelInterceptor>(); message = applyBeforeHandle(message, interceptorStack); if (message == null) { return; } } messageHandler.handleMessage(message); if (!CollectionUtils.isEmpty(interceptorStack)) { triggerAfterMessageHandled(message, null, interceptorStack); } } catch (Exception ex) { if (!CollectionUtils.isEmpty(interceptorStack)) { triggerAfterMessageHandled(message, ex, interceptorStack); } if (ex instanceof MessagingException) { throw new MessagingExceptionWrapper(message, (MessagingException) ex); } String description = "Failed to handle " + message + " to " + this + " in " + messageHandler; throw new MessageDeliveryException(message, description, ex); } catch (Error ex) { //NOSONAR - ok, we re-throw below if (!CollectionUtils.isEmpty(interceptorStack)) { String description = "Failed to handle " + message + " to " + this + " in " + messageHandler; triggerAfterMessageHandled(message, new MessageDeliveryException(message, description, ex), interceptorStack); } throw ex; } } private Message<?> applyBeforeHandle(Message<?> message, Deque<ExecutorChannelInterceptor> interceptorStack) { Message<?> theMessage = message; for (ChannelInterceptor interceptor : AbstractExecutorChannel.this.interceptors.interceptors) { if (interceptor instanceof ExecutorChannelInterceptor) { ExecutorChannelInterceptor executorInterceptor = (ExecutorChannelInterceptor) interceptor; theMessage = executorInterceptor.beforeHandle(theMessage, AbstractExecutorChannel.this, this.delegate.getMessageHandler()); if (theMessage == null) { if (isLoggingEnabled() && logger.isDebugEnabled()) { logger.debug(executorInterceptor.getClass().getSimpleName() + " returned null from beforeHandle, i.e. precluding the send."); } triggerAfterMessageHandled(null, null, interceptorStack); return null; } interceptorStack.add(executorInterceptor); } } return theMessage; } private void triggerAfterMessageHandled(Message<?> message, Exception ex, Deque<ExecutorChannelInterceptor> interceptorStack) { Iterator<ExecutorChannelInterceptor> iterator = interceptorStack.descendingIterator(); while (iterator.hasNext()) { ExecutorChannelInterceptor interceptor = iterator.next(); try { interceptor.afterMessageHandled(message, AbstractExecutorChannel.this, this.delegate.getMessageHandler(), ex); } catch (Throwable ex2) { //NOSONAR logger.error("Exception from afterMessageHandled in " + interceptor, ex2); } } } } }