Package org.springframework.messaging.simp.config

Source Code of org.springframework.messaging.simp.config.AbstractMessageBrokerConfiguration$NoOpBrokerMessageHandler

/*
* 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.simp.config;

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.BeanInitializationException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.messaging.Message;
import org.springframework.messaging.converter.ByteArrayMessageConverter;
import org.springframework.messaging.converter.CompositeMessageConverter;
import org.springframework.messaging.converter.DefaultContentTypeResolver;
import org.springframework.messaging.converter.MappingJackson2MessageConverter;
import org.springframework.messaging.converter.MessageConverter;
import org.springframework.messaging.converter.StringMessageConverter;
import org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolver;
import org.springframework.messaging.handler.invocation.HandlerMethodReturnValueHandler;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.messaging.simp.annotation.support.SimpAnnotationMethodMessageHandler;
import org.springframework.messaging.simp.broker.AbstractBrokerMessageHandler;
import org.springframework.messaging.simp.broker.SimpleBrokerMessageHandler;
import org.springframework.messaging.simp.user.DefaultUserDestinationResolver;
import org.springframework.messaging.simp.user.DefaultUserSessionRegistry;
import org.springframework.messaging.simp.user.UserDestinationMessageHandler;
import org.springframework.messaging.simp.user.UserDestinationResolver;
import org.springframework.messaging.simp.user.UserSessionRegistry;
import org.springframework.messaging.support.AbstractSubscribableChannel;
import org.springframework.messaging.support.ExecutorSubscribableChannel;
import org.springframework.messaging.support.ImmutableMessageChannelInterceptor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.util.ClassUtils;
import org.springframework.util.MimeTypeUtils;
import org.springframework.util.PathMatcher;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;

/**
* Provides essential configuration for handling messages with simple messaging
* protocols such as STOMP.
*
* <p>{@link #clientInboundChannel()} and {@link #clientOutboundChannel()} deliver
* messages to and from remote clients to several message handlers such as
* <ul>
* <li>{@link #simpAnnotationMethodMessageHandler()}</li>
* <li>{@link #simpleBrokerMessageHandler()}</li>
* <li>{@link #stompBrokerRelayMessageHandler()}</li>
* <li>{@link #userDestinationMessageHandler()}</li>
* </ul>
* while {@link #brokerChannel()} delivers messages from within the application to the
* the respective message handlers. {@link #brokerMessagingTemplate()} can be injected
* into any application component to send messages.
*
* <p>Subclasses are responsible for the part of the configuration that feed messages
* to and from the client inbound/outbound channels (e.g. STOMP over WebSocket).
*
* @author Rossen Stoyanchev
* @author Brian Clozel
* @since 4.0
*/
public abstract class AbstractMessageBrokerConfiguration implements ApplicationContextAware {

  private static final String MVC_VALIDATOR_NAME = "mvcValidator";

  private static final boolean jackson2Present= ClassUtils.isPresent(
      "com.fasterxml.jackson.databind.ObjectMapper", AbstractMessageBrokerConfiguration.class.getClassLoader());


  private ChannelRegistration clientInboundChannelRegistration;

  private ChannelRegistration clientOutboundChannelRegistration;

  private MessageBrokerRegistry brokerRegistry;

  private ApplicationContext applicationContext;


  /**
   * Protected constructor.
   */
  protected AbstractMessageBrokerConfiguration() {
  }


  @Override
  public void setApplicationContext(ApplicationContext applicationContext) {
    this.applicationContext = applicationContext;
  }

  public ApplicationContext getApplicationContext() {
    return this.applicationContext;
  }


  @Bean
  public AbstractSubscribableChannel clientInboundChannel() {
    ExecutorSubscribableChannel channel = new ExecutorSubscribableChannel(clientInboundChannelExecutor());
    ChannelRegistration reg = getClientInboundChannelRegistration();
    channel.setInterceptors(reg.getInterceptors());
    return channel;
  }

  @Bean
  public ThreadPoolTaskExecutor clientInboundChannelExecutor() {
    TaskExecutorRegistration reg = getClientInboundChannelRegistration().getOrCreateTaskExecRegistration();
    ThreadPoolTaskExecutor executor = reg.getTaskExecutor();
    executor.setThreadNamePrefix("clientInboundChannel-");
    return executor;
  }

  protected final ChannelRegistration getClientInboundChannelRegistration() {
    if (this.clientInboundChannelRegistration == null) {
      ChannelRegistration registration = new ChannelRegistration();
      configureClientInboundChannel(registration);
      registration.setInterceptors(new ImmutableMessageChannelInterceptor());
      this.clientInboundChannelRegistration = registration;
    }
    return this.clientInboundChannelRegistration;
  }

  /**
   * A hook for sub-classes to customize the message channel for inbound messages
   * from WebSocket clients.
   */
  protected void configureClientInboundChannel(ChannelRegistration registration) {
  }

