@Override
  public void handshake(Muxer muxer, MuxChannel channel, UpgradeRequest request)
      throws MuxException, IOException {
    StringBuilder response = new StringBuilder();
    response.append("HTTP/1.1 101 Switching Protocols\r\n");
    response.append("Connection: upgrade\r\n");
    // not meaningful (per Draft 08) hresp.append("Upgrade: websocket\r\n");
    // not meaningful (per Draft 08) hresp.append("Sec-WebSocket-Accept:
    // Kgo85/8KVE8YPONSeyhgL3GwqhI=\r\n");
    response.append("\r\n");

    EventDriver websocket = this.eventDriverFactory.wrap(echo);
    WebSocketSession session = new WebSocketSession(request.getRequestURI(), websocket, channel);
    session.setNegotiatedSubprotocol("echo");
    channel.setSession(session);
    channel.setSubProtocol("echo");
    channel.onOpen();
    session.open();

    MuxAddChannelResponse addChannelResponse = new MuxAddChannelResponse();
    addChannelResponse.setChannelId(channel.getChannelId());
    addChannelResponse.setEncoding(MuxAddChannelResponse.IDENTITY_ENCODING);
    addChannelResponse.setFailed(false);
    addChannelResponse.setHandshake(response.toString());

    muxer.output(addChannelResponse);
  }
  private void upgradeConnection(ClientUpgradeResponse response) {
    EndPoint endp = getEndPoint();
    Executor executor = getExecutor();
    WebSocketClientConnection connection = new WebSocketClientConnection(endp, executor, client);

    // Initialize / Negotiate Extensions
    EventDriver websocket = client.getWebSocket();
    WebSocketPolicy policy = client.getPolicy();
    String acceptedSubProtocol = response.getAcceptedSubProtocol();

    WebSocketSession session = new WebSocketSession(request.getRequestURI(), websocket, connection);
    session.setPolicy(policy);
    session.setNegotiatedSubprotocol(acceptedSubProtocol);

    connection.setSession(session);
    List<Extension> extensions = client.getFactory().initExtensions(response.getExtensions());

    // Start with default routing.
    IncomingFrames incoming = session;
    // OutgoingFrames outgoing = connection;

    // Connect extensions
    if (extensions != null) {
      connection.getParser().configureFromExtensions(extensions);
      connection.getGenerator().configureFromExtensions(extensions);

      // FIXME
      // Iterator<Extension> extIter;
      // // Connect outgoings
      // extIter = extensions.iterator();
      // while (extIter.hasNext())
      // {
      // Extension ext = extIter.next();
      // ext.setNextOutgoingFrames(outgoing);
      // outgoing = ext;
      // }
      //
      // // Connect incomings
      // Collections.reverse(extensions);
      // extIter = extensions.iterator();
      // while (extIter.hasNext())
      // {
      // Extension ext = extIter.next();
      // ext.setNextIncomingFrames(incoming);
      // incoming = ext;
      // }
    }

    // configure session for outgoing flows
    // session.setOutgoing(outgoing);
    // configure connection for incoming flows
    connection.getParser().setIncomingFramesHandler(incoming);

    // Now swap out the connection
    endp.setConnection(connection);
    connection.onOpen();
  }
    @Override
    public void onWebSocketText(String message) {
      LOG.debug("onWebSocketText({})", message);
      calls.incrementAndGet();
      if (message.equalsIgnoreCase("openSessions")) {
        Collection<WebSocketSession> sessions = container.getOpenSessions();

        StringBuilder ret = new StringBuilder();
        ret.append("openSessions.size=").append(sessions.size()).append('\n');
        int idx = 0;
        for (WebSocketSession sess : sessions) {
          ret.append('[').append(idx++).append("] ").append(sess.toString()).append('\n');
        }
        session.getRemote().sendStringByFuture(ret.toString());
        session.close(StatusCode.NORMAL, "ContainerSocket");
      } else if (message.equalsIgnoreCase("calls")) {
        session.getRemote().sendStringByFuture(String.format("calls=%,d", calls.get()));
      }
    }
  @Override
  public void incomingFrame(Frame frame) {
    if (LOG.isDebugEnabled()) {
      LOG.debug("{}.onFrame({})", websocket.getClass().getSimpleName(), frame);
    }

    try {
      onFrame(frame);

      byte opcode = frame.getOpCode();
      switch (opcode) {
        case OpCode.CLOSE:
          {
            boolean validate = true;
            CloseFrame closeframe = (CloseFrame) frame;
            CloseInfo close = new CloseInfo(closeframe, validate);

            // notify user websocket pojo
            onClose(close);

            // process handshake
            session.getConnection().getIOState().onCloseRemote(close);

            return;
          }
        case OpCode.PING:
          {
            if (LOG.isDebugEnabled()) {
              LOG.debug("PING: {}", BufferUtil.toDetailString(frame.getPayload()));
            }
            ByteBuffer pongBuf;
            if (frame.hasPayload()) {
              pongBuf = ByteBuffer.allocate(frame.getPayload().remaining());
              BufferUtil.put(frame.getPayload().slice(), pongBuf);
              BufferUtil.flipToFlush(pongBuf, 0);
            } else {
              pongBuf = ByteBuffer.allocate(0);
            }
            onPing(frame.getPayload());
            session.getRemote().sendPong(pongBuf);
            break;
          }
        case OpCode.PONG:
          {
            if (LOG.isDebugEnabled()) {
              LOG.debug("PONG: {}", BufferUtil.toDetailString(frame.getPayload()));
            }
            onPong(frame.getPayload());
            break;
          }
        case OpCode.BINARY:
          {
            onBinaryFrame(frame.getPayload(), frame.isFin());
            return;
          }
        case OpCode.TEXT:
          {
            onTextFrame(frame.getPayload(), frame.isFin());
            return;
          }
        case OpCode.CONTINUATION:
          {
            onContinuationFrame(frame.getPayload(), frame.isFin());
            return;
          }
        default:
          {
            LOG.debug("Unhandled OpCode: {}", opcode);
          }
      }
    } catch (NotUtf8Exception e) {
      terminateConnection(StatusCode.BAD_PAYLOAD, e.getMessage());
    } catch (CloseException e) {
      terminateConnection(e.getStatusCode(), e.getMessage());
    } catch (Throwable t) {
      unhandled(t);
    }
  }
 protected void dispatch(Runnable runnable) {
   session.dispatch(runnable);
 }
 protected void terminateConnection(int statusCode, String rawreason) {
   LOG.debug("terminateConnection({},{})", statusCode, rawreason);
   session.close(statusCode, CloseFrame.truncate(rawreason));
 }