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}