All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.netbeans.modules.netserver.websocket.WebSocketServerImpl Maven / Gradle / Ivy

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.netbeans.modules.netserver.websocket;

import org.netbeans.modules.netserver.api.WebSocketReadHandler;
import java.io.IOException;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.netbeans.modules.netserver.ReadHandler;
import org.netbeans.modules.netserver.SocketServer;


/**
 * @author ads
 *
 */
public class WebSocketServerImpl extends SocketServer {
    
    protected static final Logger LOG = SocketServer.LOG;
    
    public WebSocketServerImpl( SocketAddress address ) throws IOException {
        this(address , true);
    }
    
    protected WebSocketServerImpl( SocketAddress address , boolean onlyWebSocket) 
        throws IOException 
    {
        super(address);
        if ( onlyWebSocket ){
            setReadHandler(new WebSocketHandler());
        }
    }
    
    public void setWebSocketReadHandler( WebSocketReadHandler handler ){
        this.handler = handler ;
    }
    
    public WebSocketReadHandler getWebSocketReadHandler(){
        return handler;
    }
    
    public void sendMessage( SelectionKey key , String message){
        byte[] bytes = getHandler(key).createTextFrame( message);
        send(bytes , key); 
    }
    
    @Override
    public void close(SelectionKey key) throws IOException {
        super.close(key);
        getWebSocketReadHandler().closed(key);
    }
    
    /* (non-Javadoc)
     * @see org.netbeans.modules.web.common.websocket.SocketServer#getWriteQueue(java.nio.channels.SelectionKey)
     */
    @Override
    protected Queue getWriteQueue( SelectionKey key ) {
        return getContext(key).getQueue();
    }

    @Override
    protected SocketAddress getAddress() {
        return super.getAddress();
    }
    
    /* (non-Javadoc)
     * @see org.netbeans.modules.web.common.websocket.SocketServer#initWriteQueue(java.nio.channels.SelectionKey)
     */
    @Override
    protected void initWriteQueue( SelectionKey key ) {
        if ( key.attachment() == null ){
            key.attach( new SocketContext() );
        }
    }
    
    /* (non-Javadoc)
     * @see org.netbeans.modules.web.common.websocket.SocketServer#getReadHandler()
     */
    @Override
    protected WebSocketHandler getReadHandler() {
        return (WebSocketHandler)super.getReadHandler();
    }
    
    SocketContext getContext( SelectionKey key ){
        return (SocketContext)key.attachment();
    }
    
    void setHandler( WebSocketChanelHandler handler , SelectionKey key){
        getContext(key).setHandler(handler);
    }
    
    WebSocketChanelHandler getHandler(SelectionKey key ){
        return getContext(key).getHandler();
    }
    
    static class SocketContext {
        
        public SocketContext() {
            writeQueue = new ConcurrentLinkedQueue();
        }
        
        Queue getQueue(){
            return writeQueue;
        }
        
        Map getHeaders(){
            return headers;
        }
        
        void setHeaders( Map headers ){
            this.headers = headers;
        }
        
        String getRequestString(){
            return httpRequest;
        }
        
        byte[] getContent(){
            return content;
        }
        
        void setRequest( String request ){
            httpRequest = request;
        }
        
        void setHandler( WebSocketChanelHandler handler ){
            this.handler = handler;
        }
        
        void setContent( byte[] content ) {
            this.content = content;
        }
        
        WebSocketChanelHandler getHandler(){
            return handler;
        }
        
        private final Queue writeQueue; 
        private volatile Map headers;
        private volatile String httpRequest;
        private volatile WebSocketChanelHandler handler;
        private volatile byte[] content;
    }
    
    protected class WebSocketHandler implements ReadHandler {
        
        WebSocketHandler(){
            byteBuffer = ByteBuffer.allocate(Utils.BYTES);
        }
        
        /* (non-Javadoc)
         * @see org.netbeans.modules.web.common.websocket.ReadHandler#read(java.nio.channels.SelectionKey)
         */
        @Override
        public void read( SelectionKey key ) throws IOException {
            if ( getContext(key).getHeaders()!=null ){
                getContext(key).getHandler().read( byteBuffer );
            }
            else {
                handshake( key );
            }
        }
        
        protected void handshake( SelectionKey key ) throws IOException {
            SocketChannel socketChannel = (SocketChannel) key.channel();
            try {
                if ( !readHttpRequest(socketChannel, key )){
                    close(key);
                    return;
                }
                initHandler(key);
                getWebSocketReadHandler().accepted(key);
            }
            catch(IOException e ){
                close(key);
            }
        }

        protected void initHandler( SelectionKey key ) throws IOException {
            Map headers = getContext(key).getHeaders();
            String version = headers.get(Utils.VERSION);
            if ( version == null ){
                if ( headers.containsKey( Utils.KEY1 ) ){
                    handshakeVersion76( key );
                }
                else {
                    handshakeVersion75( key );
                }
            }
            else {
                handshakeVersion7( key );
            }
            WebSocketChanelHandler handler = getHandler(key);
            if ( handler== null){
                LOG.log(Level.WARNING , "Unexpected protocol version. " +
                		"Chanel handler is null."); 
                close(key);
                return;
            }
            handler.sendHandshake( );
        }
        
        /**
         * Handshake for protocol version since 07
         */
        private void handshakeVersion7( SelectionKey key ) {
            setHandler( new WebSocketHandler7(WebSocketServerImpl.this, key ), key );
        }

        /**
         * Handshake for protocol version 75
         */
        private void handshakeVersion75( SelectionKey key ) {
            setHandler( new WebSocketHandler75(WebSocketServerImpl.this, key ), key );            
        }

        /**
         * Handshake for protocol version 76
         */
        private void handshakeVersion76( SelectionKey key ) {
            setHandler( new WebSocketHandler76(WebSocketServerImpl.this, key ), key );            
        }

        protected boolean readHttpRequest(SocketChannel socketChannel, 
                SelectionKey key) throws IOException
        {
            byte[] content = new byte[8];
            List headers = Utils.readHttpRequest(socketChannel, byteBuffer, 
                    content);
            if ( headers != null ){
                setHeaders(key , headers, content );
                return true;
            }
            else {
                return false;
            }
        }
        
        private void setHeaders(SelectionKey key , List headerLines,
                byte[] content )
        {
            if ( headerLines.size() >0 ){
                getContext(key).setRequest(headerLines.get(0));
            }
            Map result = new HashMap();
            for (String line : headerLines) {
                int index = line.indexOf(':');
                if ( index != -1 ){
                    result.put( line.substring( 0, index), line.substring(index+1).trim());
                }
            }
            getContext(key).setHeaders(result);
            getContext(key).setContent(content);
        }
        
        private ByteBuffer byteBuffer;
    }
    
    private volatile WebSocketReadHandler handler;
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy