docs: @Override
      public void close() throws SIResourceException, SINotPossibleInCurrentConfigurationException
      {
          if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
              SibTr.entry(tc, "close", this);
  
          // On closing, we need to run the async consumer a final time to process
          // any messages it has attached.
          //
          // We need to take the async consumer lock so we don't step on a currently
          // running consumer (so that running asyncs can complete with all their
          // resources available - i.e. without object closed exceptions - as per the
          // JMS 1.1 spec).
          //
          // Taking this lock also prevents other invocations of close which take
          // place before this invocation has completed from proceeding (as per the
          // JMS 1.1 spec).
          //
          // We also taken the consumer session lock for most of the method.  In
          // theory, we could release this lock while running the async consumer,
          // but this makes things a little more complicated and there seems little
          // point when we're closing down anyway.
          //
          // The async consumer could concievably spin forever and prevent the close.
          // This is an accepted fact.
  
          // We need to get any asynch thread to stop looping round the queue to
          // allow us to have a chance of closing this consumer. We have to do this outside
          // of the asynch lock as that will be held by the other thread at this time.
          _interruptConsumer = true;
  
          synchronized (_asynchConsumerBusyLock)
          {
              if (_closed || _closing)
              {
                  if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
                      SibTr.exit(tc, "close", "Already Closed");
                  return;
              }
  
              _lockRequested = true;
  
              // Lock the KeyGroup if we have one before we lock this consumer
              if (_keyGroup != null)
                  _keyGroup.lock();
  
              try
              {
                  this.lock();
                  try
                  {
                      _lockRequested = false;
  
                      _consumerKey.stop();
  
                      // We don't want new messages to be attached if we're closing.
                      unsetReady();
  
                      // We need to release the LCP lock while we process attached messages
                      // but first we mark the consumer as closing to stop other calls succeeding
                      _closing = true;
                  } finally
                  {
                      this.unlock();
                  }
              } finally
              {
                  if (_keyGroup != null)
                      _keyGroup.unlock();
              }
  
              // Process any attached messages already on the async consumer.
              if (_asynchConsumerRegistered)
              {
                  // If we reach here and an async consumer is running, close() must
                  // have been called from the async consumer callback as we have been
                  // able to acquire the asynchConsumer lock.
                  //
                  // Therefore, do not erroneously recursively invoke the callback.
                  if (!_asynchConsumer.isAsynchConsumerRunning())
                  {
                      try
                      {
                          processAttachedMsgs();
                      } catch (SISessionDroppedException e)
                      {
                          //No FFDC code needed
                          //essentially the session is already closed but we'll try to carry
                          //cleaning up
                      }
                  }
  
                  // If we are a member of an ordering group then we need to leave it
                  // before we close
                  if (_keyGroup != null)
                  {
                      _consumerKey.leaveKeyGroup();
                      _keyGroup = null;
                  }
              }
  
              //Now take the lock back and unlock any locked messages and kick out
              // any waiting receiver
              this.lock();
              try
              {
                  synchronized (_allLockedMessages)
                  {
                      try
                      {
                          // Unlock any remaining locked messages
                          _allLockedMessages.unlockAll();
                      } catch (SIMPMessageNotLockedException e)
                      {
                          // No FFDC code needed
                          // This exception has occurred beause someone has deleted the
                          // message(s). Ignore this exception as it is unlocked anyway
                      } catch (SISessionDroppedException e)
                      {
                          //No FFDC code needed
                          //essentially the session is already closed but we'll try to carry
                          //cleaning up
                      }
  
                      // Mark this consumer session (point) as closed
                      _closed = true;
                  }
  
                  // If we have a synchronous receive we need to wake it up
                  if (_waiting)
                  {
                      _waiter.signal();
                  }
              } // synchronized(this)
              finally
              {
                  this.unlock();
              }
  
              _interruptConsumer = false;
  
              // If we've managed to interupt another thread that's currently checking for messages
              // to give to a consumer (runAsynchConsumer) then we need to wait until they realise
              // that we've interupted them before we return. Otherwise we'll have a dangling thread
              // that's technically 'working', even though the consumer is closed
              if (_runningAsynchConsumer && !_asynchConsumer.isAsynchConsumerRunning())
              {
                  _runAsynchConsumerInterupted = true;
                  try
                  {
                      if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled())
                          SibTr.debug(this, tc, "Waiting for runAsynchConsumer to complete");
  
                      _asynchConsumerBusyLock.wait();
                  } catch (InterruptedException e)
                  {
                      // No FFDC code needed
                  }
              }
          } // synchronized(asynch)
  
          // Now we no longer hold a lock, unlock any messages we happen
          // to have hidden for this consumer (SIB0115)
          unlockAllHiddenMessages();
  
          //detach from the CD - we CANNOT hold any consumer locks at this point!
          _consumerKey.detach();
  
          if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
              SibTr.exit(tc, "close");
      }