@Override
                    public void run() {

                        StringBuilder buffer = new StringBuilder(BUFFER_SIZE);
                        GuacamoleReader reader = tunnel.acquireReader();
                        char[] readMessage;

                        try {

                            // Send tunnel UUID
                            sendInstruction(new GuacamoleInstruction(
                                GuacamoleTunnel.INTERNAL_DATA_OPCODE,
                                tunnel.getUUID().toString()
                            ));

                            try {

                                // Attempt to read
                                while ((readMessage = reader.read()) != null) {

                                    // Buffer message
                                    buffer.append(readMessage);

                                    // Flush if we expect to wait or buffer is getting full
                                    if (!reader.available() || buffer.length() >= BUFFER_SIZE) {
                                        sendInstruction(buffer.toString());
                                        buffer.setLength(0);
                                    }

                                }

                                // No more data
                                closeConnection(connection, GuacamoleStatus.SUCCESS);
                                
                            }

                            // Catch any thrown guacamole exception and attempt
                            // to pass within the WebSocket connection, logging
                            // each error appropriately.
                            catch (GuacamoleClientException e) {
                                logger.info("WebSocket connection terminated: {}", e.getMessage());
                                logger.debug("WebSocket connection terminated due to client error.", e);
                                closeConnection(connection, e.getStatus().getGuacamoleStatusCode(),
                                        e.getWebSocketCode());
                            }
                            catch (GuacamoleConnectionClosedException e) {
                                logger.debug("Connection to guacd closed.", e);
                                closeConnection(connection, GuacamoleStatus.SUCCESS);
                            }
                            catch (GuacamoleException e) {
                                logger.error("Connection to guacd terminated abnormally: {}", e.getMessage());
                                logger.debug("Internal error during connection to guacd.", e);
                                closeConnection(connection, e.getStatus().getGuacamoleStatusCode(),
                                        e.getWebSocketCode());
                            }

                        }
                        catch (IOException e) {
                            logger.debug("WebSocket tunnel read failed due to I/O error.", e);
                            closeConnection(connection, GuacamoleStatus.SERVER_ERROR);
                        }

                    }
Sends a Guacamole instruction along the outbound WebSocket
connection to the connected Guacamole client. If an instruction
is already in the process of being sent by another thread, this
function will block until in-progress instructions are complete.

@param instruction
    The instruction to send.

@throws IOException
    If an I/O error occurs preventing the given instruction from being
    sent.
guacamole/src/main/java/org/apache/guacamole/tunnel/websocket/jetty8/GuacamoleWebSocketTunnelServlet.java