25058a3e1386c58b2d349fc64893f60b4e281b0e
[controller.git] / opendaylight / topologymanager / src / main / java / org / opendaylight / controller / topologymanager / internal / TopologyManagerImpl.java
1
2 /*
3  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
4  *
5  * This program and the accompanying materials are made available under the
6  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
7  * and is available at http://www.eclipse.org/legal/epl-v10.html
8  */
9
10 package org.opendaylight.controller.topologymanager.internal;
11
12 import java.io.FileNotFoundException;
13 import java.io.IOException;
14 import java.io.ObjectInputStream;
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;
21 import java.util.Map;
22 import java.util.Set;
23 import java.util.concurrent.ConcurrentHashMap;
24 import java.util.concurrent.ConcurrentMap;
25
26 import org.apache.commons.lang3.tuple.ImmutablePair;
27 import org.apache.felix.dm.Component;
28 import org.eclipse.osgi.framework.console.CommandInterpreter;
29 import org.eclipse.osgi.framework.console.CommandProvider;
30 import org.opendaylight.controller.clustering.services.CacheConfigException;
31 import org.opendaylight.controller.clustering.services.CacheExistException;
32 import org.opendaylight.controller.clustering.services.IClusterContainerServices;
33 import org.opendaylight.controller.clustering.services.IClusterServices;
34 import org.opendaylight.controller.configuration.IConfigurationContainerAware;
35 import org.opendaylight.controller.sal.core.ConstructionException;
36 import org.opendaylight.controller.sal.core.Edge;
37 import org.opendaylight.controller.sal.core.Host;
38 import org.opendaylight.controller.sal.core.Node;
39 import org.opendaylight.controller.sal.core.NodeConnector;
40 import org.opendaylight.controller.sal.core.NodeConnector.NodeConnectorIDType;
41 import org.opendaylight.controller.sal.core.Property;
42 import org.opendaylight.controller.sal.core.TimeStamp;
43 import org.opendaylight.controller.sal.core.UpdateType;
44 import org.opendaylight.controller.sal.core.Node.NodeIDType;
45 import org.opendaylight.controller.sal.topology.IListenTopoUpdates;
46 import org.opendaylight.controller.sal.topology.ITopologyService;
47 import org.opendaylight.controller.sal.utils.StatusCode;
48 import org.opendaylight.controller.sal.utils.GlobalConstants;
49 import org.opendaylight.controller.sal.utils.IObjectReader;
50 import org.opendaylight.controller.sal.utils.ObjectReader;
51 import org.opendaylight.controller.sal.utils.ObjectWriter;
52 import org.opendaylight.controller.sal.utils.Status;
53 import org.opendaylight.controller.topologymanager.ITopologyManager;
54 import org.opendaylight.controller.topologymanager.ITopologyManagerAware;
55 import org.opendaylight.controller.topologymanager.TopologyUserLinkConfig;
56 import org.osgi.framework.BundleContext;
57 import org.osgi.framework.FrameworkUtil;
58 import org.slf4j.Logger;
59 import org.slf4j.LoggerFactory;
60
61 /**
62  * The class describes TopologyManager which is the central repository of the
63  * network topology. It provides service for applications to interact with
64  * topology database and notifies all the listeners of topology changes.
65  */
66 public class TopologyManagerImpl implements ITopologyManager,
67         IConfigurationContainerAware, IListenTopoUpdates, IObjectReader,
68         CommandProvider {
69     private static final Logger log = LoggerFactory
70             .getLogger(TopologyManagerImpl.class);
71     private ITopologyService topoService = null;
72     private IClusterContainerServices clusterContainerService = null;
73     // DB of all the Edges with properties which constitute our topology
74     private ConcurrentMap<Edge, Set<Property>> edgesDB = null;
75     // DB of all NodeConnector which are part of Edges, meaning they
76     // are connected to another NodeConnector on the other side
77     private ConcurrentMap<NodeConnector, Set<Property>> nodeConnectorsDB = null;
78     // DB of all the NodeConnectors with an Host attached to it
79     private ConcurrentMap<NodeConnector, ImmutablePair<Host, Set<Property>>> hostsDB = null;
80     // Topology Manager Aware listeners
81     private Set<ITopologyManagerAware> topologyManagerAware = Collections
82             .synchronizedSet(new HashSet<ITopologyManagerAware>());
83
84     private static String ROOT = GlobalConstants.STARTUPHOME.toString();
85     private String userLinksFileName = null;
86     private ConcurrentMap<String, TopologyUserLinkConfig> userLinks;
87     
88     void nonClusterObjectCreate() {
89         edgesDB = new ConcurrentHashMap<Edge, Set<Property>>();
90         hostsDB = new ConcurrentHashMap<NodeConnector, ImmutablePair<Host, Set<Property>>>();
91         userLinks = new ConcurrentHashMap<String, TopologyUserLinkConfig>();
92         nodeConnectorsDB = new ConcurrentHashMap<NodeConnector, Set<Property>>();
93     }
94     
95
96     void setTopologyManagerAware(ITopologyManagerAware s) {
97         if (this.topologyManagerAware != null) {
98                 log.debug("Adding ITopologyManagerAware: " + s);
99             this.topologyManagerAware.add(s);
100         }
101     }
102
103     void unsetTopologyManagerAware(ITopologyManagerAware s) {
104         if (this.topologyManagerAware != null) {
105             this.topologyManagerAware.remove(s);
106         }
107     }
108
109     void setTopoService(ITopologyService s) {
110         this.topoService = s;
111     }
112
113     void unsetTopoService(ITopologyService s) {
114         if (this.topoService == s) {
115             this.topoService = null;
116         }
117     }
118
119     void setClusterContainerService(IClusterContainerServices s) {
120         log.debug("Cluster Service set");
121         this.clusterContainerService = s;
122     }
123
124     void unsetClusterContainerService(IClusterContainerServices s) {
125         if (this.clusterContainerService == s) {
126             log.debug("Cluster Service removed!");
127             this.clusterContainerService = null;
128         }
129     }
130
131     /**
132      * Function called by the dependency manager when all the required
133      * dependencies are satisfied
134      *
135      */
136     void init(Component c) {
137         String containerName = null;
138         Dictionary props = c.getServiceProperties();
139         if (props != null) {
140             containerName = (String) props.get("containerName");
141         } else {
142             // In the Global instance case the containerName is empty
143             containerName = "UNKNOWN";
144         }
145
146         if (this.clusterContainerService == null) {
147             log.error("Cluster Services is null, not expected!");
148             return;
149         }
150
151         if (this.topoService == null) {
152             log.error("Topology Services is null, not expected!");
153             return;
154         }
155
156         try {
157             this.edgesDB = (ConcurrentMap<Edge, Set<Property>>) this.clusterContainerService
158                     .createCache("topologymanager.edgesDB", EnumSet
159                             .of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
160         } catch (CacheExistException cee) {
161             log.error("topologymanager.edgesDB Cache already exists - "
162                     + "destroy and recreate if needed");
163         } catch (CacheConfigException cce) {
164             log.error("topologymanager.edgesDB Cache configuration invalid - "
165                     + "check cache mode");
166         }
167
168         try {
169             this.hostsDB = (ConcurrentMap<NodeConnector, ImmutablePair<Host, Set<Property>>>) this.clusterContainerService
170                     .createCache("topologymanager.hostsDB", EnumSet
171                             .of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
172         } catch (CacheExistException cee) {
173             log.error("topologymanager.hostsDB Cache already exists - "
174                     + "destroy and recreate if needed");
175         } catch (CacheConfigException cce) {
176             log.error("topologymanager.hostsDB Cache configuration invalid - "
177                     + "check cache mode");
178         }
179
180         try {
181             this.nodeConnectorsDB = (ConcurrentMap<NodeConnector, Set<Property>>) this.clusterContainerService
182                     .createCache("topologymanager.nodeConnectorDB", EnumSet
183                             .of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
184         } catch (CacheExistException cee) {
185             log.error("topologymanager.nodeConnectorDB Cache already exists"
186                     + " - destroy and recreate if needed");
187         } catch (CacheConfigException cce) {
188             log.error("topologymanager.nodeConnectorDB Cache configuration "
189                     + "invalid - check cache mode");
190         }
191
192         userLinks = new ConcurrentHashMap<String, TopologyUserLinkConfig>();
193
194         userLinksFileName = ROOT + "userTopology_" + containerName + ".conf";
195         registerWithOSGIConsole();
196         loadConfiguration();
197     }
198
199     /**
200      * Function called after the topology manager has registered the
201      * service in OSGi service registry.
202      *
203      */
204     void started() {
205         // SollicitRefresh MUST be called here else if called at init
206         // time it may sollicit refresh too soon.
207         log.debug("Sollicit topology refresh");
208         topoService.sollicitRefresh();
209     }
210
211     /**
212      * Function called by the dependency manager when at least one
213      * dependency become unsatisfied or when the component is shutting
214      * down because for example bundle is being stopped.
215      *
216      */
217     void destroy() {
218         if (this.clusterContainerService == null) {
219             log.error("Cluster Services is null, not expected!");
220             this.edgesDB = null;
221             this.hostsDB = null;
222             this.nodeConnectorsDB = null;
223             return;
224         }
225         this.clusterContainerService.destroyCache("topologymanager.edgesDB");
226         this.edgesDB = null;
227         this.clusterContainerService.destroyCache("topologymanager.hostsDB");
228         this.hostsDB = null;
229         this.clusterContainerService
230                 .destroyCache("topologymanager.nodeConnectorDB");
231         this.nodeConnectorsDB = null;
232         log.debug("Topology Manager DB DE-allocated");
233     }
234
235     @SuppressWarnings("unchecked")
236     private void loadConfiguration() {
237         ObjectReader objReader = new ObjectReader();
238         ConcurrentMap<String, TopologyUserLinkConfig> confList = (ConcurrentMap<String, TopologyUserLinkConfig>) objReader
239                 .read(this, userLinksFileName);
240
241         if (confList == null) {
242             return;
243         }
244
245         for (TopologyUserLinkConfig conf : confList.values()) {
246             addUserLink(conf);
247         }
248     }
249
250     @Override
251     public Status saveConfig() {
252         // Publish the save config event to the cluster nodes
253         /**
254          * Get the CLUSTERING SERVICES WORKING BEFORE TRYING THIS
255
256         configSaveEvent.put(new Date().getTime(), SAVE);
257          */
258         return saveConfigInternal();
259     }
260
261     public Status saveConfigInternal() {
262         Status retS;
263         ObjectWriter objWriter = new ObjectWriter();
264
265         retS = objWriter.write(
266                 new ConcurrentHashMap<String, TopologyUserLinkConfig>(
267                         userLinks), userLinksFileName);
268
269         if (retS.isSuccess()) {
270             return retS;
271         } else {
272             return new Status(StatusCode.INTERNALERROR, "Save failed");
273         }
274     }
275
276     @Override
277     public Map<Node, Set<Edge>> getNodeEdges() {
278         if (this.edgesDB == null) {
279             return null;
280         }
281
282         HashMap<Node, Set<Edge>> res = new HashMap<Node, Set<Edge>>();
283         for (Edge key : this.edgesDB.keySet()) {
284             // Lets analyze the tail
285             Node node = key.getTailNodeConnector().getNode();
286             Set<Edge> nodeEdges = res.get(node);
287             if (nodeEdges == null) {
288                 nodeEdges = new HashSet<Edge>();
289             }
290             nodeEdges.add(key);
291             // We need to re-add to the MAP even if the element was
292             // already there so in case of clustered services the map
293             // gets updated in the cluster
294             res.put(node, nodeEdges);
295
296             // Lets analyze the head
297             node = key.getHeadNodeConnector().getNode();
298             nodeEdges = res.get(node);
299             if (nodeEdges == null) {
300                 nodeEdges = new HashSet<Edge>();
301             }
302             nodeEdges.add(key);
303             // We need to re-add to the MAP even if the element was
304             // already there so in case of clustered services the map
305             // gets updated in the cluster
306             res.put(node, nodeEdges);
307         }
308
309         return res;
310     }
311
312     @Override
313     public boolean isInternal(NodeConnector p) {
314         if (this.nodeConnectorsDB == null) {
315             return false;
316         }
317
318         // This is an internal NodeConnector if is connected to
319         // another Node i.e it's part of the nodeConnectorsDB
320         return (this.nodeConnectorsDB.get(p) != null);
321     }
322
323     /**
324      * The Map returned is a copy of the current topology hence if the
325      * topology changes the copy doesn't
326      *
327      * @return A Map representing the current topology expressed as
328      * edges of the network
329      */
330     @Override
331     public Map<Edge, Set<Property>> getEdges() {
332         if (this.edgesDB == null) {
333             return null;
334         }
335
336         HashMap<Edge, Set<Property>> res = new HashMap<Edge, Set<Property>>();
337         for (Edge key : this.edgesDB.keySet()) {
338             // Sets of props are copied because the composition of
339             // those properties could change with time
340             HashSet<Property> prop = new HashSet<Property>(this.edgesDB
341                     .get(key));
342             // We can simply reuse the key because the object is
343             // immutable so doesn't really matter that we are
344             // referencing the only owned by a different table, the
345             // meaning is the same because doesn't change with time.
346             res.put(key, prop);
347         }
348
349         return res;
350     }
351
352     // TODO remove with spring-dm removal
353     /**
354      * @param set the topologyAware to set
355      */
356     public void setTopologyAware(Set<Object> set) {
357         for (Object s : set) {
358             setTopologyManagerAware((ITopologyManagerAware) s);
359         }
360     }
361
362     @Override
363     public Set<NodeConnector> getNodeConnectorWithHost() {
364         if (this.hostsDB == null) {
365             return null;
366         }
367
368         return (this.hostsDB.keySet());
369     }
370
371     @Override
372     public Map<Node, Set<NodeConnector>> getNodesWithNodeConnectorHost() {
373         if (this.hostsDB == null) {
374             return null;
375         }
376         HashMap<Node, Set<NodeConnector>> res = new HashMap<Node, Set<NodeConnector>>();
377
378         for (NodeConnector p : this.hostsDB.keySet()) {
379             Node n = p.getNode();
380             Set<NodeConnector> pSet = res.get(n);
381             if (pSet == null) {
382                 // Create the HashSet if null
383                 pSet = new HashSet<NodeConnector>();
384                 res.put(n, pSet);
385             }
386
387             // Keep updating the HashSet, given this is not a
388             // clustered map we can just update the set without
389             // worrying to update the hashmap.
390             pSet.add(p);
391         }
392
393         return (res);
394     }
395
396     @Override
397     public Host getHostAttachedToNodeConnector(NodeConnector p) {
398         if (this.hostsDB == null) {
399             return null;
400         }
401
402         return (this.hostsDB.get(p).getLeft());
403     }
404
405     @Override
406     public void updateHostLink(NodeConnector p, Host h, UpdateType t,
407             Set<Property> props) {
408         if (this.hostsDB == null) {
409             return;
410         }
411
412         switch (t) {
413         case ADDED:
414         case CHANGED:
415             // Clone the property set in case non null else just
416             // create an empty one. Caches allocated via infinispan
417             // don't allow null values
418             if (props == null) {
419                 props = new HashSet<Property>();
420             } else {
421                 props = new HashSet<Property>(props);
422             }
423
424             this.hostsDB.put(p, new ImmutablePair(h, props));
425             break;
426         case REMOVED:
427             this.hostsDB.remove(p);
428             break;
429         }
430     }
431
432     @Override
433     public void edgeUpdate(Edge e, UpdateType type, Set<Property> props) {
434         switch (type) {
435         case ADDED:
436             // Make sure the props are non-null
437             if (props == null) {
438                 props = (Set<Property>) new HashSet();
439             } else {
440                 // Copy the set so noone is going to change the content
441                 props = (Set<Property>) new HashSet(props);
442             }
443
444             // Now make sure thre is the creation timestamp for the
445             // edge, if not there timestamp with the first update
446             boolean found_create = false;
447             for (Property prop : props) {
448                 if (prop instanceof TimeStamp) {
449                     TimeStamp t = (TimeStamp) prop;
450                     if (t.getTimeStampName().equals("creation")) {
451                         found_create = true;
452                     }
453                 }
454             }
455
456             if (!found_create) {
457                 TimeStamp t = new TimeStamp(System.currentTimeMillis(),
458                         "creation");
459                 props.add(t);
460             }
461
462             // Now add this in the database eventually overriding
463             // something that may have been already existing
464             this.edgesDB.put(e, props);
465
466             // Now populate the DB of NodeConnectors
467             // NOTE WELL: properties are empy sets, not really needed
468             // for now.
469             this.nodeConnectorsDB.put(e.getHeadNodeConnector(),
470                     new HashSet<Property>());
471             this.nodeConnectorsDB.put(e.getTailNodeConnector(),
472                     new HashSet<Property>());
473             break;
474         case REMOVED:
475             // Now remove the edge from edgesDB
476             this.edgesDB.remove(e);
477
478             // Now lets update the NodeConnectors DB, the assumption
479             // here is that two NodeConnector are exclusively
480             // connected by 1 and only 1 edge, this is reasonable in
481             // the same plug (virtual of phisical) we can assume two
482             // cables won't be plugged. This could break only in case
483             // of devices in the middle that acts as hubs, but it
484             // should be safe to assume that won't happen.
485             this.nodeConnectorsDB.remove(e.getHeadNodeConnector());
486             this.nodeConnectorsDB.remove(e.getTailNodeConnector());
487             break;
488         case CHANGED:
489             Set<Property> old_props = this.edgesDB.get(e);
490
491             // When property changes lets make sure we can change it
492             // all except the creation time stamp because that should
493             // be changed only when the edge is destroyed and created
494             // again
495             TimeStamp tc = null;
496             for (Property prop : old_props) {
497                 if (prop instanceof TimeStamp) {
498                     TimeStamp t = (TimeStamp) prop;
499                     if (t.getTimeStampName().equals("creation")) {
500                         tc = t;
501                     }
502                 }
503             }
504
505             // Now lest make sure new properties are non-null
506             // Make sure the props are non-null
507             if (props == null) {
508                 props = (Set<Property>) new HashSet();
509             } else {
510                 // Copy the set so noone is going to change the content
511                 props = (Set<Property>) new HashSet(props);
512             }
513
514             // Now lets remove the creation property if exist in the
515             // new props
516             for (Iterator<Property> i = props.iterator(); i.hasNext();) {
517                 Property prop = i.next();
518                 if (prop instanceof TimeStamp) {
519                     TimeStamp t = (TimeStamp) prop;
520                     if (t.getTimeStampName().equals("creation")) {
521                         i.remove();
522                     }
523                 }
524             }
525
526             // Now lets add the creation timestamp in it
527             if (tc != null) {
528                 props.add(tc);
529             }
530
531             // Finally update
532             this.edgesDB.put(e, props);
533             break;
534         }
535
536         // Now update the listeners
537         for (ITopologyManagerAware s : this.topologyManagerAware) {
538             try {
539                 s.edgeUpdate(e, type, props);
540             } catch (Exception exc) {
541                 log.error("Exception on callback", exc);
542             }
543         }
544     }
545
546     private Edge getReverseLinkTuple(TopologyUserLinkConfig link) {
547                 TopologyUserLinkConfig rLink = new TopologyUserLinkConfig(
548                                 link.getName(), link.getDstNodeIDType(), link.getDstSwitchId(),
549                                 link.getDstNodeConnectorIDType(), link.getDstPort(),
550                                 link.getSrcNodeIDType(), link.getSrcSwitchId(),
551                                 link.getSrcNodeConnectorIDType(), link.getSrcPort());
552         return getLinkTuple(rLink);
553     }
554
555     private Edge getLinkTuple(TopologyUserLinkConfig link) {
556         Edge linkTuple = null;
557
558         // if atleast 1 link exists for the srcPort and atleast 1 link exists for the dstPort
559         // that makes it ineligible for the Manual link addition
560         // This is just an extra protection to avoid mis-programming.
561         boolean srcLinkExists = false;
562         boolean dstLinkExists = false;
563         //TODO check a way to validate the port with inventory services
564         //if (srcSw.getPorts().contains(srcPort) &&
565         //dstSw.getPorts().contains(srcPort) &&
566         if (!srcLinkExists && !dstLinkExists) {
567             Node sNode = null;
568             Node dNode = null;
569             NodeConnector sPort = null;
570             NodeConnector dPort = null;
571             linkTuple = null;
572             String srcNodeIDType = link.getSrcNodeIDType();
573             String srcNodeConnectorIDType = link.getSrcNodeConnectorIDType();
574             String dstNodeIDType = link.getDstNodeIDType();
575             String dstNodeConnectorIDType = link.getDstNodeConnectorIDType();
576             try {
577                 if (srcNodeIDType.equals(NodeIDType.OPENFLOW)) {
578                     sNode = new Node(srcNodeIDType, link.getSrcSwitchIDLong());
579                 } else {
580                     sNode = new Node(srcNodeIDType, link.getSrcSwitchId());                     
581                 }
582
583                 if (dstNodeIDType.equals(NodeIDType.OPENFLOW)) {
584                     dNode = new Node(dstNodeIDType, link.getDstSwitchIDLong());
585                 } else {
586                     dNode = new Node(dstNodeIDType, link.getDstSwitchId());                     
587                 }
588         
589                 if (srcNodeConnectorIDType.equals(NodeConnectorIDType.OPENFLOW)) {
590                     Short srcPort = Short.valueOf((short) 0);
591                                 if (!link.isSrcPortByName()) {
592                                         srcPort = Short.parseShort(link.getSrcPort());
593                                 }
594                                         sPort = new NodeConnector(srcNodeConnectorIDType, 
595                                                         srcPort, sNode);
596                 } else {
597                                 sPort = new NodeConnector(srcNodeConnectorIDType,
598                                                 link.getSrcPort(), sNode);                      
599                 }
600
601                 if (dstNodeConnectorIDType.equals(NodeConnectorIDType.OPENFLOW)) {
602                     Short dstPort = Short.valueOf((short) 0);
603                                 if (!link.isDstPortByName()) {
604                             dstPort = Short.parseShort(link.getDstPort());
605                         }
606                                         dPort = new NodeConnector(dstNodeConnectorIDType,
607                                                         dstPort, dNode);
608                 } else {
609                                         dPort = new NodeConnector(dstNodeConnectorIDType,
610                                                         link.getDstPort(), dNode);
611                 }
612                 linkTuple = new Edge(sPort, dPort);
613             } catch (ConstructionException cex) {
614                 log.warn("Caught exception ", cex);
615             }
616             return linkTuple;
617         }
618
619         if (srcLinkExists && dstLinkExists) {
620             link.setStatus(TopologyUserLinkConfig.STATUS.INCORRECT);
621         }
622         return null;
623     }
624
625     @Override
626     public ConcurrentMap<String, TopologyUserLinkConfig> getUserLinks() {
627         return userLinks;
628     }
629
630     @Override
631     public Status addUserLink(TopologyUserLinkConfig link) {
632         if (!link.isValid()) {
633             return new Status(StatusCode.BADREQUEST, 
634                         "Configuration Invalid. Please check the parameters");
635         }
636         if (userLinks.get(link.getName()) != null) {
637             return new Status(StatusCode.CONFLICT, 
638                         "Link with name : " + link.getName()
639                     + " already exists. Please use another name");
640         }
641         if (userLinks.containsValue(link)) {
642             return new Status(StatusCode.CONFLICT, "Link configuration exists");
643         }
644
645         link.setStatus(TopologyUserLinkConfig.STATUS.LINKDOWN);
646         userLinks.put(link.getName(), link);
647
648         Edge linkTuple = getLinkTuple(link);
649         if (linkTuple != null) {
650             try {
651                 linkTuple = getReverseLinkTuple(link);
652                 link.setStatus(TopologyUserLinkConfig.STATUS.SUCCESS);
653             } catch (Exception e) {
654                 return new Status(StatusCode.INTERNALERROR,
655                                 "Exception while adding custom link : " + 
656                                                 e.getMessage());
657             }
658         }
659         return new Status(StatusCode.SUCCESS, null);
660     }
661
662     @Override
663     public Status deleteUserLink(String linkName) {
664         if (linkName == null) {
665             return new Status(StatusCode.BADREQUEST, 
666                         "A valid linkName is required to Delete a link");
667         }
668
669         TopologyUserLinkConfig link = userLinks.get(linkName);
670
671         Edge linkTuple = getLinkTuple(link);
672         userLinks.remove(linkName);
673         if (linkTuple != null) {
674             try {
675                 //oneTopology.deleteUserConfiguredLink(linkTuple);
676             } catch (Exception e) {
677                 log
678                         .warn("Harmless : Exception while Deleting User Configured link "
679                                 + link + " " + e.toString());
680             }
681             linkTuple = getReverseLinkTuple(link);
682             try {
683                 //oneTopology.deleteUserConfiguredLink(linkTuple);
684             } catch (Exception e) {
685                 log
686                         .error("Harmless : Exception while Deleting User Configured Reverse link "
687                                 + link + " " + e.toString());
688             }
689         }
690         return new Status(StatusCode.SUCCESS, null);
691     }
692
693     private void registerWithOSGIConsole() {
694         BundleContext bundleContext = FrameworkUtil.getBundle(this.getClass())
695                 .getBundleContext();
696         bundleContext.registerService(CommandProvider.class.getName(), this,
697                 null);
698     }
699
700     @Override
701     public String getHelp() {
702         StringBuffer help = new StringBuffer();
703         help.append("---Topology Manager---\n");
704                 help.append("\t addTopo name <NodeIDType> <src-sw-id> <NodeConnectorIDType> <port-number> <NodeIDType> <dst-sw-id> <NodeConnectorIDType> <port-number>\n");
705         help.append("\t delTopo name\n");
706         help.append("\t printTopo\n");
707         help.append("\t printNodeEdges\n");
708         return help.toString();
709     }
710
711     public void _printTopo(CommandInterpreter ci) {
712         for (String name : this.userLinks.keySet()) {
713                 TopologyUserLinkConfig linkConfig = userLinks.get(name);
714             ci.println("Name : " + name);
715             ci.println(linkConfig);
716             ci.println("Edge " +  getLinkTuple(linkConfig));
717             ci.println("Reverse Edge " +  getReverseLinkTuple(linkConfig));
718         }
719     }
720
721     public void _addTopo(CommandInterpreter ci) {
722         String name = ci.nextArgument();
723         if ((name == null)) {
724             ci.println("Please enter a valid Name");
725             return;
726         }
727
728         String srcNodeIDType = ci.nextArgument();
729         if (srcNodeIDType == null) {
730             ci.println("Null source node ID Type. Example: OF or PR");
731             return;
732         }
733
734         String dpid = ci.nextArgument();
735         if (dpid == null) {
736             ci.println("Null source ndoe id");
737             return;
738         }
739
740         String srcNodeConnectorIDType = ci.nextArgument();
741         if (srcNodeConnectorIDType == null) {
742             ci.println("Null source node connector ID Type. Example: OF or PR");
743             return;
744         }
745
746         String port = ci.nextArgument();
747         if (port == null) {
748             ci.println("Null source port number");
749             return;
750         }
751
752         String dstNodeIDType = ci.nextArgument();
753         if (dstNodeIDType == null) {
754             ci.println("Null destination node ID Type. Example: OF or PR");
755             return;
756         }
757
758         String ddpid = ci.nextArgument();
759         if (ddpid == null) {
760             ci.println("Null destination node ID");
761             return;
762         }
763
764         String dstNodeConnectorIDType = ci.nextArgument();
765         if (dstNodeConnectorIDType == null) {
766             ci.println("Null destination node connector ID Type. Example: OF or PR");
767             return;
768         }
769
770         String dport = ci.nextArgument();
771         if (dport == null) {
772             ci.println("Null destination port number");
773             return;
774         }
775                 TopologyUserLinkConfig config = new TopologyUserLinkConfig(name,
776                                 srcNodeIDType, dpid, srcNodeConnectorIDType, port,
777                                 dstNodeIDType, ddpid, dstNodeConnectorIDType, dport);
778         ci.println(this.addUserLink(config));
779     }
780
781     public void _delTopo(CommandInterpreter ci) {
782         String name = ci.nextArgument();
783         if ((name == null)) {
784             ci.println("Please enter a valid Name");
785             return;
786         }
787         this.deleteUserLink(name);
788     }
789
790     public void _printNodeEdges(CommandInterpreter ci) {
791         Map<Node, Set<Edge>> nodeEdges = getNodeEdges();        
792         if (nodeEdges == null) {
793                 return;
794         }
795         Set<Node> nodeSet = nodeEdges.keySet();
796         if (nodeSet == null) {
797                 return;
798         }
799         ci.println("        Node                                         Edge");
800         for (Node node : nodeSet) {
801                 Set<Edge> edgeSet = nodeEdges.get(node);
802                 if (edgeSet == null) {
803                         continue;
804                 }
805                 for (Edge edge : edgeSet) {
806                         ci.println(node + "             " + edge);
807                 }
808         }
809     }
810
811     @Override
812     public Object readObject(ObjectInputStream ois)
813             throws FileNotFoundException, IOException, ClassNotFoundException {
814         // TODO Auto-generated method stub
815         return ois.readObject();
816     }
817
818     @Override
819     public Status saveConfiguration() {
820         return saveConfig();
821     }
822
823     @Override
824     public void edgeOverUtilized(Edge edge) {
825         log.warn("Link Utilization above normal: " + edge);
826     }
827
828     @Override
829     public void edgeUtilBackToNormal(Edge edge) {
830         log.warn("Link Utilization back to normal: " + edge);
831     }
832
833 }