docs: @Override
      public void close(VirtualConnection inVC, Exception e) {
  
          // This H2InboundLink.close method should only get called from the H2HttpInboundLinkWrap.close method.
          // for this reason, if we sync this method, then if a stream changes state while we are looking at it, we should
          // be able to do the close when that stream closing causes this close method to be called.
  
          // the device link close should always use the initial VC that this object was created with, so inVC will be ignored.
  
          synchronized (linkStatusSync) {
  
              if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
                  Tr.debug(tc, "close(vc,e): :linkstatus: is: " + linkStatus + " :close: H2InboundLink hc: " + this.hashCode());
              }
  
              if ((linkStatus == LINK_STATUS.CLOSING) || (linkStatus == LINK_STATUS.GOAWAY_SENDING)
                  || (linkStatus == LINK_STATUS.WAIT_TO_SEND_GOAWAY)) {
                  // another thread is in charge of closing, or another thread has already armed the future to close
                  if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
                      Tr.debug(tc, "close(vc,e): returning: close of muxLink is being done on a differnt thread" + " :close: H2InboundLink hc: " + this.hashCode());
                  }
                  return;
              }
  
              if (e == null) {
                  // Attempt to close down cleanly if all streams are closed.
  
                  //Determine if all streams are in half closed or closed state
                  //If not, do nothing and return
                  //If so, look to see if the GoAway frame has been sent
                  //If not, trigger a timer and wait to send the GOAWAY frame
                  //If so, call close on the TCP-Channel/Device-Channel below us
  
                  H2StreamProcessor stream;
                  for (Integer i : streamTable.keySet()) {
                      stream = streamTable.get(i);
  
                      if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
                          Tr.debug(tc, "close(vc,e): looking at stream: " + stream.getId());
                      }
  
                      if (stream.getId() != 0 && !stream.isHalfClosed() && !stream.isStreamClosed() && highestLocalStreamId > -1) {
                          continue;
                      } else {
                          if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
                              Tr.debug(tc, "close(vc,e): stream not ready to close: " + stream.getId() + " :close: H2InboundLink hc: " + this.hashCode());
                          }
                          return;
                      }
                  }
              }
  
              // All streams are either closed or in half closed, and a GOAWAY frame needs to be sent
              // Wait the timeout time and then send the GOAWAY frame with the last good stream
  
              linkStatus = LINK_STATUS.WAIT_TO_SEND_GOAWAY;
              if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
                  Tr.debug(tc, "close(vc,e): loading up the wait to close timeout" + " :close: H2InboundLink hc: " + this.hashCode());
              }
  
              ScheduledExecutorService scheduler = CHFWBundle.getScheduledExecutorService();
              if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
                  Tr.debug(tc, "close : scheduler : " + scheduler + " config : " + config);
              }
              connTimeout = new H2ConnectionTimeout(e);
  
              if (e == null) {
                  // close cleanly if no other traffic has been received for this H2 connection within the timeout
                  // Save the future so we can cancel it later on
                  closeFuture = scheduler.schedule(connTimeout, config.getH2ConnCloseTimeout(), TimeUnit.SECONDS);
              } else {
                  if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
                      Tr.debug(tc, "close(vc,e): close on link called with exception: " + e);
                  }
                  // do the close immediately on this thread
                  connTimeout.run();
              }
          }
      }