net.jotel.ws.client.WebSocketReaderThread.java Source code

Java tutorial

Introduction

Here is the source code for net.jotel.ws.client.WebSocketReaderThread.java

Source

/*
 * Copyright 2012 Jotel Ltd.
 *
 * Licensed 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 net.jotel.ws.client;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.atomic.AtomicBoolean;

import org.apache.commons.io.input.BoundedInputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class WebSocketReaderThread extends Thread {
    private final static Logger log = LoggerFactory.getLogger(WebSocketReaderThread.class);

    private WebSocketClient wsClient;
    private BufferedInputStream inputStream;
    private AtomicBoolean active = new AtomicBoolean(true);

    public WebSocketReaderThread(WebSocketClient wsClient) throws WebSocketException {
        super("WebSocket Reader Thread");

        setDaemon(true);

        this.wsClient = wsClient;
        inputStream = new BufferedInputStream(wsClient.getInputStream());
    }

    public boolean isActive() {
        return active.get();
    }

    public void finish() {
        active.set(false);
    }

    @Override
    public void run() {
        try {
            int inFrameType = 0;

            while (active.get() && !interrupted()) {
                int b = read(inputStream);

                boolean finalFragment = (b & 0x80) == 0x80;
                int opcode = b & 0xF;

                if (!finalFragment) {
                    if (inFrameType == 0) {
                        inFrameType = opcode;
                    }
                } else {
                    inFrameType = 0;
                }

                b = read(inputStream);

                final boolean masked = (b & 0x80) == 0x80;
                // FIXME in the spec length might be 64 bit.. but this implementation won't handle so big amount of data
                int length = b & 0x7f;

                if (length > 125) {
                    int bytesToRead = (length == 126) ? 2 : 8;
                    length = 0;
                    for (int i = 0; i < bytesToRead; i++) {
                        b = read(inputStream);
                        length = length << (i << 3) | (b & 0xFF); // (i * 8) == (i << 3)
                    }
                }

                byte[] mask = null;

                if (masked) {
                    mask = new byte[WebSocketClient.MASK_SIZE];
                    read(inputStream, mask);
                }

                byte[] payload = new byte[length];

                MaskedInputStream maskedInputStream = new MaskedInputStream(
                        new BoundedInputStream(inputStream, length), mask);

                read(maskedInputStream, payload);

                wsClient.onDataFrame(opcode, payload);
            }
        } catch (Exception ex) {
            if (active.compareAndSet(true, false)) {
                wsClient.triggerOnError(ex);
                log.error(ex.getMessage(), ex);

                if (wsClient.isReconnectEnabled()) {
                    new WebSocketReconnectionThread(wsClient).start();
                }
            }
        }
    }

    private int read(BufferedInputStream is) throws IOException, WebSocketException {
        int b = is.read();
        if (b == -1) {
            throw new WebSocketException("Unexpected EOF");
        }
        return b;
    }

    private void read(InputStream is, byte[] buffer) throws IOException, WebSocketException {
        int off = 0;
        int bytesRead = 0;
        int totalBytesRead = 0;
        int bytesToRead = buffer.length;

        do {
            bytesRead = is.read(buffer, off, bytesToRead);
            if (bytesRead > 0) {
                totalBytesRead += bytesRead;
                bytesToRead -= bytesRead;
                off += bytesRead;
            }

        } while (bytesToRead > 0 && bytesRead != -1);

        if (totalBytesRead != buffer.length) {
            throw new WebSocketException("Unexpected end of stream!");
        }
    }
}