// add collection elements
  private void processDomainVmElements(Resource vm, OntModel om, OrcaNode parent) {

    // HACK - if we added real interfaces to inner nodes, we don't need link to parent
    boolean innerNodeConnected = false;

    for (StmtIterator vmEl = vm.listProperties(NdlCommons.collectionElementProperty);
        vmEl.hasNext(); ) {
      Resource tmpR = vmEl.next().getResource();
      OrcaNode on = new OrcaNode(getTrueName(tmpR), parent, true);
      nodes.put(getTrueName(tmpR), on);
      pg.addNodeLater(on);
      OrcaLink ol = new OrcaLink("Unnamed");

      // link to parent (a visual HACK)
      links.put(ol.getName(), ol);

      pg.addEdgeLater(on, parent, null, ol);
      // add various properties
      setCommonNodeProperties(on, tmpR);

      // process interfaces. if there is an interface that leads to
      // a link, this is an intra-domain case, so we can delete the parent later
      for (Resource intR : NdlCommons.getResourceInterfaces(tmpR)) {
        // interfaceToNode.put(getTrueName(intR), on);
        addNodeToInterface(getTrueName(intR), on);
        // HACK: for now check that this interface connects to something
        // and is not just hanging there with IP address
        List<Resource> hasI = NdlCommons.getWhoHasInterface(intR, om);
        if (hasI.size() > 1) innerNodeConnected = true;
      }
    }

    // Hack - remove parent if nodes are linked between themselves
    if (innerNodeConnected) pg.removeNode(parent);
  }
  @Override
  public void ndlNetworkConnectionPath(
      Resource c, OntModel m, List<List<Resource>> paths, List<Resource> roots) {

    // ignore request items
    // if (requestPhase)
    //	return;

    // logger.debug("Network Connection Path: " + c);
    if (roots != null) {
      // logger.debug("Printing roots");
      for (Resource rr : roots) {
        // logger.debug(rr.toString());
      }
    }
    if (paths != null) {
      // logger.debug("Printing paths");
      for (List<Resource> p : paths) {
        StringBuilder sb = new StringBuilder();
        sb.append("   Path: ");
        for (Resource r : p) {
          sb.append(r + " ");
        }
        // logger.debug(sb.toString());

        Iterator<Resource> pIter = p.iterator();

        Resource first = pIter.next();
        if (first == null) continue;
        while (pIter.hasNext()) {
          // only take nodes, skip links on the path
          pIter.next();
          if (!pIter.hasNext()) break;
          Resource second = pIter.next();
          OrcaNode firstNode = nodes.get(getTrueName(first));
          OrcaNode secondNode = nodes.get(getTrueName(second));
          if ((firstNode == null) || (secondNode == null)) {
            break;
          }

          // logger.debug("  Adding p-to-p link");
          OrcaLink ol = new OrcaLink("Unnamed");

          // logger.debug("  Creating a link " + ol.getName() + " from " + first + " to " + second);
          pg.addEdgeLater(firstNode, secondNode, null, ol);
          first = second;
        }
      }

    } else
      // logger.debug("   None");
      assert true;
  }
  @Override
  public void ndlInterface(
      Resource intf, OntModel om, Resource conn, Resource node, String ip, String mask) {

    // ignore request items
    // if (requestPhase)
    //	return;

    // System.out.println("Interface " + l + " has IP/netmask" + ip + "/" + mask);
    // logger.debug("Interface " + intf + " between " + node + " and " + conn + " has IP/netmask " +
    // ip + "/" + mask);

    if (intf == null) return;
    OrcaNode on = null;
    OrcaLink ol = null;
    OrcaCrossconnect crs = null;
    if (node != null) on = nodes.get(getTrueName(node));

    if (conn != null) {
      ol = links.get(getTrueName(conn));
      if (ol == null)
        // maybe it is a crossconnect and not a link connection
        crs = (OrcaCrossconnect) nodes.get(getTrueName(conn));
    }

    // extract the IP address from label, if it is not set on
    // the interface in the request (basically we favor manifest
    // setting over the request because in node groups that's the
    // correct one)
    String nmInt = null;
    if (ip == null) {
      String ifIpLabel = NdlCommons.getLabelID(intf);
      // x.y.z.w/24
      if (ifIpLabel != null) {
        String[] ipnm = ifIpLabel.split("/");
        if (ipnm.length == 2) {
          ip = ipnm[0];
          nmInt = ipnm[1];
        }
      }
    } else {
      if (mask != null) nmInt = "" + RequestSaver.netmaskStringToInt(mask);
    }

    // check mirrored storage interfaces
    if ((ip == null) && (sharedStorageLinkInterfaceEquivalence.containsKey(intf))) {
      String ifIpLabel = NdlCommons.getLabelID(sharedStorageLinkInterfaceEquivalence.get(intf));
      // x.y.z.w/24
      if (ifIpLabel != null) {
        String[] ipnm = ifIpLabel.split("/");
        if (ipnm.length == 2) {
          ip = ipnm[0];
          nmInt = ipnm[1];
        }
      }
    }

    if (on != null) {
      if (ol != null) {
        on.setIp(ol, ip, nmInt);
        on.setInterfaceName(ol, getTrueName(intf));
        on.setMac(ol, NdlCommons.getAddressMAC(intf));
      } else if (crs != null) {
        // for individual nodes
        // create link from node to crossconnect and assign IP if it doesn't exist

        // check if the nodes are listed in the map

        if (interfaceToNode.get(getTrueName(intf)) != null) {
          // logger.debug("  Creating a link  from " + on + " to " + crs);
          ol = new OrcaLink("Unnamed");
          pg.addEdgeLater(on, crs, null, ol);
        } else {
          // logger.debug("  Skipping a link from " + on + " to " + crs + " as interface isn't
          // remembered");
        }
        on.setIp(ol, ip, nmInt);
        on.setInterfaceName(ol, getTrueName(intf));
        on.setMac(ol, NdlCommons.getAddressMAC(intf));
      } else {
        // this could be a disconnected node group
        if (on instanceof OrcaNodeGroup) {
          OrcaNodeGroup ong = (OrcaNodeGroup) on;
          ong.setInternalIp(ip, "" + RequestSaver.netmaskStringToInt(mask));
        }
      }
    }
  }
  @Override
  public void ndlLinkConnection(
      Resource l, OntModel m, List<Resource> interfaces, Resource parent) {
    // System.out.println("Found link connection " + l + " connecting " + interfaces);
    assert (l != null);

    // ignore request items
    // if (requestPhase)
    //	return;

    // logger.debug("Link Connection: " + l + " with interfaces " + interfaces);

    // ignore links that are part of network connections
    if (parent != null) {
      // logger.debug("    ignoring due to parent " + parent);
      return;
    }

    Iterator<Resource> it = interfaces.iterator();

    String label = NdlCommons.getResourceLabel(l);

    // limit to link connections not part of a network connection
    if (interfaces.size() == 2) {
      // logger.debug("  Adding p-to-p link");
      OrcaLink ol = new OrcaLink(getPrettyName(l));
      ol.setBandwidth(NdlCommons.getResourceBandwidth(l));
      ol.setLabel(label);
      // state
      ol.setState(NdlCommons.getResourceStateAsString(l));

      if (ol.getState() != null) ol.setIsResource();

      // reservation notice
      ol.setReservationNotice(NdlCommons.getResourceReservationNotice(l));
      ol.setReservationGuid(getGuidFromNotice(ol.getReservationNotice()));
      links.put(getTrueName(l), ol);

      // maybe point-to-point link
      // the ends
      Resource if1 = it.next(), if2 = it.next();

      boolean usedOnce = false;
      if ((if1 != null) && (if2 != null)) {
        List<OrcaNode> if1List = interfaceToNode.get(getTrueName(if1));
        List<OrcaNode> if2List = interfaceToNode.get(getTrueName(if2));

        if (if1List != null) {
          for (OrcaNode if1Node : if1List) {
            if (if2List != null) {
              for (OrcaNode if2Node : if2List) {

                if ((if1Node != null) && if1Node.equals(if2Node)) {
                  // degenerate case of a node on a shared vlan
                  OrcaCrossconnect oc = new OrcaCrossconnect(getPrettyName(l));
                  oc.setLabel(label);
                  oc.setDomain(RequestSaver.reverseLookupDomain(NdlCommons.getDomain(l)));
                  nodes.put(getTrueName(l), oc);
                  // save one interface
                  // interfaceToNode.put(getTrueName(if1), oc);
                  addNodeToInterface(getTrueName(if1), oc);
                  pg.addNodeLater(oc);
                  return;
                }

                if (!usedOnce) {
                  // get the bandwidth of crossconnects if possible
                  long bw1 = 0, bw2 = 0;
                  if (if1Node instanceof OrcaCrossconnect) {
                    OrcaCrossconnect oc = (OrcaCrossconnect) if1Node;
                    bw1 = oc.getBandwidth();
                  }
                  if (if2Node instanceof OrcaCrossconnect) {
                    OrcaCrossconnect oc = (OrcaCrossconnect) if2Node;
                    bw2 = oc.getBandwidth();
                  }
                  ol.setBandwidth(bw1 > bw2 ? bw1 : bw2);
                } else ol = new OrcaLink(ol);

                // have to be there
                if ((if1Node != null) && (if2Node != null)) {
                  // logger.debug("  Creating a link " + ol.getName() + " from " + if1Node + " to "
                  // + if2Node);

                  usedOnce = true;
                  pg.addEdgeLater(if1Node, if2Node, label, ol);
                }
              }
            }
          }
        }
      }

    } else {
      // logger.debug("  Adding multi-point crossconnect " + getTrueName(l) + " (has " +
      // interfaces.size() + " interfaces)");
      // multi-point link
      // create a crossconnect then use interfaceToNode mapping to create links to it
      OrcaCrossconnect ml = new OrcaCrossconnect(getPrettyName(l));

      ml.setLabel(label);
      ml.setReservationNotice(NdlCommons.getResourceReservationNotice(l));
      ml.setReservationGuid(getGuidFromNotice(ml.getReservationNotice()));
      ml.setState(NdlCommons.getResourceStateAsString(l));
      ml.setDomain(RequestSaver.reverseLookupDomain(NdlCommons.getDomain(l)));

      if (ml.getState() != null) ml.setIsResource();

      nodes.put(getTrueName(l), ml);

      // special case handling - if storage is one side of the link
      // (only for shared vlan storage), then we only remember
      // interfaces with no ip addresses on them (others are duplicates;
      // we save the equivalence relationship to lookup IP later) /ib 09/18/14
      boolean sharedVlanStorageLink = false;
      Map<Resource, List<Resource>> interfacesByOwner = new HashMap<Resource, List<Resource>>();

      for (Resource ti : interfaces) {
        List<Resource> attached = NdlCommons.getWhoHasInterface(ti, m);
        if (attached == null) continue;
        for (Resource ta : attached) {
          // skip links (self included)
          if (NdlCommons.hasResourceType(ta, NdlCommons.topologyLinkConnectionClass)) continue;
          if (NdlCommons.isISCSINetworkStorage(ta)) {
            sharedVlanStorageLink = true;
          }
          List<Resource> tmp = interfacesByOwner.get(ta);
          if (tmp == null) tmp = new ArrayList<Resource>();
          tmp.add(ti);
          interfacesByOwner.put(ta, tmp);
        }
      }

      // map ip/noip interfaces to each other
      for (Map.Entry<Resource, List<Resource>> ee : interfacesByOwner.entrySet()) {
        // for regular nodes and storage, not for node groups
        if (ee.getValue().size() == 2) {
          Resource noIp = null, ip = null;
          if (NdlCommons.getInterfaceIP(ee.getValue().get(0)) == null) {
            noIp = ee.getValue().get(0);
            ip = ee.getValue().get(1);
          } else {
            noIp = ee.getValue().get(1);
            ip = ee.getValue().get(0);
          }
          sharedStorageLinkInterfaceEquivalence.put(noIp, ip);
          sharedStorageLinkInterfaceEquivalence.put(ip, noIp);
        }
      }

      // remember the interfaces
      while (it.hasNext()) {
        Resource intR = it.next();
        // interfaceToNode.put(getTrueName(intR), ml);
        if (sharedVlanStorageLink) {
          // does it have an IP address? - then we use it (for node groups this ends up false)
          if ((NdlCommons.getInterfaceIP(intR) != null)
              && sharedStorageLinkInterfaceEquivalence.containsKey(intR)) {
            // if it has IP, it is shared and we don't need it, however we need
            // IP address from it
            // logger.debug("  Skipping/deleting interface " + intR + " of " + ml + " that has IP
            // address");
            interfaceToNode.remove(getTrueName(intR));
          } else {
            // if it doesn't have IP, we need it for proper topology visualization
            // logger.debug("  Remembering interface " + intR + " of " + ml);
            addNodeToInterface(getTrueName(intR), ml);
          }
        } else {
          // logger.debug("  Remembering interface " + intR + " of " + ml);
          addNodeToInterface(getTrueName(intR), ml);
        }
      }

      // add crossconnect to the graph
      pg.addNodeLater(ml);

      // link to this later from interface information

      // link nodes (we've already seen them) to it
      //			for(Resource intf: interfaces) {
      //				if (interfaceToNode.get(getTrueName(intf)) != null) {
      //					//logger.debug("  Creating a link " + lcount + " from " + ml + " to " +
      // interfaceToNode.get(getTrueName(intf)));
      //					OrcaLink ol = new OrcaLink("Link " + lcount++);
      //					GUIManifestState.getInstance().getGraph().addEdge(ol, new Pair<OrcaNode>(ml,
      // interfaceToNode.get(getTrueName(intf))), EdgeType.UNDIRECTED);
      //				}
      //			}
    }
  }