001/* 002 * Copyright 2002-2018 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.web.socket.messaging; 018 019import java.util.ArrayList; 020import java.util.List; 021 022import org.springframework.context.ApplicationContext; 023import org.springframework.core.annotation.AnnotationAwareOrderComparator; 024import org.springframework.messaging.MessageChannel; 025import org.springframework.messaging.SubscribableChannel; 026import org.springframework.messaging.handler.MessagingAdviceBean; 027import org.springframework.messaging.handler.annotation.support.AnnotationExceptionHandlerMethodResolver; 028import org.springframework.messaging.simp.SimpMessageSendingOperations; 029import org.springframework.messaging.simp.annotation.support.SimpAnnotationMethodMessageHandler; 030import org.springframework.web.method.ControllerAdviceBean; 031 032/** 033 * A sub-class of {@link SimpAnnotationMethodMessageHandler} to provide support 034 * for {@link org.springframework.web.bind.annotation.ControllerAdvice 035 * ControllerAdvice} with global {@code @MessageExceptionHandler} methods. 036 * 037 * @author Rossen Stoyanchev 038 * @since 4.2 039 */ 040public class WebSocketAnnotationMethodMessageHandler extends SimpAnnotationMethodMessageHandler { 041 042 public WebSocketAnnotationMethodMessageHandler(SubscribableChannel clientInChannel, 043 MessageChannel clientOutChannel, SimpMessageSendingOperations brokerTemplate) { 044 045 super(clientInChannel, clientOutChannel, brokerTemplate); 046 } 047 048 049 @Override 050 public void afterPropertiesSet() { 051 initControllerAdviceCache(); 052 super.afterPropertiesSet(); 053 } 054 055 private void initControllerAdviceCache() { 056 ApplicationContext context = getApplicationContext(); 057 if (context == null) { 058 return; 059 } 060 if (logger.isDebugEnabled()) { 061 logger.debug("Looking for @MessageExceptionHandler mappings: " + context); 062 } 063 List<ControllerAdviceBean> beans = ControllerAdviceBean.findAnnotatedBeans(context); 064 AnnotationAwareOrderComparator.sort(beans); 065 initMessagingAdviceCache(MessagingControllerAdviceBean.createFromList(beans)); 066 } 067 068 private void initMessagingAdviceCache(List<MessagingAdviceBean> beans) { 069 if (beans == null) { 070 return; 071 } 072 for (MessagingAdviceBean bean : beans) { 073 Class<?> type = bean.getBeanType(); 074 AnnotationExceptionHandlerMethodResolver resolver = new AnnotationExceptionHandlerMethodResolver(type); 075 if (resolver.hasExceptionMappings()) { 076 registerExceptionHandlerAdvice(bean, resolver); 077 if (logger.isInfoEnabled()) { 078 logger.info("Detected @MessageExceptionHandler methods in " + bean); 079 } 080 } 081 } 082 } 083 084 085 /** 086 * Adapt ControllerAdviceBean to MessagingAdviceBean. 087 */ 088 private static class MessagingControllerAdviceBean implements MessagingAdviceBean { 089 090 private final ControllerAdviceBean adviceBean; 091 092 private MessagingControllerAdviceBean(ControllerAdviceBean adviceBean) { 093 this.adviceBean = adviceBean; 094 } 095 096 public static List<MessagingAdviceBean> createFromList(List<ControllerAdviceBean> beans) { 097 List<MessagingAdviceBean> result = new ArrayList<MessagingAdviceBean>(beans.size()); 098 for (ControllerAdviceBean bean : beans) { 099 result.add(new MessagingControllerAdviceBean(bean)); 100 } 101 return result; 102 } 103 104 @Override 105 public Class<?> getBeanType() { 106 return this.adviceBean.getBeanType(); 107 } 108 109 @Override 110 public Object resolveBean() { 111 return this.adviceBean.resolveBean(); 112 } 113 114 @Override 115 public boolean isApplicableToBeanType(Class<?> beanType) { 116 return this.adviceBean.isApplicableToBeanType(beanType); 117 } 118 119 @Override 120 public int getOrder() { 121 return this.adviceBean.getOrder(); 122 } 123 } 124 125}