docs: private void quiesceListeners(Collection<ServiceReference<ServerQuiesceListener>> listenerRefs) {
          // Make a copy of existing notifications: we can't hold the lock around notifications
          // to iterate while waiting for the existing notifications to complete because that would
          // lock-out cleanupNotifications.
          final Map<String, RuntimeUpdateNotification> existingNotifications = new HashMap<String, RuntimeUpdateNotification>();
          synchronized (notifications) {
              existingNotifications.putAll(notifications);
          }
  
          if (listenerRefs.isEmpty() && existingNotifications.isEmpty())
              return;
  
          if (isServer())
              Tr.audit(tc, "quiesce.begin");
          else
              Tr.audit(tc, "client.quiesce.begin");
  
          // If there are RuntimeUpdateNotifications outstanding, submit a thread to wait on them
          if (!existingNotifications.isEmpty()) {
              executorService.execute(new Runnable() {
                  @Override
                  public void run() {
                      try {
                          for (RuntimeUpdateNotification notification : existingNotifications.values()) {
                              if (!notification.ignoreOnQuiesce())
                                  notification.waitForCompletion();
                          }
                      } catch (Throwable t) {
                          // Auto-FFDC here..
                      }
                  }
              });
          }
  
          // Queue the notification of each listener (unbounded queue)
          final ConcurrentLinkedQueue<ServerQuiesceListener> listeners = new ConcurrentLinkedQueue<ServerQuiesceListener>();
          for (ServiceReference<ServerQuiesceListener> ref : listenerRefs) {
              final ServerQuiesceListener listener = bundleCtx.getService(ref);
              if (listener != null) {
  
                  executorService.execute(new Runnable() {
                      @Override
                      public void run() {
                          try {
                              listeners.add(listener);
                              if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
                                  Tr.debug(tc, "Invoking serverStopping() on listener: " + listener);
                              }
                              listener.serverStopping();
                              if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
                                  Tr.debug(tc, "serverStopping() method completed on listener: " + listener);
                              }
  
                          } catch (Throwable t) {
                              // Auto-FFDC here..
                          } finally {
                              listeners.remove(listener);
                          }
                      }
                  });
  
              }
          }
  
          if (tc.isDebugEnabled())
              Tr.debug(tc, "About to begin quiesce of executor service threads.");
  
          // Notify the executor service that we are quiescing
          ThreadQuiesce tq = (ThreadQuiesce) executorService;
          if (tq.quiesceThreads()) {
              if (isServer())
                  Tr.info(tc, "quiesce.end");
              else
                  Tr.info(tc, "client.quiesce.end");
          } else {
  
              if (tc.isDebugEnabled()) {
                  // If debug is enabled we will dump threads so that we can determine what was still running
                  libertyProcess.createJavaDump(Collections.singleton("thread"));
              }
  
              int count = tq.getActiveThreads();
  
              // we timed out - we now have to stop waiting for existing notifications to finish...
              // we set the normal stop to false and issue the timeout warning after the diagnostics to
              // ensure that we have valid diagnostics (to avoid situations where the long running threads
              // finish right after we issue the warning - then we wouldn't see them in the diagnostics).
              normalServerStop.set(false);
              Tr.warning(tc, "quiece.warning");
  
              int notificationCount = 0;
  
              for (RuntimeUpdateNotification notification : existingNotifications.values()) {
                  if (!!!notification.isDone()) {
                      notificationCount++;
                      if (tc.isDebugEnabled()) {
                          Tr.debug(tc, "Notification did not complete during quiesce: ", notification.getName());
                      }
                  }
              }
              if (notificationCount > 0) {
                  Tr.warning(tc, "notifications.not.complete", notificationCount);
              }
  
              if (listeners.size() > 0) {
                  Tr.warning(tc, "quiesce.listeners.not.complete", listeners.size());
              }
  
              if (tc.isDebugEnabled()) {
                  for (ServerQuiesceListener sql : listeners) {
                      Tr.debug(tc, "Quiesce listener did not complete during quiesce: ", sql.getClass().getName());
                  }
              }
  
              count = count - notificationCount - listeners.size();
              if (count > 0) {
                  Tr.warning(tc, "quiesce.waiting.on.threads", count);
              }
          }
  
      }