docs: @FFDCIgnore({ ChannelException.class, ChainException.class })
      public synchronized void update(String resolvedHostName) {
          if (TraceComponent.isAnyTracingEnabled() && tc.isEventEnabled()) {
              Tr.event(this, tc, "update chain " + this);
          }
  
          // Don't update or start the chain if it is disabled or the framework is stopping..
          if (!enabled || FrameworkState.isStopping())
              return;
  
          final ActiveConfiguration oldConfig = currentConfig;
  
          // The old configuration was "valid" if it existed, and if it was correctly configured
          final boolean validOldConfig = oldConfig == null ? false : oldConfig.validConfiguration;
  
          Map<String, Object> tcpOptions = owner.getTcpOptions();
          Map<String, Object> sslOptions = (isHttps) ? owner.getSslOptions() : null;
          Map<String, Object> httpOptions = owner.getHttpOptions();
          Map<String, Object> endpointOptions = owner.getEndpointOptions();
          Map<String, Object> remoteIpOptions = owner.getRemoteIpConfig();
  
  
          final ActiveConfiguration newConfig = new ActiveConfiguration(isHttps, tcpOptions, sslOptions, httpOptions, remoteIpOptions, endpointOptions, resolvedHostName);
  
          if (newConfig.configPort < 0 || !newConfig.complete()) {
              if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
                  Tr.debug(this, tc, "Stopping chain due to configuration " + newConfig);
              }
  
              // save the new/changed configuration before we start setting up the new chain
              currentConfig = newConfig;
  
              stop();
          } else {
              Map<Object, Object> chanProps;
  
              try {
                  boolean sameConfig = newConfig.unchanged(oldConfig);
                  if (validOldConfig) {
                      if (sameConfig) {
                          int state = chainState.get();
                          if (state == ChainState.STARTED.val) {
                              // If configurations are identical, see if the listening port is also the same
                              // which would indicate that the chain is running with the unchanged configuration
                              // toggle start/stop of chain if we are somehow active on a different port..
                              sameConfig = oldConfig.validateActivePort();
                              if (sameConfig) {
                                  if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
                                      Tr.debug(this, tc, "Configuration is unchanged, and chain is already started: " + oldConfig);
                                  }
                                  // EARLY EXIT: we have nothing else to do here: "new configuration" not saved
                                  return;
                              } else {
                                  if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
                                      Tr.debug(this, tc, "Configuration is unchanged, but chain is running with a mismatched configuration: " + oldConfig);
                                  }
                              }
                          } else if (state == ChainState.QUIESCED.val) {
                              // Chain is in the process of stopping.. we need to wait for it
                              // to finish stopping before we start it again
                              if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
                                  Tr.debug(this, tc, "Configuration is unchanged, chain is quiescing, wait for stop: " + newConfig);
                              }
                              stopWait.waitForStop(cfw.getDefaultChainQuiesceTimeout(), this); // BLOCK
                          } else {
                              if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
                                  Tr.debug(this, tc, "Configuration is unchanged, chain must be started: " + newConfig);
                              }
                          }
                      }
                  }
  
                  if (!sameConfig) {
                      // Note that one path in the above block can change the value of sameConfig:
                      // if the started chain is actually running on a different port than we expect,
                      // something strange happened, and the whole thing should be stopped and restarted.
                      // We come through this block for the stop/teardown...
  
                      if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
                          Tr.debug(this, tc, "New/changed chain configuration " + newConfig);
                      }
  
                      // We've been through channel configuration before...
                      // We have to destroy/rebuild the chains because the channels don't
                      // really support dynamic updates. *sigh*
                      ChainData cd = cfw.getChain(chainName);
                      if (cd != null) {
                          cfw.stopChain(cd, cfw.getDefaultChainQuiesceTimeout());
                          stopWait.waitForStop(cfw.getDefaultChainQuiesceTimeout(), this); // BLOCK
                          cfw.destroyChain(cd);
                          cfw.removeChain(cd);
                      }
                      // Remove any channels that have to be rebuilt..
                      if (newConfig.tcpChanged(oldConfig))
                          removeChannel(tcpName);
  
                      if (newConfig.sslChanged(oldConfig))
                          removeChannel(sslName);
  
                      if (newConfig.httpChanged(oldConfig))
                          removeChannel(httpName);
  
  
                      if (newConfig.endpointChanged(oldConfig))
                          removeChannel(dispatcherName);
                  }
  
                  // save the new/changed configuration before we start setting up the new chain
                  currentConfig = newConfig;
  
                  // Define and register an EndPoint to represent this chain
                  EndPointInfo ep = endpointMgr.defineEndPoint(endpointName, newConfig.configHost, newConfig.configPort);
  
                  // TCP Channel
                  ChannelData tcpChannel = cfw.getChannel(tcpName);
                  if (tcpChannel == null) {
                      String typeName = (String) tcpOptions.get("type");
                      chanProps = new HashMap<Object, Object>(tcpOptions);
                      chanProps.put("endPointName", endpointName);
                      chanProps.put("hostname", ep.getHost());
                      chanProps.put("port", String.valueOf(ep.getPort()));
  
                      tcpChannel = cfw.addChannel(tcpName, cfw.lookupFactory(typeName), chanProps);
                  }
  
                  // SSL Channel
                  if (isHttps) {
                      ChannelData sslChannel = cfw.getChannel(sslName);
                      if (sslChannel == null) {
                          chanProps = new HashMap<Object, Object>(sslOptions);
                          // Put the protocol version, which allows the http channel to dynamically
                          // know what http version it will use.
                          if (owner.getProtocolVersion() != null) {
                              chanProps.put(HttpConfigConstants.PROPNAME_PROTOCOL_VERSION, owner.getProtocolVersion());
                          }
                          sslChannel = cfw.addChannel(sslName, cfw.lookupFactory("SSLChannel"), chanProps);
                      }
                  }
  
                  // HTTP Channel
                  ChannelData httpChannel = cfw.getChannel(httpName);
                  if (httpChannel == null) {
                      chanProps = new HashMap<Object, Object>(httpOptions);
                      // Put the endpoint id, which allows us to find the registered access log
                      // dynamically
                      chanProps.put(HttpConfigConstants.PROPNAME_ACCESSLOG_ID, owner.getName());
                      // Put the protocol version, which allows the http channel to dynamically
                      // know what http version it will use.
                      if (owner.getProtocolVersion() != null) {
                          chanProps.put(HttpConfigConstants.PROPNAME_PROTOCOL_VERSION, owner.getProtocolVersion());
                      }
                      if(remoteIpOptions.get("id").equals("defaultRemoteIp")){
                          //Put the internal remoteIp set to false since the element was not configured to be used
                          chanProps.put(HttpConfigConstants.PROPNAME_REMOTE_IP, "false");
                          chanProps.put(HttpConfigConstants.PROPNAME_REMOTE_PROXIES, null);
                          chanProps.put(HttpConfigConstants.PROPNAME_REMOTE_IP_ACCESS_LOG, null);
                      }
                      else{
                          chanProps.put(HttpConfigConstants.PROPNAME_REMOTE_IP, "true");
                          //Check if the remoteIp is configured to use the remoteIp in the access log or if
                          //a custom proxy regex was provided
                          if(remoteIpOptions.containsKey("proxies")){
                              chanProps.put(HttpConfigConstants.PROPNAME_REMOTE_PROXIES, remoteIpOptions.get("proxies"));
                          }
                          if(remoteIpOptions.containsKey("useRemoteIpInAccessLog")){
                              chanProps.put(HttpConfigConstants.PROPNAME_REMOTE_IP_ACCESS_LOG, remoteIpOptions.get("useRemoteIpInAccessLog"));
                          }
                      }
  
  
  
  
                      httpChannel = cfw.addChannel(httpName, cfw.lookupFactory("HTTPInboundChannel"), chanProps);
                  }
  
                  // HTTPDispatcher Channel
                  ChannelData httpDispatcher = cfw.getChannel(dispatcherName);
                  if (httpDispatcher == null) {
                      chanProps = new HashMap<Object, Object>();
                      chanProps.put(HttpDispatcherConfig.PROP_ENDPOINT, owner.getPid());
  
                      httpDispatcher = cfw.addChannel(dispatcherName, cfw.lookupFactory("HTTPDispatcherChannel"), chanProps);
                  }
  
                  // Add chain
                  ChainData cd = cfw.getChain(chainName);
                  if (null == cd) {
                      final String[] chanList;
                      if (isHttps)
                          chanList = new String[] { tcpName, sslName, httpName, dispatcherName };
                      else
                          chanList = new String[] { tcpName, httpName, dispatcherName };
  
                      cd = cfw.addChain(chainName, FlowType.INBOUND, chanList);
                      cd.setEnabled(enabled);
                      cfw.addChainEventListener(this, chainName);
  
                      // initialize the chain: this will find/create the channels in the chain,
                      // initialize each channel, and create the chain. If there are issues with any
                      // channel properties, they will surface here
                      // THIS INCLUDES ATTEMPTING TO BIND TO THE PORT
                      cfw.initChain(chainName);
                  }
  
                  // We configured the chain successfully
                  newConfig.validConfiguration = true;
              } catch (ChannelException e) {
                  handleStartupError(e, newConfig); // FFDCIgnore: CFW will have logged and FFDCd already
              } catch (ChainException e) {
                  handleStartupError(e, newConfig); // FFDCIgnore: CFW will have logged and FFDCd already
              } catch (Exception e) {
                  // The exception stack for this is all internals and does not belong in messages.log.
                  Tr.error(tc, "config.httpChain.error", tcpName, e.toString());
                  handleStartupError(e, newConfig);
              }
  
              if (newConfig.validConfiguration) {
                  try {
                      // Start the chain: follow along to chainStarted method (CFW callback)
                      cfw.startChain(chainName);
                  } catch (ChannelException e) {
                      handleStartupError(e, newConfig); // FFDCIgnore: CFW will have logged and FFDCd already
                  } catch (ChainException e) {
                      handleStartupError(e, newConfig); // FFDCIgnore: CFW will have logged and FFDCd already
                  } catch (Exception e) {
                      // The exception stack for this is all internals and does not belong in messages.log.
                      Tr.error(tc, "start.httpChain.error", tcpName, e.toString());
                      handleStartupError(e, newConfig);
                  }
              }
          }
      }