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}