View Javadoc
1   /*
2    * Copyright 2002-2015 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.springframework.web.socket.adapter.jetty;
18  
19  import java.nio.ByteBuffer;
20  
21  import org.apache.commons.logging.Log;
22  import org.apache.commons.logging.LogFactory;
23  import org.eclipse.jetty.websocket.api.Session;
24  import org.eclipse.jetty.websocket.api.annotations.OnWebSocketClose;
25  import org.eclipse.jetty.websocket.api.annotations.OnWebSocketConnect;
26  import org.eclipse.jetty.websocket.api.annotations.OnWebSocketError;
27  import org.eclipse.jetty.websocket.api.annotations.OnWebSocketFrame;
28  import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
29  import org.eclipse.jetty.websocket.api.annotations.WebSocket;
30  import org.eclipse.jetty.websocket.api.extensions.Frame;
31  import org.eclipse.jetty.websocket.common.OpCode;
32  
33  import org.springframework.util.Assert;
34  import org.springframework.web.socket.BinaryMessage;
35  import org.springframework.web.socket.CloseStatus;
36  import org.springframework.web.socket.PongMessage;
37  import org.springframework.web.socket.TextMessage;
38  import org.springframework.web.socket.WebSocketHandler;
39  import org.springframework.web.socket.handler.ExceptionWebSocketHandlerDecorator;
40  
41  
42  /**
43   * Adapts {@link WebSocketHandler} to the Jetty 9 WebSocket API.
44   *
45   * @author Rossen Stoyanchev
46   * @since 4.0
47   */
48  @WebSocket
49  public class JettyWebSocketHandlerAdapter {
50  
51  	private static final ByteBuffer EMPTY_PAYLOAD = ByteBuffer.wrap(new byte[0]);
52  
53  	private static final Log logger = LogFactory.getLog(JettyWebSocketHandlerAdapter.class);
54  
55  
56  	private final WebSocketHandler webSocketHandler;
57  
58  	private final JettyWebSocketSession wsSession;
59  
60  
61  	public JettyWebSocketHandlerAdapter(WebSocketHandler webSocketHandler, JettyWebSocketSession wsSession) {
62  		Assert.notNull(webSocketHandler, "webSocketHandler must not be null");
63  		Assert.notNull(wsSession, "wsSession must not be null");
64  		this.webSocketHandler = webSocketHandler;
65  		this.wsSession = wsSession;
66  	}
67  
68  
69  	@OnWebSocketConnect
70  	public void onWebSocketConnect(Session session) {
71  		try {
72  			this.wsSession.initializeNativeSession(session);
73  			this.webSocketHandler.afterConnectionEstablished(this.wsSession);
74  		}
75  		catch (Throwable t) {
76  			ExceptionWebSocketHandlerDecorator.tryCloseWithError(this.wsSession, t, logger);
77  		}
78  	}
79  
80  	@OnWebSocketMessage
81  	public void onWebSocketText(String payload) {
82  		TextMessage message = new TextMessage(payload);
83  		try {
84  			this.webSocketHandler.handleMessage(this.wsSession, message);
85  		}
86  		catch (Throwable t) {
87  			ExceptionWebSocketHandlerDecorator.tryCloseWithError(this.wsSession, t, logger);
88  		}
89  	}
90  
91  	@OnWebSocketMessage
92  	public void onWebSocketBinary(byte[] payload, int offset, int length) {
93  		BinaryMessage message = new BinaryMessage(payload, offset, length, true);
94  		try {
95  			this.webSocketHandler.handleMessage(this.wsSession, message);
96  		}
97  		catch (Throwable t) {
98  			ExceptionWebSocketHandlerDecorator.tryCloseWithError(this.wsSession, t, logger);
99  		}
100 	}
101 
102 	@OnWebSocketFrame
103 	public void onWebSocketFrame(Frame frame) {
104 		if (OpCode.PONG == frame.getOpCode()) {
105 			ByteBuffer payload = frame.getPayload() != null ? frame.getPayload() : EMPTY_PAYLOAD;
106 			PongMessage message = new PongMessage(payload);
107 			try {
108 				this.webSocketHandler.handleMessage(this.wsSession, message);
109 			}
110 			catch (Throwable t) {
111 				ExceptionWebSocketHandlerDecorator.tryCloseWithError(this.wsSession, t, logger);
112 			}
113 		}
114 	}
115 
116 	@OnWebSocketClose
117 	public void onWebSocketClose(int statusCode, String reason) {
118 		CloseStatus closeStatus = new CloseStatus(statusCode, reason);
119 		try {
120 			this.webSocketHandler.afterConnectionClosed(this.wsSession, closeStatus);
121 		}
122 		catch (Throwable t) {
123 			logger.error("Unhandled error for " + this.wsSession, t);
124 		}
125 	}
126 
127 	@OnWebSocketError
128 	public void onWebSocketError(Throwable cause) {
129 		try {
130 			this.webSocketHandler.handleTransportError(this.wsSession, cause);
131 		}
132 		catch (Throwable t) {
133 			ExceptionWebSocketHandlerDecorator.tryCloseWithError(this.wsSession, t, logger);
134 		}
135 	}
136 
137 }