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.reactive.socket.adapter; 018 019import java.util.HashMap; 020import java.util.Map; 021 022import io.netty.buffer.ByteBuf; 023import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame; 024import io.netty.handler.codec.http.websocketx.PingWebSocketFrame; 025import io.netty.handler.codec.http.websocketx.PongWebSocketFrame; 026import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; 027import io.netty.handler.codec.http.websocketx.WebSocketFrame; 028 029import org.springframework.core.io.buffer.DataBuffer; 030import org.springframework.core.io.buffer.NettyDataBufferFactory; 031import org.springframework.util.ObjectUtils; 032import org.springframework.web.reactive.socket.HandshakeInfo; 033import org.springframework.web.reactive.socket.WebSocketMessage; 034import org.springframework.web.reactive.socket.WebSocketSession; 035 036/** 037 * Base class for Netty-based {@link WebSocketSession} adapters that provides 038 * convenience methods to convert Netty {@link WebSocketFrame WebSocketFrames} to and from 039 * {@link WebSocketMessage WebSocketMessages}. 040 * 041 * @author Rossen Stoyanchev 042 * @since 5.0 043 * @param <T> the native delegate type 044 */ 045public abstract class NettyWebSocketSessionSupport<T> extends AbstractWebSocketSession<T> { 046 047 /** 048 * The default max size for inbound WebSocket frames. 049 */ 050 public static final int DEFAULT_FRAME_MAX_SIZE = 64 * 1024; 051 052 053 private static final Map<Class<?>, WebSocketMessage.Type> messageTypes; 054 055 static { 056 messageTypes = new HashMap<>(8); 057 messageTypes.put(TextWebSocketFrame.class, WebSocketMessage.Type.TEXT); 058 messageTypes.put(BinaryWebSocketFrame.class, WebSocketMessage.Type.BINARY); 059 messageTypes.put(PingWebSocketFrame.class, WebSocketMessage.Type.PING); 060 messageTypes.put(PongWebSocketFrame.class, WebSocketMessage.Type.PONG); 061 } 062 063 064 protected NettyWebSocketSessionSupport(T delegate, HandshakeInfo info, NettyDataBufferFactory factory) { 065 super(delegate, ObjectUtils.getIdentityHexString(delegate), info, factory); 066 } 067 068 069 @Override 070 public NettyDataBufferFactory bufferFactory() { 071 return (NettyDataBufferFactory) super.bufferFactory(); 072 } 073 074 075 protected WebSocketMessage toMessage(WebSocketFrame frame) { 076 DataBuffer payload = bufferFactory().wrap(frame.content()); 077 return new WebSocketMessage(messageTypes.get(frame.getClass()), payload); 078 } 079 080 protected WebSocketFrame toFrame(WebSocketMessage message) { 081 ByteBuf byteBuf = NettyDataBufferFactory.toByteBuf(message.getPayload()); 082 if (WebSocketMessage.Type.TEXT.equals(message.getType())) { 083 return new TextWebSocketFrame(byteBuf); 084 } 085 else if (WebSocketMessage.Type.BINARY.equals(message.getType())) { 086 return new BinaryWebSocketFrame(byteBuf); 087 } 088 else if (WebSocketMessage.Type.PING.equals(message.getType())) { 089 return new PingWebSocketFrame(byteBuf); 090 } 091 else if (WebSocketMessage.Type.PONG.equals(message.getType())) { 092 return new PongWebSocketFrame(byteBuf); 093 } 094 else { 095 throw new IllegalArgumentException("Unexpected message type: " + message.getType()); 096 } 097 } 098 099}