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