docs: public void copyToDirectBuffer() {
          if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled()) {
              Tr.entry(tc, "copyToDirectBuffer");
          }
  
          if (oByteBuffer.isDirect()) {
              this.oWsBBDirect = this.oByteBuffer;
              if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled()) {
                  Tr.exit(tc, "copyToDirectBuffer, exit point 1");
              }
              return;
          }
  
          if (this.quickBufferAction == ACTIVATED) {
  
              synchronized (wsBBRoot.actionAccess) {
                  if (wsBBRoot.actionState == PooledWsByteBufferImpl.COPY_WHEN_NEEDED_STATE1) {
  
                      if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
                          Tr.debug(tc, "bufferAction in STATE1, do not copy");
                      }
  
                      // no put activity has been done on the NonDirect Buffer, so
                      // the data in the Direct buffer can be written as is
                      this.oWsBBDirect.limit(oByteBuffer.limit());
                      this.oWsBBDirect.position(oByteBuffer.position());
  
                      if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled()) {
                          Tr.exit(tc, "copyToDirectBuffer, exit point 2");
                      }
                      return;
                  }
  
                  if (wsBBRoot.actionState == PooledWsByteBufferImpl.COPY_WHEN_NEEDED_STATE2) {
  
                      if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
                          Tr.debug(tc, "bufferAction in STATE2, copy only changed data");
                      }
  
                      // put activity has been done on the NonDirect Buffer, so
                      // the new data in the nonDirect buffer needs to be copied
                      // down to the Direct Buffer
                      if ((wsBBRoot.putMin != -1) && (wsBBRoot.putMax != -1)) {
  
                          copyRangeToDirectBuffer(wsBBRoot.putMin, wsBBRoot.putMax);
                          wsBBRoot.putMin = -1;
                          wsBBRoot.putMax = -1;
                      }
  
                      this.oWsBBDirect.limit(oByteBuffer.limit());
                      this.oWsBBDirect.position(oByteBuffer.position());
  
                      if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled()) {
                          Tr.exit(tc, "copyToDirectBuffer, exit point 3");
                      }
                      return;
                  }
              } // end-sync
          }
  
          if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
              Tr.debug(tc, "buffer optimization is off, copy all data");
          }
  
          // we are here because either Optimization was never on, or it just switched off.
          if (oWsBBDirect == null) {
              this.oWsBBDirect = ByteBuffer.allocateDirect(oByteBuffer.capacity());
          }
  
          int cachePosition = this.oByteBuffer.position();
          int cacheLimit = this.oByteBuffer.limit();
          int offset = this.oByteBuffer.arrayOffset();
  
          // set the position and limit for copying
          this.oWsBBDirect.limit(cacheLimit);
          this.oWsBBDirect.position(cachePosition);
  
          // copy the bytes from position to limit
          this.oWsBBDirect.put(oByteBuffer.array(), cachePosition + offset, cacheLimit - cachePosition);
  
          // reset the position
          this.oWsBBDirect.position(cachePosition);
  
          if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled()) {
              Tr.exit(tc, "copyToDirectBuffer, exit point 4");
          }
      }