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.handler; 018 019import org.apache.commons.logging.Log; 020import org.apache.commons.logging.LogFactory; 021 022import org.springframework.web.socket.CloseStatus; 023import org.springframework.web.socket.WebSocketHandler; 024import org.springframework.web.socket.WebSocketMessage; 025import org.springframework.web.socket.WebSocketSession; 026 027/** 028 * An exception handling {@link WebSocketHandlerDecorator}. 029 * Traps all {@link Throwable} instances that escape from the decorated 030 * handler and closes the session with {@link CloseStatus#SERVER_ERROR}. 031 * 032 * @author Rossen Stoyanchev 033 * @since 4.0 034 */ 035public class ExceptionWebSocketHandlerDecorator extends WebSocketHandlerDecorator { 036 037 private static final Log logger = LogFactory.getLog(ExceptionWebSocketHandlerDecorator.class); 038 039 040 public ExceptionWebSocketHandlerDecorator(WebSocketHandler delegate) { 041 super(delegate); 042 } 043 044 045 @Override 046 public void afterConnectionEstablished(WebSocketSession session) { 047 try { 048 getDelegate().afterConnectionEstablished(session); 049 } 050 catch (Throwable ex) { 051 tryCloseWithError(session, ex, logger); 052 } 053 } 054 055 @Override 056 public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) { 057 try { 058 getDelegate().handleMessage(session, message); 059 } 060 catch (Throwable ex) { 061 tryCloseWithError(session, ex, logger); 062 } 063 } 064 065 @Override 066 public void handleTransportError(WebSocketSession session, Throwable exception) { 067 try { 068 getDelegate().handleTransportError(session, exception); 069 } 070 catch (Throwable ex) { 071 tryCloseWithError(session, ex, logger); 072 } 073 } 074 075 @Override 076 public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) { 077 try { 078 getDelegate().afterConnectionClosed(session, closeStatus); 079 } 080 catch (Throwable ex) { 081 if (logger.isWarnEnabled()) { 082 logger.warn("Unhandled exception after connection closed for " + this, ex); 083 } 084 } 085 } 086 087 088 public static void tryCloseWithError(WebSocketSession session, Throwable exception, Log logger) { 089 if (logger.isErrorEnabled()) { 090 logger.error("Closing session due to exception for " + session, exception); 091 } 092 if (session.isOpen()) { 093 try { 094 session.close(CloseStatus.SERVER_ERROR); 095 } 096 catch (Throwable ex) { 097 // ignore 098 } 099 } 100 } 101 102}