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