// set common node properties from NDL
  private void setCommonNodeProperties(OrcaNode on, Resource nr) {
    // post boot script
    on.setPostBootScript(NdlCommons.getPostBootScript(nr));

    // management IP/port access
    on.setManagementAccess(NdlCommons.getNodeServices(nr));

    // state
    on.setState(NdlCommons.getResourceStateAsString(nr));

    if (on.getState() != null) {
      on.setIsResource();
    }

    // reservation notice
    on.setReservationNotice(NdlCommons.getResourceReservationNotice(nr));
    on.setReservationGuid(getGuidFromNotice(on.getReservationNotice()));

    // domain
    Resource domain = NdlCommons.getDomain(nr);
    if (domain != null) on.setDomain(RequestSaver.reverseLookupDomain(domain));

    // url
    on.setUrl(nr.getURI());

    // group (if any)
    String groupUrl = NdlCommons.getRequestGroupURLProperty(nr);
    // group URL same as my URL means I'm a single node
    if ((groupUrl != null) && groupUrl.equals(on.getUrl())) groupUrl = null;
    on.setGroup(groupUrl);

    // specific ce type
    Resource ceType = NdlCommons.getSpecificCE(nr);
    if (ceType != null) on.setNodeType(RequestSaver.reverseNodeTypeLookup(ceType));

    // substrate info if present
    if (NdlCommons.getEC2WorkerNodeId(nr) != null)
      on.setSubstrateInfo("worker", NdlCommons.getEC2WorkerNodeId(nr));
    if (NdlCommons.getEC2InstanceId(nr) != null)
      on.setSubstrateInfo("instance", NdlCommons.getEC2InstanceId(nr));
  }
  @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);
      //				}
      //			}
    }
  }