protected void updatePredecessorsFor(Host host) {
    NetID pre = getOverlayPredecessor(host);
    EdgeHandle old_pre = predecessors.get(host);
    // log.debug("PREDECESSORS: " + pre + "|" + ((old_pre !=
    // null)?old_pre.getTo():"null"));

    if (pre == null) {
      if (old_pre != null) {
        old_pre.remove();
      }
    } else if (old_pre == null || !pre.equals(old_pre.getTo())) {
      if (old_pre != null) {
        old_pre.remove();
      }
      EdgeHandle newEdge = this.addEdge(netID(host), pre, Color.CYAN, "predecessor");
      predecessors.put(host, newEdge);
    }
  }
  @Override
  protected void refreshFingertable(Host fromNode) {
    AbstractChordRoutingTable crt =
        ((AbstractChordNode) fromNode.getOverlay(AbstractChordNode.class)).getChordRoutingTable();
    if (crt == null) {
      return;
    }
    AbstractChordContact[] ft = crt.copyFingerTable();
    LinkedHashSet<AbstractChordContact> ft_set =
        new LinkedHashSet<AbstractChordContact>(Arrays.asList(ft));
    if (ft_set.contains(null)) {
      ft_set.remove(null);
    }

    if (ft != null) {

      Map<NetID, EdgeHandle> edgeHandles = fingerEdges.get(netID(fromNode));
      if (edgeHandles == null) {
        edgeHandles = new LinkedHashMap<NetID, EdgeHandle>();
        fingerEdges.put(netID(fromNode), edgeHandles);
      }

      Set<NetID> vis_ft = fingertables.get(netID(fromNode));
      if (vis_ft == null) {
        vis_ft = new LinkedHashSet<NetID>();
        fingertables.put(netID(fromNode), vis_ft);
      }
      boolean ft_changed = false;
      // add new edges
      for (AbstractChordContact con : ft_set) {
        NetID newNetID = con.getTransInfo().getNetId();
        if (con != null && !vis_ft.contains(newNetID)) {
          EdgeHandle h = this.addEdge(netID(fromNode), newNetID, Color.LIGHT_GRAY, "finger");
          edgeHandles.put(newNetID, h);
          vis_ft.add(newNetID);
          ft_changed = true;
        }
      }
      // remove unused edges:
      if (vis_ft != null) {
        for (NetID nId : vis_ft) {
          boolean inUse = false;
          for (AbstractChordContact con : ft_set) {
            if (con.getTransInfo().getNetId().toString().equals(nId.toString())) {
              inUse = true;
              break;
            }
          }
          if (!inUse && edgeHandles.containsKey(nId)) {
            // remove edge.
            edgeHandles.get(nId).remove();
            edgeHandles.remove(nId);
          }
        }
      }
      if (ft_changed) {
        this.getTranslator()
            .nodeAttributeChanged(fromNode.getNetLayer().getNetID(), "ft_hosts", ft_set.size());
      }
    }
  }