docs: public void complete(NetworkConnection vc, IOReadRequestContext rctx)
     {	
        if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled()) SibTr.entry(this, tc, "complete", new Object[] {vc, rctx});
        if (thisConnection.isLoggingIOEvents()) thisConnection.getConnectionEventRecorder().logDebug("complete method invoked on read context "+System.identityHashCode(rctx));
  
        // First update the invocation count. If we are being called back on the same thread as
        // last time, increment the counter. Otherwise, start counting from 1 again.
        synchronized (invocationCountLock)
        {
           if (lastInvokedOnThread == Thread.currentThread())
           {
              invocationCount++;
           }
           else
           {
              invocationCount = 1;
              lastInvokedOnThread = Thread.currentThread();
           }
        }
  
        try
        {
           synchronized(this)
           {
              boolean done = false;
              do
              {
                 done = true;
                 WsByteBuffer contextBuffer = rctx.getBuffer();
  
                 contextBuffer.flip();
  
                 // Notify PMI that read has completed.
                 if (conversation.getConversationType() == Conversation.CLIENT)
                 {
                    xmitParser.setType(Conversation.CLIENT);
                 }
                 else if (conversation.getConversationType() == Conversation.ME)
                 {
                    xmitParser.setType(Conversation.ME);
                 }
  
                 if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled()) JFapUtils.debugTraceWsByteBuffer(this, tc, contextBuffer, 16, "data received");
  
                 xmitParser.parse(contextBuffer);
  
           		if ((rctx != null) && (!receivePhysicalCloseRequest))
           		{
                    // Calculate the amount of time before the request times out
                    // This is the mechanism by which we implement heartbeat
                    // intervals and time outs.
                    int timeout;
                    if (awaitingHeartbeatResponse.isSet())
                    {
                       // We can only reach this point in the code if we have
                       // made a heartbeat request but this callback was driven
                       // because of a non-heartbeat response.  In previous versions
                       // of the code we were careful to calculate the remaining time and
                       // make another read request.  This caused timeouts ala defect
                       // 363463.  So, now the code is more generous and resets its
                       // timer to the full heartbeat timeout value every time any
                       // non-heartbeat trasmission is received from our peer.  This isn't
                       // unreasonable as the fact we are receiving data indicates that the
                       // peer is probably still healthy.
                       timeout = currentHeartbeatTimeout*1000;
                       if (timeout < 1) timeout = 1;
                    }
                    else
                    {
                       // We are not awaiting a heartbeat response, use the
                       // heartbeat interval as our timeout.
                       timeout = thisConnection.getHeartbeatInterval()*1000;
                    }
  
                    if (timeout > 0)
                    {
                       if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) SibTr.debug(this, tc, "setting heartbeat timeout to: "+timeout+" milliseconds");
                    }
                    else
                    {
                       if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) SibTr.debug(this, tc, "not using a heartbeat timeout");
                       timeout = IOReadRequestContext.NO_TIMEOUT;
                    }
  
                    boolean closing = false;
                    synchronized(connectionClosingLock)
                    {
                       closing = connectionClosing;
                    }
  
                    //If the connection is closing/closed our buffers will have been released, so make sure we don't use them again.
                    if (!closing)
                    {
                       // Crude way to ensure we end up with the right sized read buffer.
                       if (isFirstCompleteInvocation)
                       {
                          int readBufferSize =
                             Integer.parseInt(RuntimeInfo.getProperty("com.ibm.ws.sib.jfapchannel.DEFAULT_READ_BUFFER_SIZE", ""+JFapChannelConstants.DEFAULT_READ_BUFFER_SIZE));
                          if (!contextBuffer.isDirect() || (contextBuffer.capacity() < readBufferSize))
                          {
                             //Make sure we release the other buffer so we don't leak memory.
                             contextBuffer.release();
  
                             contextBuffer = WsByteBufferPool.getInstance().allocateDirect(readBufferSize);
                             rctx.setBuffer(contextBuffer);
                          }
                          isFirstCompleteInvocation = false;
                       }
  
                       contextBuffer.clear();
  
                       // Decide whether to explictly request a thread switch. We'll do this if we
                       // have been recursively called more than MAX_INVOCATIONS_BEFORE_THREAD_SWITCH
                       boolean forceQueue = false;
                       synchronized (invocationCountLock)
                       {
                          if (invocationCount > MAX_INVOCATIONS_BEFORE_THREAD_SWITCH)
                          {
                             forceQueue = true;
                             lastInvokedOnThread = null;
                          }
                       }
  
                       if (thisConnection.isLoggingIOEvents()) thisConnection.getConnectionEventRecorder().logDebug("invoking readCtx.read() on context "+System.identityHashCode(rctx)+" with a timeout of "+timeout);
                       done = (rctx.read(1, this, forceQueue, timeout) == null);
                     
                    }
           		}
              }
              while(!done);
           }
        }
        catch(Error error)
        {
           FFDCFilter.processException
           (error, "com.ibm.ws.sib.jfapchannel.impl.ConnectionReadCompletedCallback", JFapChannelConstants.CONNREADCOMPCALLBACK_COMPLETE_01, thisConnection.getDiagnostics(true));
           if (TraceComponent.isAnyTracingEnabled() && tc.isEventEnabled()) SibTr.exception(this, tc, error);
  
           // It might appear slightly odd for this code to catch Error (especially since the JDK docs say
           // that Error means that something has gone so badly wrong that you should abandon all hope).
           // This code makes one final stab at putting out some diagnostics about what happened (if we
           // propagate the Error up to the TCP Channel, it is sometimes lost) and closing down the
           // connection.  I figured that we might as well try to do something - as we can hardly make
           // things worse... (famous last words)
  
           thisConnection.invalidate(false, error, "Error caught in ConnectionReadCompletedCallback.complete()");
  
           // Re-throw the error to ensure that it causes the maximum devastation.
           // The JVM is probably very ill if an Error is thrown so attempt no recovery.
           throw error;
        }
        catch(RuntimeException runtimeException)
        {
           FFDCFilter.processException
           (runtimeException, "com.ibm.ws.sib.jfapchannel.impl.ConnectionReadCompletedCallback", JFapChannelConstants.CONNREADCOMPCALLBACK_COMPLETE_02, thisConnection.getDiagnostics(true));
           if (TraceComponent.isAnyTracingEnabled() && tc.isEventEnabled()) SibTr.exception(this, tc, runtimeException);
  
           // We can reasonably try to recover from a runtime exception by invalidating the associated
           // connection.  This should drive the underlying TCP/IP socket to be closed.
           thisConnection.invalidate(false, runtimeException, "RuntimeException caught in ConnectionReadCompletedCallback.complete");
  
           // Don't throw the RuntimeException on as we risk blowing away part of the TCP channel.
        }
  
  		if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled()) SibTr.exit(this, tc, "complete");
  	}