  @Bean
  public AbstractSubscribableChannel clientOutboundChannel() {
    ExecutorSubscribableChannel channel = new ExecutorSubscribableChannel(clientOutboundChannelExecutor());
    ChannelRegistration reg = getClientOutboundChannelRegistration();
    channel.setInterceptors(reg.getInterceptors());
    return channel;
  }

  @Bean
  public ThreadPoolTaskExecutor clientOutboundChannelExecutor() {
    TaskExecutorRegistration reg = getClientOutboundChannelRegistration().getOrCreateTaskExecRegistration();
    ThreadPoolTaskExecutor executor = reg.getTaskExecutor();
    executor.setThreadNamePrefix("clientOutboundChannel-");
    return executor;
  }

  protected final ChannelRegistration getClientOutboundChannelRegistration() {
    if (this.clientOutboundChannelRegistration == null) {
      ChannelRegistration registration = new ChannelRegistration();
      configureClientOutboundChannel(registration);
      registration.setInterceptors(new ImmutableMessageChannelInterceptor());
      this.clientOutboundChannelRegistration = registration;
    }
    return this.clientOutboundChannelRegistration;
  }

  /**
   * A hook for sub-classes to customize the message channel for messages from
   * the application or message broker to WebSocket clients.
   */
  protected void configureClientOutboundChannel(ChannelRegistration registration) {
  }

  @Bean
  public AbstractSubscribableChannel brokerChannel() {
    ChannelRegistration reg = getBrokerRegistry().getBrokerChannelRegistration();
    ExecutorSubscribableChannel channel = reg.hasTaskExecutor() ?
        new ExecutorSubscribableChannel(brokerChannelExecutor()) : new ExecutorSubscribableChannel();
    reg.setInterceptors(new ImmutableMessageChannelInterceptor());
    channel.setInterceptors(reg.getInterceptors());
    return channel;
  }

  @Bean
  public ThreadPoolTaskExecutor brokerChannelExecutor() {
    ChannelRegistration reg = getBrokerRegistry().getBrokerChannelRegistration();
    ThreadPoolTaskExecutor executor;
    if (reg.hasTaskExecutor()) {
      executor = reg.taskExecutor().getTaskExecutor();
    }
    else {
      // Should never be used
      executor = new ThreadPoolTaskExecutor();
      executor.setCorePoolSize(0);
      executor.setMaxPoolSize(1);
      executor.setQueueCapacity(0);
    }
    executor.setThreadNamePrefix("brokerChannel-");
    return executor;
  }

  /**
   * An accessor for the {@link MessageBrokerRegistry} that ensures its one-time creation
   * and initialization through {@link #configureMessageBroker(MessageBrokerRegistry)}.
   */
  protected final MessageBrokerRegistry getBrokerRegistry() {
    if (this.brokerRegistry == null) {
      MessageBrokerRegistry registry = new MessageBrokerRegistry(clientInboundChannel(), clientOutboundChannel());
      configureMessageBroker(registry);
      this.brokerRegistry = registry;
    }
    return this.brokerRegistry;
  }

  /**
   * A hook for sub-classes to customize message broker configuration through the
   * provided {@link MessageBrokerRegistry} instance.
   */
  protected void configureMessageBroker(MessageBrokerRegistry registry) {
  }

  @Bean
  public SimpAnnotationMethodMessageHandler simpAnnotationMethodMessageHandler() {
    SimpAnnotationMethodMessageHandler handler = new SimpAnnotationMethodMessageHandler(
        clientInboundChannel(), clientOutboundChannel(), brokerMessagingTemplate());

    handler.setDestinationPrefixes(getBrokerRegistry().getApplicationDestinationPrefixes());
    handler.setMessageConverter(brokerMessageConverter());
    handler.setValidator(simpValidator());

    List<HandlerMethodArgumentResolver> argumentResolvers = new ArrayList<HandlerMethodArgumentResolver>();
    addArgumentResolvers(argumentResolvers);
    handler.setCustomArgumentResolvers(argumentResolvers);

    List<HandlerMethodReturnValueHandler> returnValueHandlers = new ArrayList<HandlerMethodReturnValueHandler>();
    addReturnValueHandlers(returnValueHandlers);
    handler.setCustomReturnValueHandlers(returnValueHandlers);

    PathMatcher pathMatcher = this.getBrokerRegistry().getPathMatcher();
    if (pathMatcher != null) {
      handler.setPathMatcher(pathMatcher);
    }
    return handler;
  }

