2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
9 package org.opendaylight.controller.topologymanager.internal;
11 import java.io.FileNotFoundException;
12 import java.io.IOException;
13 import java.io.ObjectInputStream;
14 import java.util.ArrayList;
15 import java.util.Collections;
16 import java.util.Dictionary;
17 import java.util.EnumSet;
18 import java.util.HashMap;
19 import java.util.HashSet;
20 import java.util.Iterator;
23 import java.util.List;
24 import java.util.concurrent.ConcurrentHashMap;
25 import java.util.concurrent.ConcurrentMap;
27 import org.apache.commons.lang3.tuple.ImmutablePair;
28 import org.apache.felix.dm.Component;
29 import org.eclipse.osgi.framework.console.CommandInterpreter;
30 import org.eclipse.osgi.framework.console.CommandProvider;
31 import org.opendaylight.controller.clustering.services.CacheConfigException;
32 import org.opendaylight.controller.clustering.services.CacheExistException;
33 import org.opendaylight.controller.clustering.services.IClusterContainerServices;
34 import org.opendaylight.controller.clustering.services.IClusterServices;
35 import org.opendaylight.controller.configuration.IConfigurationContainerAware;
36 import org.opendaylight.controller.sal.core.ConstructionException;
37 import org.opendaylight.controller.sal.core.Edge;
38 import org.opendaylight.controller.sal.core.Host;
39 import org.opendaylight.controller.sal.core.Node;
40 import org.opendaylight.controller.sal.core.NodeConnector;
41 import org.opendaylight.controller.sal.core.NodeConnector.NodeConnectorIDType;
42 import org.opendaylight.controller.sal.core.Property;
43 import org.opendaylight.controller.sal.core.TimeStamp;
44 import org.opendaylight.controller.sal.core.UpdateType;
45 import org.opendaylight.controller.sal.core.Node.NodeIDType;
46 import org.opendaylight.controller.sal.topology.IListenTopoUpdates;
47 import org.opendaylight.controller.sal.topology.ITopologyService;
48 import org.opendaylight.controller.sal.topology.TopoEdgeUpdate;
49 import org.opendaylight.controller.sal.utils.StatusCode;
50 import org.opendaylight.controller.sal.utils.GlobalConstants;
51 import org.opendaylight.controller.sal.utils.IObjectReader;
52 import org.opendaylight.controller.sal.utils.ObjectReader;
53 import org.opendaylight.controller.sal.utils.ObjectWriter;
54 import org.opendaylight.controller.sal.utils.Status;
55 import org.opendaylight.controller.topologymanager.ITopologyManager;
56 import org.opendaylight.controller.topologymanager.ITopologyManagerAware;
57 import org.opendaylight.controller.topologymanager.TopologyUserLinkConfig;
58 import org.osgi.framework.BundleContext;
59 import org.osgi.framework.FrameworkUtil;
60 import org.slf4j.Logger;
61 import org.slf4j.LoggerFactory;
64 * The class describes TopologyManager which is the central repository of the
65 * network topology. It provides service for applications to interact with
66 * topology database and notifies all the listeners of topology changes.
68 public class TopologyManagerImpl implements ITopologyManager,
69 IConfigurationContainerAware, IListenTopoUpdates, IObjectReader,
71 private static final Logger log = LoggerFactory
72 .getLogger(TopologyManagerImpl.class);
73 private ITopologyService topoService = null;
74 private IClusterContainerServices clusterContainerService = null;
75 // DB of all the Edges with properties which constitute our topology
76 private ConcurrentMap<Edge, Set<Property>> edgesDB = null;
77 // DB of all NodeConnector which are part of ISL Edges, meaning they
78 // are connected to another NodeConnector on the other side of an ISL link.
79 // NodeConnector of a Production Edge is not part of this DB.
80 private ConcurrentMap<NodeConnector, Set<Property>> nodeConnectorsDB = null;
81 // DB of all the NodeConnectors with an Host attached to it
82 private ConcurrentMap<NodeConnector, ImmutablePair<Host, Set<Property>>> hostsDB = null;
83 // Topology Manager Aware listeners
84 private Set<ITopologyManagerAware> topologyManagerAware = Collections
85 .synchronizedSet(new HashSet<ITopologyManagerAware>());
87 private static String ROOT = GlobalConstants.STARTUPHOME.toString();
88 private String userLinksFileName = null;
89 private ConcurrentMap<String, TopologyUserLinkConfig> userLinks;
91 void nonClusterObjectCreate() {
92 edgesDB = new ConcurrentHashMap<Edge, Set<Property>>();
93 hostsDB = new ConcurrentHashMap<NodeConnector, ImmutablePair<Host, Set<Property>>>();
94 userLinks = new ConcurrentHashMap<String, TopologyUserLinkConfig>();
95 nodeConnectorsDB = new ConcurrentHashMap<NodeConnector, Set<Property>>();
98 void setTopologyManagerAware(ITopologyManagerAware s) {
99 if (this.topologyManagerAware != null) {
100 log.debug("Adding ITopologyManagerAware: {}", s);
101 this.topologyManagerAware.add(s);
105 void unsetTopologyManagerAware(ITopologyManagerAware s) {
106 if (this.topologyManagerAware != null) {
107 log.debug("Removing ITopologyManagerAware: {}", s);
108 this.topologyManagerAware.remove(s);
112 void setTopoService(ITopologyService s) {
113 log.debug("Adding ITopologyService: {}", s);
114 this.topoService = s;
117 void unsetTopoService(ITopologyService s) {
118 if (this.topoService == s) {
119 log.debug("Removing ITopologyService: {}", s);
120 this.topoService = null;
124 void setClusterContainerService(IClusterContainerServices s) {
125 log.debug("Cluster Service set");
126 this.clusterContainerService = s;
129 void unsetClusterContainerService(IClusterContainerServices s) {
130 if (this.clusterContainerService == s) {
131 log.debug("Cluster Service removed!");
132 this.clusterContainerService = null;
137 * Function called by the dependency manager when all the required
138 * dependencies are satisfied
141 void init(Component c) {
142 String containerName = null;
143 Dictionary props = c.getServiceProperties();
145 containerName = (String) props.get("containerName");
147 // In the Global instance case the containerName is empty
148 containerName = "UNKNOWN";
151 if (this.clusterContainerService == null) {
152 log.error("Cluster Services is null, not expected!");
156 if (this.topoService == null) {
157 log.error("Topology Services is null, not expected!");
162 this.edgesDB = (ConcurrentMap<Edge, Set<Property>>) this.clusterContainerService
163 .createCache("topologymanager.edgesDB", EnumSet
164 .of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
165 } catch (CacheExistException cee) {
166 log.error("topologymanager.edgesDB Cache already exists - "
167 + "destroy and recreate if needed");
168 } catch (CacheConfigException cce) {
169 log.error("topologymanager.edgesDB Cache configuration invalid - "
170 + "check cache mode");
174 this.hostsDB = (ConcurrentMap<NodeConnector, ImmutablePair<Host, Set<Property>>>) this.clusterContainerService
175 .createCache("topologymanager.hostsDB", EnumSet
176 .of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
177 } catch (CacheExistException cee) {
178 log.error("topologymanager.hostsDB Cache already exists - "
179 + "destroy and recreate if needed");
180 } catch (CacheConfigException cce) {
181 log.error("topologymanager.hostsDB Cache configuration invalid - "
182 + "check cache mode");
186 this.nodeConnectorsDB = (ConcurrentMap<NodeConnector, Set<Property>>) this.clusterContainerService
187 .createCache("topologymanager.nodeConnectorDB", EnumSet
188 .of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
189 } catch (CacheExistException cee) {
190 log.error("topologymanager.nodeConnectorDB Cache already exists"
191 + " - destroy and recreate if needed");
192 } catch (CacheConfigException cce) {
193 log.error("topologymanager.nodeConnectorDB Cache configuration "
194 + "invalid - check cache mode");
197 userLinks = new ConcurrentHashMap<String, TopologyUserLinkConfig>();
199 userLinksFileName = ROOT + "userTopology_" + containerName + ".conf";
200 registerWithOSGIConsole();
205 * Function called after the topology manager has registered the service in
206 * OSGi service registry.
210 // SollicitRefresh MUST be called here else if called at init
211 // time it may sollicit refresh too soon.
212 log.debug("Sollicit topology refresh");
213 topoService.sollicitRefresh();
217 * Function called by the dependency manager when at least one dependency
218 * become unsatisfied or when the component is shutting down because for
219 * example bundle is being stopped.
223 if (this.clusterContainerService == null) {
224 log.error("Cluster Services is null, not expected!");
227 this.nodeConnectorsDB = null;
230 this.clusterContainerService.destroyCache("topologymanager.edgesDB");
232 this.clusterContainerService.destroyCache("topologymanager.hostsDB");
234 this.clusterContainerService
235 .destroyCache("topologymanager.nodeConnectorDB");
236 this.nodeConnectorsDB = null;
237 log.debug("Topology Manager DB Deallocated");
240 @SuppressWarnings("unchecked")
241 private void loadConfiguration() {
242 ObjectReader objReader = new ObjectReader();
243 ConcurrentMap<String, TopologyUserLinkConfig> confList = (ConcurrentMap<String, TopologyUserLinkConfig>) objReader
244 .read(this, userLinksFileName);
246 if (confList == null) {
250 for (TopologyUserLinkConfig conf : confList.values()) {
256 public Status saveConfig() {
257 // Publish the save config event to the cluster nodes
259 * Get the CLUSTERING SERVICES WORKING BEFORE TRYING THIS
261 * configSaveEvent.put(new Date().getTime(), SAVE);
263 return saveConfigInternal();
266 public Status saveConfigInternal() {
268 ObjectWriter objWriter = new ObjectWriter();
271 .write(new ConcurrentHashMap<String, TopologyUserLinkConfig>(
272 userLinks), userLinksFileName);
274 if (retS.isSuccess()) {
277 return new Status(StatusCode.INTERNALERROR, "Save failed");
282 public Map<Node, Set<Edge>> getNodeEdges() {
283 if (this.edgesDB == null) {
287 HashMap<Node, Set<Edge>> res = new HashMap<Node, Set<Edge>>();
288 for (Edge key : this.edgesDB.keySet()) {
289 // Lets analyze the tail
290 Node node = key.getTailNodeConnector().getNode();
291 Set<Edge> nodeEdges = res.get(node);
292 if (nodeEdges == null) {
293 nodeEdges = new HashSet<Edge>();
296 // We need to re-add to the MAP even if the element was
297 // already there so in case of clustered services the map
298 // gets updated in the cluster
299 res.put(node, nodeEdges);
301 // Lets analyze the head
302 node = key.getHeadNodeConnector().getNode();
303 nodeEdges = res.get(node);
304 if (nodeEdges == null) {
305 nodeEdges = new HashSet<Edge>();
308 // We need to re-add to the MAP even if the element was
309 // already there so in case of clustered services the map
310 // gets updated in the cluster
311 res.put(node, nodeEdges);
318 public boolean isInternal(NodeConnector p) {
319 if (this.nodeConnectorsDB == null) {
323 // This is an internal NodeConnector if is connected to
324 // another Node i.e it's part of the nodeConnectorsDB
325 return (this.nodeConnectorsDB.get(p) != null);
329 * This method returns true if the edge is an ISL link.
333 * @return true if it is an ISL link
335 public boolean isISLink(Edge e) {
336 return (!isProductionLink(e));
340 * This method returns true if the edge is a production link.
344 * @return true if it is a production link
346 public boolean isProductionLink(Edge e) {
347 return (e.getHeadNodeConnector().getType()
348 .equals(NodeConnector.NodeConnectorIDType.PRODUCTION) || e
349 .getTailNodeConnector().getType()
350 .equals(NodeConnector.NodeConnectorIDType.PRODUCTION));
354 * The Map returned is a copy of the current topology hence if the topology
355 * changes the copy doesn't
357 * @return A Map representing the current topology expressed as edges of the
361 public Map<Edge, Set<Property>> getEdges() {
362 if (this.edgesDB == null) {
366 HashMap<Edge, Set<Property>> res = new HashMap<Edge, Set<Property>>();
367 for (Edge key : this.edgesDB.keySet()) {
368 // Sets of props are copied because the composition of
369 // those properties could change with time
370 HashSet<Property> prop = new HashSet<Property>(
371 this.edgesDB.get(key));
372 // We can simply reuse the key because the object is
373 // immutable so doesn't really matter that we are
374 // referencing the only owned by a different table, the
375 // meaning is the same because doesn't change with time.
382 // TODO remove with spring-dm removal
385 * the topologyAware to set
387 public void setTopologyAware(Set<Object> set) {
388 for (Object s : set) {
389 setTopologyManagerAware((ITopologyManagerAware) s);
394 public Set<NodeConnector> getNodeConnectorWithHost() {
395 if (this.hostsDB == null) {
399 return (this.hostsDB.keySet());
403 public Map<Node, Set<NodeConnector>> getNodesWithNodeConnectorHost() {
404 if (this.hostsDB == null) {
407 HashMap<Node, Set<NodeConnector>> res = new HashMap<Node, Set<NodeConnector>>();
409 for (NodeConnector p : this.hostsDB.keySet()) {
410 Node n = p.getNode();
411 Set<NodeConnector> pSet = res.get(n);
413 // Create the HashSet if null
414 pSet = new HashSet<NodeConnector>();
418 // Keep updating the HashSet, given this is not a
419 // clustered map we can just update the set without
420 // worrying to update the hashmap.
428 public Host getHostAttachedToNodeConnector(NodeConnector p) {
429 if (this.hostsDB == null) {
433 return (this.hostsDB.get(p).getLeft());
437 public void updateHostLink(NodeConnector p, Host h, UpdateType t,
438 Set<Property> props) {
439 if (this.hostsDB == null) {
446 // Clone the property set in case non null else just
447 // create an empty one. Caches allocated via infinispan
448 // don't allow null values
450 props = new HashSet<Property>();
452 props = new HashSet<Property>(props);
455 this.hostsDB.put(p, new ImmutablePair(h, props));
458 this.hostsDB.remove(p);
463 private TopoEdgeUpdate edgeUpdate(Edge e, UpdateType type,
464 Set<Property> props) {
467 // Make sure the props are non-null
469 props = (Set<Property>) new HashSet();
471 // Copy the set so noone is going to change the content
472 props = (Set<Property>) new HashSet(props);
475 // Now make sure there is the creation timestamp for the
476 // edge, if not there timestamp with the first update
477 boolean found_create = false;
478 for (Property prop : props) {
479 if (prop instanceof TimeStamp) {
480 TimeStamp t = (TimeStamp) prop;
481 if (t.getTimeStampName().equals("creation")) {
488 TimeStamp t = new TimeStamp(System.currentTimeMillis(),
493 // Now add this in the database eventually overriding
494 // something that may have been already existing
495 this.edgesDB.put(e, props);
497 // Now populate the DB of NodeConnectors
498 // NOTE WELL: properties are empty sets, not really needed
500 // The DB only contains ISL ports
502 this.nodeConnectorsDB.put(e.getHeadNodeConnector(),
503 new HashSet<Property>());
504 this.nodeConnectorsDB.put(e.getTailNodeConnector(),
505 new HashSet<Property>());
507 log.trace("Edge {} {}", e.toString(), type.name());
510 // Now remove the edge from edgesDB
511 this.edgesDB.remove(e);
513 // Now lets update the NodeConnectors DB, the assumption
514 // here is that two NodeConnector are exclusively
515 // connected by 1 and only 1 edge, this is reasonable in
516 // the same plug (virtual of phisical) we can assume two
517 // cables won't be plugged. This could break only in case
518 // of devices in the middle that acts as hubs, but it
519 // should be safe to assume that won't happen.
520 this.nodeConnectorsDB.remove(e.getHeadNodeConnector());
521 this.nodeConnectorsDB.remove(e.getTailNodeConnector());
522 log.trace("Edge {} {}", e.toString(), type.name());
525 Set<Property> old_props = this.edgesDB.get(e);
527 // When property changes lets make sure we can change it
528 // all except the creation time stamp because that should
529 // be changed only when the edge is destroyed and created
532 for (Property prop : old_props) {
533 if (prop instanceof TimeStamp) {
534 TimeStamp t = (TimeStamp) prop;
535 if (t.getTimeStampName().equals("creation")) {
541 // Now lets make sure new properties are non-null
542 // Make sure the props are non-null
544 props = (Set<Property>) new HashSet();
546 // Copy the set so noone is going to change the content
547 props = (Set<Property>) new HashSet(props);
550 // Now lets remove the creation property if exist in the
552 for (Iterator<Property> i = props.iterator(); i.hasNext();) {
553 Property prop = i.next();
554 if (prop instanceof TimeStamp) {
555 TimeStamp t = (TimeStamp) prop;
556 if (t.getTimeStampName().equals("creation")) {
562 // Now lets add the creation timestamp in it
568 this.edgesDB.put(e, props);
569 log.trace("Edge {} {}", e.toString(), type.name());
572 return new TopoEdgeUpdate(e, props, type);
576 public void edgeUpdate(List<TopoEdgeUpdate> topoedgeupdateList) {
577 List<TopoEdgeUpdate> teuList = new ArrayList<TopoEdgeUpdate>();
578 for (int i = 0; i < topoedgeupdateList.size(); i++) {
579 Edge e = topoedgeupdateList.get(i).getEdge();
580 Set<Property> p = topoedgeupdateList.get(i).getProperty();
581 UpdateType type = topoedgeupdateList.get(i).getUpdateType();
582 TopoEdgeUpdate teu = edgeUpdate(e, type, p);
586 // Now update the listeners
587 for (ITopologyManagerAware s : this.topologyManagerAware) {
589 s.edgeUpdate(teuList);
590 } catch (Exception exc) {
591 log.error("Exception on callback", exc);
597 private Edge getReverseLinkTuple(TopologyUserLinkConfig link) {
598 TopologyUserLinkConfig rLink = new TopologyUserLinkConfig(
599 link.getName(), link.getDstNodeIDType(), link.getDstSwitchId(),
600 link.getDstNodeConnectorIDType(), link.getDstPort(),
601 link.getSrcNodeIDType(), link.getSrcSwitchId(),
602 link.getSrcNodeConnectorIDType(), link.getSrcPort());
603 return getLinkTuple(rLink);
606 private Edge getLinkTuple(TopologyUserLinkConfig link) {
607 Edge linkTuple = null;
609 // if atleast 1 link exists for the srcPort and atleast 1 link exists
611 // that makes it ineligible for the Manual link addition
612 // This is just an extra protection to avoid mis-programming.
613 boolean srcLinkExists = false;
614 boolean dstLinkExists = false;
615 // TODO check a way to validate the port with inventory services
616 // if (srcSw.getPorts().contains(srcPort) &&
617 // dstSw.getPorts().contains(srcPort) &&
618 if (!srcLinkExists && !dstLinkExists) {
621 NodeConnector sPort = null;
622 NodeConnector dPort = null;
624 String srcNodeIDType = link.getSrcNodeIDType();
625 String srcNodeConnectorIDType = link.getSrcNodeConnectorIDType();
626 String dstNodeIDType = link.getDstNodeIDType();
627 String dstNodeConnectorIDType = link.getDstNodeConnectorIDType();
629 if (srcNodeIDType.equals(NodeIDType.OPENFLOW)) {
630 sNode = new Node(srcNodeIDType, link.getSrcSwitchIDLong());
632 sNode = new Node(srcNodeIDType, link.getSrcSwitchId());
635 if (dstNodeIDType.equals(NodeIDType.OPENFLOW)) {
636 dNode = new Node(dstNodeIDType, link.getDstSwitchIDLong());
638 dNode = new Node(dstNodeIDType, link.getDstSwitchId());
641 if (srcNodeConnectorIDType.equals(NodeConnectorIDType.OPENFLOW)) {
642 Short srcPort = Short.valueOf((short) 0);
643 if (!link.isSrcPortByName()) {
644 srcPort = Short.parseShort(link.getSrcPort());
646 sPort = new NodeConnector(srcNodeConnectorIDType, srcPort,
649 sPort = new NodeConnector(srcNodeConnectorIDType,
650 link.getSrcPort(), sNode);
653 if (dstNodeConnectorIDType.equals(NodeConnectorIDType.OPENFLOW)) {
654 Short dstPort = Short.valueOf((short) 0);
655 if (!link.isDstPortByName()) {
656 dstPort = Short.parseShort(link.getDstPort());
658 dPort = new NodeConnector(dstNodeConnectorIDType, dstPort,
661 dPort = new NodeConnector(dstNodeConnectorIDType,
662 link.getDstPort(), dNode);
664 linkTuple = new Edge(sPort, dPort);
665 } catch (ConstructionException cex) {
666 log.warn("Caught exception ", cex);
671 if (srcLinkExists && dstLinkExists) {
672 link.setStatus(TopologyUserLinkConfig.STATUS.INCORRECT);
678 public ConcurrentMap<String, TopologyUserLinkConfig> getUserLinks() {
683 public Status addUserLink(TopologyUserLinkConfig link) {
684 if (!link.isValid()) {
685 return new Status(StatusCode.BADREQUEST,
686 "Configuration Invalid. Please check the parameters");
688 if (userLinks.get(link.getName()) != null) {
689 return new Status(StatusCode.CONFLICT, "Link with name : "
691 + " already exists. Please use another name");
693 if (userLinks.containsValue(link)) {
694 return new Status(StatusCode.CONFLICT, "Link configuration exists");
697 link.setStatus(TopologyUserLinkConfig.STATUS.LINKDOWN);
698 userLinks.put(link.getName(), link);
700 Edge linkTuple = getLinkTuple(link);
701 if (linkTuple != null) {
702 if (!isProductionLink(linkTuple)) {
703 edgeUpdate(linkTuple, UpdateType.ADDED, new HashSet<Property>());
706 linkTuple = getReverseLinkTuple(link);
707 if (linkTuple != null) {
708 link.setStatus(TopologyUserLinkConfig.STATUS.SUCCESS);
709 if (!isProductionLink(linkTuple)) {
710 edgeUpdate(linkTuple, UpdateType.ADDED, new HashSet<Property>());
714 return new Status(StatusCode.SUCCESS, null);
718 public Status deleteUserLink(String linkName) {
719 if (linkName == null) {
720 return new Status(StatusCode.BADREQUEST,
721 "A valid linkName is required to Delete a link");
724 TopologyUserLinkConfig link = userLinks.get(linkName);
726 Edge linkTuple = getLinkTuple(link);
727 userLinks.remove(linkName);
728 if (linkTuple != null) {
729 if (!isProductionLink(linkTuple)) {
730 edgeUpdate(linkTuple, UpdateType.REMOVED, null);
733 linkTuple = getReverseLinkTuple(link);
734 if ((linkTuple != null) && !isProductionLink(linkTuple)) {
735 edgeUpdate(linkTuple, UpdateType.REMOVED, null);
738 return new Status(StatusCode.SUCCESS, null);
741 private void registerWithOSGIConsole() {
742 BundleContext bundleContext = FrameworkUtil.getBundle(this.getClass())
744 bundleContext.registerService(CommandProvider.class.getName(), this,
749 public String getHelp() {
750 StringBuffer help = new StringBuffer();
751 help.append("---Topology Manager---\n");
752 help.append("\t addUserLink <name> <node connector string> <node connector string>\n");
753 help.append("\t deleteUserLink <name>\n");
754 help.append("\t printUserLink\n");
755 help.append("\t printNodeEdges\n");
756 return help.toString();
759 public void _printUserLink(CommandInterpreter ci) {
760 for (String name : this.userLinks.keySet()) {
761 TopologyUserLinkConfig linkConfig = userLinks.get(name);
762 ci.println("Name : " + name);
763 ci.println(linkConfig);
764 ci.println("Edge " + getLinkTuple(linkConfig));
765 ci.println("Reverse Edge " + getReverseLinkTuple(linkConfig));
769 public void _addUserLink(CommandInterpreter ci) {
770 String name = ci.nextArgument();
771 if ((name == null)) {
772 ci.println("Please enter a valid Name");
776 String ncStr1 = ci.nextArgument();
777 if (ncStr1 == null) {
778 ci.println("Please enter two node connector strings");
781 String ncStr2 = ci.nextArgument();
782 if (ncStr2 == null) {
783 ci.println("Please enter second node connector string");
787 NodeConnector nc1 = NodeConnector.fromString(ncStr1);
789 ci.println("Invalid input node connector 1 string: " + ncStr1);
792 NodeConnector nc2 = NodeConnector.fromString(ncStr2);
794 ci.println("Invalid input node connector 2 string: " + ncStr2);
798 String nodeType1 = nc1.getNode().getType().toString();
799 String nid1 = nc1.getNode().getID().toString();
800 String ncType1 = nc1.getType().toString();
801 String ncid1 = nc1.getID().toString();
803 String nodeType2 = nc2.getNode().getType().toString();
804 String nid2 = nc2.getNode().getID().toString();
805 String ncType2 = nc2.getType().toString();
806 String ncid2 = nc2.getID().toString();
808 TopologyUserLinkConfig config = new TopologyUserLinkConfig(name,
809 nodeType1, nid1, ncType1, ncid1, nodeType2, nid2, ncType2,
811 ci.println(this.addUserLink(config));
814 public void _deleteUserLink(CommandInterpreter ci) {
815 String name = ci.nextArgument();
816 if ((name == null)) {
817 ci.println("Please enter a valid Name");
820 this.deleteUserLink(name);
823 public void _printNodeEdges(CommandInterpreter ci) {
824 Map<Node, Set<Edge>> nodeEdges = getNodeEdges();
825 if (nodeEdges == null) {
828 Set<Node> nodeSet = nodeEdges.keySet();
829 if (nodeSet == null) {
832 ci.println(" Node Edge");
833 for (Node node : nodeSet) {
834 Set<Edge> edgeSet = nodeEdges.get(node);
835 if (edgeSet == null) {
838 for (Edge edge : edgeSet) {
839 ci.println(node + " " + edge);
845 public Object readObject(ObjectInputStream ois)
846 throws FileNotFoundException, IOException, ClassNotFoundException {
847 // TODO Auto-generated method stub
848 return ois.readObject();
852 public Status saveConfiguration() {
857 public void edgeOverUtilized(Edge edge) {
858 log.warn("Link Utilization above normal: {}", edge);
862 public void edgeUtilBackToNormal(Edge edge) {
863 log.warn("Link Utilization back to normal: {}", edge);