/**
  * Update all the networks "routedNetworks" field by adding the routed networks list according to
  * the given transit network, including both "localNetworks" and "remoteRoutedNetworks".
  *
  * @param networkSystem
  * @param connectedNetworkSystems
  * @param allNetworks
  */
 private void updateRoutedNetworksForTransitNetwork(
     NetworkSystem networkSystem, Set<String> connectedNetworkSystems, List<Network> allNetworks) {
   // 1. Get localNetworks, remoteRoutedNetworks and routedNetworks. With transit network, both the
   // local
   // networks and the remote routed networks are routed.
   List<Network> localNetworks = getLocalNetworks(networkSystem, allNetworks);
   for (Network network : localNetworks) {
     dumpRoutedNetworks("localNetwork = ", network);
   }
   List<Network> remoteRoutedNetworks =
       this.getRemoteRoutedNetworks(
           networkSystem.getId().toString(), connectedNetworkSystems, allNetworks);
   for (Network network : remoteRoutedNetworks) {
     dumpRoutedNetworks("remoteRoutedNetworks = ", network);
   }
   List<Network> routedNetworks = new ArrayList<Network>(localNetworks);
   routedNetworks.addAll(remoteRoutedNetworks);
   for (Network network : routedNetworks) {
     dumpRoutedNetworks("routedNetworks = ", network);
   }
   // 2. Update each local network by setting the routed networks.
   for (Network currentNetwork : localNetworks) {
     boolean modified = false;
     StringSet networkSet = currentNetwork.getRoutedNetworks();
     _log.info("NetworkDiscoveryWorker handling routed network, existing: {}", networkSet);
     if (networkSet == null) {
       networkSet = new StringSet();
     }
     for (Network routedNetwork : routedNetworks) {
       if (!networkSet.contains(routedNetwork.getId().toString())
           && !routedNetwork.getId().equals(currentNetwork.getId())) {
         networkSet.add(routedNetwork.getId().toString());
         modified = true;
       }
     }
     _log.info("NetworkDiscoveryWorker handling routed network, updated: {}", networkSet);
     if (modified) {
       currentNetwork.setRoutedNetworks(networkSet);
       dumpRoutedNetworks("update network=", currentNetwork);
       dbClient.updateObject(currentNetwork);
     }
   }
 }
  /**
   * Looks in the topology view for endpoints that accessible by routing
   *
   * @param networkSystem the network system being refreshed
   * @param updatedNetworks the networks that require updating
   * @param routedEndpoints the routed endpoints map of Fabric-WWN-to-endpoints-WWN
   * @throws Exception
   */
  private void updateRoutedNetworks(
      NetworkSystem networkSystem,
      List<Network> updatedNetworks,
      Map<String, Set<String>> routedEndpoints)
      throws Exception {
    // for each network, get the list of routed ports and locate them in other networks
    StringSet routedNetworks = null;
    Network routedNetwork = null;

    // get the current networks from the database
    Map<URI, Network> allNetworks = DataObjectUtils.toMap(getCurrentTransportZones());
    for (Network network : updatedNetworks) {
      // if this network has any routed endpoints
      Set<String> netRoutedEndpoints = routedEndpoints.get(NetworkUtil.getNetworkWwn(network));
      if (netRoutedEndpoints == null || netRoutedEndpoints.isEmpty()) {
        _log.debug("No routed endpoint in network {}", network.getNativeGuid());
        network.setRoutedNetworks(null);
      } else {
        _log.info(
            "Found {} routed endpoint in network {}", netRoutedEndpoints, network.getNativeGuid());
        routedNetworks = new StringSet();
        for (String endpoint : netRoutedEndpoints) {
          // find the source network of the routed endpoint
          routedNetwork = findNetworkForDiscoveredEndPoint(allNetworks.values(), endpoint, network);
          if (routedNetwork != null) { // it is possible we did not discover the source
            routedNetworks.add(routedNetwork.getId().toString());
          }
        }
        network.setRoutedNetworks(routedNetworks);
      }
      dbClient.updateAndReindexObject(network);
      _log.info("Updated routed networks for {} to {}", network.getNativeGuid(), routedNetworks);
    }
    // clean up transit networks from any one-way associations.
    // Transit networks will show any endpoints routed thru them
    // which may cause one-way associations in the routedNetworks.
    // For example if network A has ep1 and B has ep2 and there is
    // a routed zone between A and B, the transit network C will
    // reports ep1 and ep2 but there is not actual routing between
    // C and A or C and B, so we want to remove these associations.
    for (URI id : allNetworks.keySet()) {
      Network net = allNetworks.get(id);
      boolean updated = false;
      if (net.getRoutedNetworks() != null) {
        routedNetworks = new StringSet(net.getRoutedNetworks());
        // for each network this network is pointing to
        for (String strUri : net.getRoutedNetworks()) {
          // get the opposite network
          Network opNet = allNetworks.get(URI.create(strUri));
          if (opNet != null // it is possible this network is getting removed - the next discovery
              // cleans up
              && opNet.getRoutedNetworks()
                  != null // check for null in case the other network routed eps are not yet visible
              && !opNet
                  .getRoutedNetworks()
                  .contains(net.getId().toString())) { // if the opposite network is not seeing this
            // one
            // remove this association because the opposite network is does not have the matching
            // association
            routedNetworks.remove(opNet.getId().toString());
            updated = true;
          }
        }
        if (updated) {
          _log.info("Reconciled routed networks for {} to {}", net.getNativeGuid(), routedNetworks);
          net.setRoutedNetworks(routedNetworks);
          dbClient.updateAndReindexObject(net);
        }
      }
    }
    for (Network network : allNetworks.values()) {
      NetworkAssociationHelper.setNetworkConnectedVirtualArrays(network, false, dbClient);
    }
    /*
     * COP-23266, COP-20698: Fix the problem that ViPR could not create IVR zone between VSANs routed by
     * transit VSAN(network), the "routedNetwork" field of "Network" data object should be updated based
     * on the transit network(s) if there is.
     */
    this.updateTransitRoutedNetworks(networkSystem);
  }