// 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 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);
      //				}
      //			}
    }
  }