docs: private synchronized VirtualConnectionFactory getOutboundVCFactory(List<OutboundChannelDefinition> channelDefs) throws ChannelFrameworkException {
  
          if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
              Tr.entry(tc, "getOutboundVCFactory");
  
          ChainDataImpl chainData = null;
          boolean found = false;
          int hashKey = 0;
  
          // Build a hash key based on names of channel factories.
          for (OutboundChannelDefinition def : channelDefs) {
              hashKey += def.getOutboundFactory().hashCode();
          }
  
          // See if the key already exists in the current set of outbound chains.
          OutboundVirtualConnectionFactoryImpl vcf = null;
          Iterator<OutboundVirtualConnectionFactoryImpl> vcfs = this.outboundVCFactories.values().iterator();
          while (vcfs.hasNext()) {
              vcf = vcfs.next();
              chainData = (ChainDataImpl) vcf.getChain().getChainData();
              if (hashKey == chainData.getChannelFactoryHash()) {
                  if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
                      Tr.debug(tc, "Found matching hash keys");
                  }
                  // Handle tiny case where two chains hash to same value.
                  // Verify the channel factories, factory props, and channel
                  // props are the same.
                  ChannelData channelDataList[] = chainData.getChannelList();
                  if (channelDataList.length == channelDefs.size()) {
                      if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
                          Tr.debug(tc, "Found matching number of channels");
                      }
                      // Assume a match.
                      found = true;
                      ChannelData existingDef;
                      ChannelFactoryData existingFactoryData;
                      OutboundChannelDefinition inputDef;
                      // Loop through all the channels in the chain data.
                      for (int i = 0; i < channelDataList.length; i++) {
                          // Extract the current/existing channel def.
                          existingDef = channelDataList[i];
                          existingFactoryData = getChannelFactory(existingDef.getFactoryType());
                          // Extract the new channel def.
                          inputDef = channelDefs.get(i);
                          // Compare the existing and new channel defs.
                          if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
                              Tr.debug(tc, "Comparing existing def " + existingDef.getFactoryType() + "to new def " + inputDef.getOutboundFactory());
                          }
                          boolean sameFactoryType = (existingDef.getFactoryType() == inputDef.getOutboundFactory());
                          boolean sameChannelProps = propertiesIncluded(inputDef.getOutboundChannelProperties(), existingDef.getPropertyBag());
                          boolean sameFactoryProps = propertiesIncluded(inputDef.getOutboundFactoryProperties(), existingFactoryData.getProperties());
  
                          if (!sameFactoryType || !sameChannelProps || !sameFactoryProps) {
                              // Found a mismatch.
                              if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
                                  Tr.debug(tc, "Keys matched, but factories didn't");
                              }
                              found = false;
                              // Break out of this inner loop.
                              break;
                          }
                      }
                      if (found) {
                          // Break out of outer loop.
                          break;
                      }
                  }
              }
          } // factory loop
  
          if (!found) {
              // Couldn't find a match. Need to create a one.
              if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
                  Tr.debug(tc, "No existing VCF, create one.");
              }
              // We may be able to reuse existing chain or channel data objects.
              // However, the hit in searching probably isn't worth it.
              // For now, create them all from scratch.
              String channelNameList[] = new String[channelDefs.size()];
              String channelName = null;
              int i = 0;
              for (OutboundChannelDefinition def : channelDefs) {
                  channelName = "channel_" + channelNameCounter.getAndIncrement();
                  channelNameList[i++] = channelName;
                  addChannel(channelName, def.getOutboundFactory(), def.getOutboundChannelProperties());
              }
              String chainName = "chain_" + chainNameCounter.getAndIncrement();
              addChain(chainName, FlowType.OUTBOUND, channelNameList);
              vcf = (OutboundVirtualConnectionFactoryImpl) getOutboundVCFactory(chainName);
          } else if (null != vcf) {
              vcf.incrementRefCount();
              if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
                  Tr.debug(tc, "Found an existing vcf " + vcf.hashCode());
              }
          }
  
          if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled()) {
              Tr.exit(tc, "getOutboundVCFactory");
          }
          return vcf;
      }