docs: private void buildChannel() {
        FileLookup fileLookup = FileLookupFactory.newInstance();
  
        // in order of preference - we first look for an external JGroups file, then a set of XML
        // properties, and
        // finally the legacy JGroups String properties.
        String cfg;
        if (props != null) {
           if (props.containsKey(CHANNEL_LOOKUP)) {
              String channelLookupClassName = props.getProperty(CHANNEL_LOOKUP);
  
              try {
                 JGroupsChannelLookup lookup = Util.getInstance(channelLookupClassName, configuration.classLoader());
                 channel = lookup.getJGroupsChannel(props);
                 connectChannel = lookup.shouldConnect();
                 disconnectChannel = lookup.shouldDisconnect();
                 closeChannel = lookup.shouldClose();
              } catch (ClassCastException e) {
                 log.wrongTypeForJGroupsChannelLookup(channelLookupClassName, e);
                 throw new CacheException(e);
              } catch (Exception e) {
                 log.errorInstantiatingJGroupsChannelLookup(channelLookupClassName, e);
                 throw new CacheException(e);
              }
           }
  
           if (channel == null && props.containsKey(CHANNEL_CONFIGURATOR)) {
              JGroupsChannelConfigurator configurator = (JGroupsChannelConfigurator) props.get(CHANNEL_CONFIGURATOR);
              try {
                 channel = configurator.createChannel();
              } catch (Exception e) {
                 throw log.errorCreatingChannelFromConfigurator(configurator.getProtocolStackString(), e);
              }
           }
  
           if (channel == null && props.containsKey(CONFIGURATION_FILE)) {
              cfg = props.getProperty(CONFIGURATION_FILE);
              Collection<URL> confs = Collections.emptyList();
              try {
                 confs = fileLookup.lookupFileLocations(cfg, configuration.classLoader());
              } catch (IOException io) {
                 //ignore, we check confs later for various states
              }
              if (confs.isEmpty()) {
                 throw log.jgroupsConfigurationNotFound(cfg);
              } else if (confs.size() > 1) {
                 log.ambiguousConfigurationFiles(Util.toStr(confs));
              }
              try {
                 channel = new JChannel(confs.iterator().next());
              } catch (Exception e) {
                 throw log.errorCreatingChannelFromConfigFile(cfg, e);
              }
           }
  
           if (channel == null && props.containsKey(CONFIGURATION_XML)) {
              cfg = props.getProperty(CONFIGURATION_XML);
              try {
                 channel = new JChannel(XmlConfigHelper.stringToElement(cfg));
              } catch (Exception e) {
                 throw log.errorCreatingChannelFromXML(cfg, e);
              }
           }
  
           if (channel == null && props.containsKey(CONFIGURATION_STRING)) {
              cfg = props.getProperty(CONFIGURATION_STRING);
              try {
                 channel = new JChannel(new ByteArrayInputStream(cfg.getBytes()));
              } catch (Exception e) {
                 throw log.errorCreatingChannelFromConfigString(cfg, e);
              }
           }
        }
  
        if (channel == null) {
           log.unableToUseJGroupsPropertiesProvided(props);
           try {
              channel = new JChannel(
                    fileLookup.lookupFileLocation(DEFAULT_JGROUPS_CONFIGURATION_FILE, configuration.classLoader()));
           } catch (Exception e) {
              throw log.errorCreatingChannelFromConfigFile(DEFAULT_JGROUPS_CONFIGURATION_FILE, e);
           }
        }
     }