docs: private synchronized void destroyChannelInChain(Channel targetChannel, Chain chain, ChannelData channelData) throws ChannelException, ChainException {
          if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled()) {
              Tr.entry(tc, "destroyChannelInChain");
          }
          // No need to check parameters since this is called from internal only.
          String channelName = targetChannel.getName();
          if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
              Tr.debug(tc, "channelName=" + channelName + " chainName=" + chain.getName());
          }
          ChannelContainer channelContainer = channelRunningMap.get(channelName);
          // No need to check returned channelContainer since this is called from
          // internal only.
          Channel channel = channelContainer.getChannel();
          Map<String, Chain> chainMap = channelContainer.getChainMap();
          RuntimeState channelState = channelContainer.getState();
          if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
              Tr.debug(tc, "Remove chain reference for channel, " + channelName);
          }
          channelContainer.removeChainReference(chain.getName());
          int numChains = chainMap.size();
          if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
              Tr.debug(tc, "Remaining chain refs, " + numChains);
          }
  
          // The only way to destroy a channel is if no other chains reference it at
          // all.
          if (numChains == 0) {
              if (RuntimeState.INITIALIZED != channelState) {
                  if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
                      Tr.debug(tc, "Skip channel destroy, not in correct state, state=" + channelState.ordinal);
                  }
              } else {
                  if (chain.getChainData().getType().equals(FlowType.INBOUND)) {
                      // Disable the channel from handling any more connections in the
                      // chain.
                      if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
                          Tr.debug(tc, "Disabling channel, " + channel.getName());
                      }
                      ((InboundChain) chain).disableChannel(channel);
                  }
                  // Destroy the channel itself.
                  try {
                      channel.destroy();
                  } catch (ChannelException ce) {
                      if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
                          Tr.debug(tc, "Channel " + channel + " threw ChannelException " + ce.getMessage());
                      }
                      throw ce;
                  } catch (Throwable e) {
                      FFDCFilter.processException(e, getClass().getName() + ".destroyChannelInChain", "1408", this, new Object[] { channel });
                      if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
                          Tr.debug(tc, "Channel " + channel + " threw non-ChannelException " + e.getMessage());
                      }
                      throw new ChannelException(e);
                  }
                  // Remove the channel from the framework runtime. Opposite of init.
                  this.channelRunningMap.remove(channelName);
                  // Remove reference to child in parent channel data object.
                  ChildChannelDataImpl child = (ChildChannelDataImpl) channelData;
                  child.getParent().removeChild(child);
                  // Get running channels with this type
                  ChainData[] rChains = getRunningChains(channelData.getFactoryType());
                  if (rChains == null || rChains.length == 0 || rChains[0] == null || (rChains.length == 1 && rChains[0].getName().equals(chain.getChainData().getName()))) {
                      // remove the ChannelFactory if it is no longer in use.
                      ChannelFactoryDataImpl cfd = channelFactories.remove(channelData.getFactoryType());
                      ChannelFactory factory = cfd.getChannelFactory();
                      cfd.setChannelFactory(null);
                      if (factory != null) {
                          try {
                              factory.destroy();
                          } catch (Throwable e) {
                              FFDCFilter.processException(e, getClass().getName() + ".destroyChannelInChain", "1450", this, new Object[] { factory });
                              if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
                                  Tr.debug(tc, "Factory " + factory + " threw non-ChannelFactoryException " + e.getMessage());
                              }
                              // no throwing this up being that we don't care about this case
                              // anymore
                          }
                      }
  
                  }
              }
          } else if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
              Tr.debug(tc, "Skip channel destroy, in use by other chain(s)");
          }
          if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled()) {
              Tr.exit(tc, "destroyChannelInChain");
          }
      }