docs: @Override
      public long write(long _numBytes, int timeout) throws IOException {
          if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled()) {
              Tr.entry(tc, "write, numBytes=" + _numBytes + ", timeout=" + timeout + ", vc=" + getVCHash());
          }
          final TCPWriteRequestContext tcp = getConnLink().getDeviceWriteInterface();
          long numBytesLeft = _numBytes;
  
          // Handle timing out of former read request.
          if (timeout == IMMED_TIMEOUT || timeout == ABORT_TIMEOUT) {
              if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
                  Tr.debug(tc, "Requested to timeout former request.  Calling device side.");
              }
              tcp.write(numBytesLeft, timeout);
              if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled()) {
                  Tr.exit(tc, "write");
              }
              return 0;
          }
  
          // Look for errors in the request.
          IOException exception = checkForErrors(numBytesLeft, false);
          if (exception != null) {
              // Found an error.
              throw exception;
          }
          SSLEngineResult result = null;
          final long maxBytes = WsByteBufferUtils.lengthOf(getBuffers());
          if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
              Tr.debug(tc, "App provided " + maxBytes + " bytes");
          }
  
          // Adjust size of numBytes if all data is requested to be written (-1).
          if (numBytesLeft == TCPWriteRequestContext.WRITE_ALL_DATA) {
              numBytesLeft = maxBytes;
          }
  
          // Check if a handshake is needed.
          if (SSLUtils.isHandshaking(getConnLink().getSSLEngine())) {
              try {
                  // A handshake is needed.
                  result = doHandshake(null);
              } catch (IOException e) {
                  if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
                      Tr.debug(tc, "Exception caught during handshake, " + e);
                  }
                  FFDCFilter.processException(e, getClass().getName(), "84", this);
                  throw e;
              }
              // Verify the output of the handshake.
              if (result.getHandshakeStatus() != HandshakeStatus.FINISHED) {
                  IOException e = new IOException("Unable to complete SSLhandshake");
                  if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
                      Tr.debug(tc, "Unable to complete SSLhandshake, " + e);
                  }
                  FFDCFilter.processException(e, getClass().getName(), "117", this);
                  throw e;
              }
          }
  
          // Encrypt the data and write it to the network.
  
          // make sure we have an output buffer of the target size ready
          final int packetSize = getConnLink().getPacketBufferSize();
          if (numBytesLeft > packetSize) {
              // need >1 packet, do blocks of up to 2 at a time
              getEncryptedAppBuffer(packetSize * 2);
          } else {
              // one packet is fine
              getEncryptedAppBuffer(1);
          }
  
          try {
              final int cap = this.encryptedAppBuffer.capacity();
              int produced;
  
              do {
                  // write distinct blocks of data to reduce excess overhead (for example, the
                  // encrypted buffer must be continually expanded to fit the output data since
                  // we can only hand 1 buffer to JSSE, which is expensive expanding and copying data)
                  this.encryptedAppBuffer.clear();
  
                  result = encryptMessage();
                  numBytesLeft -= result.bytesConsumed();
                  produced = result.bytesProduced();
                  if (0 < produced) {
                      while (0 < numBytesLeft && (cap - produced) >= packetSize) {
                          // space in the current output buffer to encrypt a little more
                          // Note: JSSE requires a full packet size of open space regardless of the input
                          // amount, so even 100 bytes to encrypt requires 16K of output space
                          result = encryptMessage();
                          numBytesLeft -= result.bytesConsumed();
                          produced += result.bytesProduced();
                      }
  
                      this.encryptedAppBuffer.flip();
                      tcp.setBuffer(this.encryptedAppBuffer);
                      final long wrote = tcp.write(TCPWriteRequestContext.WRITE_ALL_DATA, timeout);
                      if (TraceComponent.isAnyTracingEnabled() && tc.isEventEnabled()) {
                          Tr.event(tc, "wrote " + wrote);
                      }
                  }
  
              } while (0 < numBytesLeft && 0 < produced);
          } catch (Exception original) {
              synchronized (closeSync) {
                  // if close has been called then assume this exception was due to a race condition
                  // with the close logic and consume the exception without FFDC. Otherwise rethrow
                  // as the logic did before this change.
                  if (closeCalled) {
                      IOException up = new IOException("Exception occurred while close detected" + original);
                      throw up;
                  } else {
                      throw original;
                  }
              }
          }
  
          final long rc = (maxBytes - numBytesLeft);
          if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled()) {
              Tr.exit(tc, "write: " + rc);
          }
          return (rc);
      }