Package org.springframework.messaging.support

Source Code of org.springframework.messaging.support.ExecutorSubscribableChannel

/*
* Copyright 2002-2014 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.messaging.support;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;

import org.springframework.messaging.Message;
import org.springframework.messaging.MessageDeliveryException;
import org.springframework.messaging.MessageHandler;
import org.springframework.messaging.MessagingException;
import org.springframework.messaging.SubscribableChannel;

/**
* A {@link SubscribableChannel} that sends messages to each of its subscribers.
*
* @author Phillip Webb
* @author Rossen Stoyanchev
* @since 4.0
*/
public class ExecutorSubscribableChannel extends AbstractSubscribableChannel {

  private final Executor executor;

  private final List<ExecutorChannelInterceptor> executorInterceptors = new ArrayList<ExecutorChannelInterceptor>(4);


  /**
   * Create a new {@link ExecutorSubscribableChannel} instance
   * where messages will be sent in the callers thread.
   */
  public ExecutorSubscribableChannel() {
    this(null);
  }

  /**
   * Create a new {@link ExecutorSubscribableChannel} instance
   * where messages will be sent via the specified executor.
   * @param executor the executor used to send the message,
   * or {@code null} to execute in the callers thread.
   */
  public ExecutorSubscribableChannel(Executor executor) {
    this.executor = executor;
  }


  public Executor getExecutor() {
    return this.executor;
  }

  @Override
  public void setInterceptors(List<ChannelInterceptor> interceptors) {
    super.setInterceptors(interceptors);
    this.executorInterceptors.clear();
    for (ChannelInterceptor interceptor : interceptors) {
      if (interceptor instanceof ExecutorChannelInterceptor) {
        this.executorInterceptors.add((ExecutorChannelInterceptor) interceptor);
      }
    }
  }

  @Override
  public void addInterceptor(ChannelInterceptor interceptor) {
    super.addInterceptor(interceptor);
    if (interceptor instanceof ExecutorChannelInterceptor) {
      this.executorInterceptors.add((ExecutorChannelInterceptor) interceptor);
    }
  }


  @Override
  public boolean sendInternal(Message<?> message, long timeout) {
    for (MessageHandler handler : getSubscribers()) {
      SendTask sendTask = new SendTask(message, handler);
      if (this.executor == null) {
        sendTask.run();
      }
      else {
        this.executor.execute(sendTask);
      }
    }
    return true;
  }


  /**
   * Invoke a MessageHandler with ExecutorChannelInterceptor's.
   */
  private class SendTask implements MessageHandlingRunnable {

    private final Message<?> inputMessage;

    private final MessageHandler messageHandler;

    private int interceptorIndex = -1;

    public SendTask(Message<?> message, MessageHandler messageHandler) {
      this.inputMessage = message;
      this.messageHandler = messageHandler;
    }

    @Override
    public Message<?> getMessage() {
      return this.inputMessage;
    }

    @Override
    public MessageHandler getMessageHandler() {
      return this.messageHandler;
    }

    @Override
    public void run() {
      Message<?> message = this.inputMessage;
      try {
        message = applyBeforeHandle(message);
        if (message == null) {
          return;
        }
        this.messageHandler.handleMessage(message);
        triggerAfterMessageHandled(message, null);
      }
      catch (Exception ex) {
        triggerAfterMessageHandled(message, ex);
        if (ex instanceof MessagingException) {
          throw (MessagingException) ex;
        }
        String description = "Failed to handle " + message + " to " + this + " in " + this.messageHandler;
        throw new MessageDeliveryException(message, description, ex);
      }
      catch (Error ex) {
        String description = "Failed to handle " + message + " to " + this + " in " + this.messageHandler;
        triggerAfterMessageHandled(message, new MessageDeliveryException(message, description, ex));
        throw ex;
      }
    }

    private Message<?> applyBeforeHandle(Message<?> message) {
      for (ExecutorChannelInterceptor interceptor : executorInterceptors) {
        message = interceptor.beforeHandle(message, ExecutorSubscribableChannel.this, this.messageHandler);
        if (message == null) {
          String name = interceptor.getClass().getSimpleName();
          if (logger.isDebugEnabled()) {
            logger.debug(name + " returned null from beforeHandle, i.e. precluding the send.");
          }
          triggerAfterMessageHandled(message, null);
          return null;
        }
        this.interceptorIndex++;
      }
      return message;
    }

    private void triggerAfterMessageHandled(Message<?> message, Exception ex) {
      for (int i = this.interceptorIndex; i >= 0; i--) {
        ExecutorChannelInterceptor interceptor = executorInterceptors.get(i);
        try {
          interceptor.afterMessageHandled(message, ExecutorSubscribableChannel.this, this.messageHandler, ex);
        }
        catch (Throwable ex2) {
          logger.error("Exception from afterMessageHandled in " + interceptor, ex2);
        }
      }
    }
  }

}
TOP

Related Classes of org.springframework.messaging.support.ExecutorSubscribableChannel

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.