  protected void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
  }

  protected void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers) {
  }

  @Bean
  public AbstractBrokerMessageHandler simpleBrokerMessageHandler() {
    SimpleBrokerMessageHandler handler = getBrokerRegistry().getSimpleBroker(brokerChannel());
    return (handler != null ? handler : new NoOpBrokerMessageHandler());
  }

  @Bean
  public AbstractBrokerMessageHandler stompBrokerRelayMessageHandler() {
    AbstractBrokerMessageHandler handler = getBrokerRegistry().getStompBrokerRelay(brokerChannel());
    return (handler != null ? handler : new NoOpBrokerMessageHandler());
  }

  @Bean
  public UserDestinationMessageHandler userDestinationMessageHandler() {
    return new UserDestinationMessageHandler(clientInboundChannel(), brokerChannel(), userDestinationResolver());
  }

  @Bean
  public SimpMessagingTemplate brokerMessagingTemplate() {
    SimpMessagingTemplate template = new SimpMessagingTemplate(brokerChannel());
    String prefix = getBrokerRegistry().getUserDestinationPrefix();
    if (prefix != null) {
      template.setUserDestinationPrefix(prefix);
    }
    template.setMessageConverter(brokerMessageConverter());
    return template;
  }

  @Bean
  public CompositeMessageConverter brokerMessageConverter() {
    List<MessageConverter> converters = new ArrayList<MessageConverter>();
    boolean registerDefaults = configureMessageConverters(converters);
    if (registerDefaults) {
      converters.add(new StringMessageConverter());
      converters.add(new ByteArrayMessageConverter());
      if (jackson2Present) {
        DefaultContentTypeResolver resolver = new DefaultContentTypeResolver();
        resolver.setDefaultMimeType(MimeTypeUtils.APPLICATION_JSON);
        MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
        converter.setContentTypeResolver(resolver);
        converters.add(converter);
      }
    }
    return new CompositeMessageConverter(converters);
  }

  /**
   * Override this method to add custom message converters.
   * @param messageConverters the list to add converters to, initially empty
   * @return {@code true} if default message converters should be added to list,
   * {@code false} if no more converters should be added.
   */
  protected boolean configureMessageConverters(List<MessageConverter> messageConverters) {
    return true;
  }

  @Bean
  public UserDestinationResolver userDestinationResolver() {
    DefaultUserDestinationResolver resolver = new DefaultUserDestinationResolver(userSessionRegistry());
    String prefix = getBrokerRegistry().getUserDestinationPrefix();
    if (prefix != null) {
      resolver.setUserDestinationPrefix(prefix);
    }
    return resolver;
  }

  @Bean
  public UserSessionRegistry userSessionRegistry() {
    return new DefaultUserSessionRegistry();
  }

  /**
   * Return a {@link org.springframework.validation.Validator}s instance for validating
   * {@code @Payload} method arguments.
   * <p>In order, this method tries to get a Validator instance:
   * <ul>
   * <li>delegating to getValidator() first</li>
   * <li>if none returned, getting an existing instance with its well-known name "mvcValidator",
   * created by an MVC configuration</li>
   * <li>if none returned, checking the classpath for the presence of a JSR-303 implementation
   * before creating a {@code OptionalValidatorFactoryBean}</li>
   * <li>returning a no-op Validator instance</li>
   * </ul>
   */
  protected Validator simpValidator() {
    Validator validator = getValidator();
    if (validator == null) {
      if (this.applicationContext.containsBean(MVC_VALIDATOR_NAME)) {
        validator = this.applicationContext.getBean(MVC_VALIDATOR_NAME, Validator.class);
      }
      else if (ClassUtils.isPresent("javax.validation.Validator", getClass().getClassLoader())) {
        Class<?> clazz;
        try {
          String className = "org.springframework.validation.beanvalidation.OptionalValidatorFactoryBean";
          clazz = ClassUtils.forName(className, AbstractMessageBrokerConfiguration.class.getClassLoader());
        }
        catch (Throwable ex) {
          throw new BeanInitializationException("Could not find default validator class", ex);
        }
        validator = (Validator) BeanUtils.instantiate(clazz);
      }
      else {
        validator = new Validator() {
          @Override
          public boolean supports(Class<?> clazz) {
            return false;
          }
          @Override
          public void validate(Object target, Errors errors) {
          }
        };
      }
    }
    return validator;
  }

  /**
   * Override this method to provide a custom {@link Validator}.
   * @since 4.0.1
   */
  public Validator getValidator() {
    return null;
  }


  private class NoOpBrokerMessageHandler extends AbstractBrokerMessageHandler {

    public NoOpBrokerMessageHandler() {
      super(clientInboundChannel(), clientOutboundChannel(), brokerChannel());
    }

    @Override
    public void start() {
    }

    @Override
    public void stop() {
    }

    @Override
    public void handleMessage(Message<?> message) {
    }

    @Override
    protected void handleMessageInternal(Message<?> message) {
    }
  }

}
TOP

Related Classes of org.springframework.messaging.simp.config.AbstractMessageBrokerConfiguration$NoOpBrokerMessageHandler

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.