@Override
    public void close(CloseReason reason) {
      if (socket.isConnected()) {
        socket.close(reason.getCloseCode().getCode(), reason.getReasonPhrase());

        for (Extension extension : endpoint.getSupportedExtensions()) {
          if (extension instanceof ExtendedExtension) {
            try {
              ((ExtendedExtension) extension).destroy(extensionContext);
            } catch (Throwable t) {
              // ignore.
            }
          }
        }
      }
    }
    TyrusConnection(
        TyrusEndpoint endpoint,
        ProtocolHandler protocolHandler,
        int incomingBufferSize,
        Writer writer,
        Connection.CloseListener closeListener,
        UpgradeRequest upgradeRequest,
        ExtendedExtension.ExtensionContext extensionContext) {
      protocolHandler.setWriter(writer);
      final TyrusWebSocket socket = endpoint.createSocket(protocolHandler);

      socket.onConnect(upgradeRequest);
      this.socket = socket;
      this.readHandler =
          new TyrusReadHandler(
              protocolHandler, socket, endpoint, incomingBufferSize, extensionContext);
      this.writer = writer;
      this.closeListener = closeListener;
      this.extensionContext = extensionContext;
      this.endpoint = endpoint;
    }
    @Override
    public void handle(ByteBuffer data) {
      try {
        if (data != null && data.hasRemaining()) {

          if (buffer != null) {
            data = Utils.appendBuffers(buffer, data, incomingBufferSize, BUFFER_STEP_SIZE);
          } else {
            int newSize = data.remaining();
            if (newSize > incomingBufferSize) {
              throw new IllegalArgumentException("Buffer overflow.");
            } else {
              final int roundedSize =
                  (newSize % BUFFER_STEP_SIZE) > 0
                      ? ((newSize / BUFFER_STEP_SIZE) + 1) * BUFFER_STEP_SIZE
                      : newSize;
              final ByteBuffer result =
                  ByteBuffer.allocate(roundedSize > incomingBufferSize ? newSize : roundedSize);
              result.flip();
              data = Utils.appendBuffers(result, data, incomingBufferSize, BUFFER_STEP_SIZE);
            }
          }

          do {
            final Frame incomingFrame = protocolHandler.unframe(data);

            if (incomingFrame == null) {
              buffer = data;
              break;
            } else {
              Frame frame = incomingFrame;

              for (Extension extension : negotiatedExtensions) {
                if (extension instanceof ExtendedExtension) {
                  try {
                    frame =
                        ((ExtendedExtension) extension).processIncoming(extensionContext, frame);
                  } catch (Throwable t) {
                    LOGGER.log(
                        Level.FINE,
                        String.format(
                            "Extension '%s' threw an exception during processIncoming method invocation: \"%s\".",
                            extension.getName(), t.getMessage()),
                        t);
                  }
                }
              }

              protocolHandler.process(frame, socket);
            }
          } while (true);
        }
      } catch (FramingException e) {
        LOGGER.log(Level.FINE, e.getMessage(), e);
        socket.onClose(
            new CloseFrame(
                new CloseReason(
                    CloseReason.CloseCodes.getCloseCode(e.getClosingCode()), e.getMessage())));
      } catch (Exception e) {
        LOGGER.log(Level.FINE, e.getMessage(), e);
        if (endpoint.onError(socket, e)) {
          socket.onClose(
              new CloseFrame(
                  new CloseReason(CloseReason.CloseCodes.UNEXPECTED_CONDITION, e.getMessage())));
        }
      }
    }
 private void sendBuffer(boolean last) {
   socket.sendText(buffer, last);
 }