4c4adf047853410d325b5d67fad2c197ef66866e
[controller.git] / opendaylight / switchmanager / implementation / src / main / java / org / opendaylight / controller / switchmanager / internal / SwitchManager.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.switchmanager.internal;
10
11 import java.io.FileNotFoundException;
12 import java.io.IOException;
13 import java.io.ObjectInputStream;
14 import java.net.InetAddress;
15 import java.net.NetworkInterface;
16 import java.net.SocketException;
17 import java.util.ArrayList;
18 import java.util.Collections;
19 import java.util.Date;
20 import java.util.Dictionary;
21 import java.util.EnumSet;
22 import java.util.Enumeration;
23 import java.util.HashMap;
24 import java.util.HashSet;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.Set;
28 import java.util.concurrent.ConcurrentHashMap;
29 import java.util.concurrent.ConcurrentMap;
30 import java.util.concurrent.CopyOnWriteArrayList;
31
32 import org.apache.felix.dm.Component;
33 import org.eclipse.osgi.framework.console.CommandInterpreter;
34 import org.eclipse.osgi.framework.console.CommandProvider;
35 import org.opendaylight.controller.clustering.services.CacheConfigException;
36 import org.opendaylight.controller.clustering.services.CacheExistException;
37 import org.opendaylight.controller.clustering.services.ICacheUpdateAware;
38 import org.opendaylight.controller.clustering.services.IClusterContainerServices;
39 import org.opendaylight.controller.clustering.services.IClusterServices;
40 import org.opendaylight.controller.configuration.IConfigurationContainerAware;
41 import org.opendaylight.controller.sal.core.Bandwidth;
42 import org.opendaylight.controller.sal.core.Config;
43 import org.opendaylight.controller.sal.core.ConstructionException;
44 import org.opendaylight.controller.sal.core.Description;
45 import org.opendaylight.controller.sal.core.ForwardingMode;
46 import org.opendaylight.controller.sal.core.MacAddress;
47 import org.opendaylight.controller.sal.core.Name;
48 import org.opendaylight.controller.sal.core.Node;
49 import org.opendaylight.controller.sal.core.NodeConnector;
50 import org.opendaylight.controller.sal.core.NodeConnector.NodeConnectorIDType;
51 import org.opendaylight.controller.sal.core.Property;
52 import org.opendaylight.controller.sal.core.State;
53 import org.opendaylight.controller.sal.core.Tier;
54 import org.opendaylight.controller.sal.core.UpdateType;
55 import org.opendaylight.controller.sal.inventory.IInventoryService;
56 import org.opendaylight.controller.sal.inventory.IListenInventoryUpdates;
57 import org.opendaylight.controller.sal.utils.GlobalConstants;
58 import org.opendaylight.controller.sal.utils.HexEncode;
59 import org.opendaylight.controller.sal.utils.IObjectReader;
60 import org.opendaylight.controller.sal.utils.ObjectReader;
61 import org.opendaylight.controller.sal.utils.ObjectWriter;
62 import org.opendaylight.controller.sal.utils.Status;
63 import org.opendaylight.controller.sal.utils.StatusCode;
64 import org.opendaylight.controller.switchmanager.IInventoryListener;
65 import org.opendaylight.controller.switchmanager.ISpanAware;
66 import org.opendaylight.controller.switchmanager.ISwitchManager;
67 import org.opendaylight.controller.switchmanager.ISwitchManagerAware;
68 import org.opendaylight.controller.switchmanager.SpanConfig;
69 import org.opendaylight.controller.switchmanager.Subnet;
70 import org.opendaylight.controller.switchmanager.SubnetConfig;
71 import org.opendaylight.controller.switchmanager.Switch;
72 import org.opendaylight.controller.switchmanager.SwitchConfig;
73 import org.osgi.framework.BundleContext;
74 import org.osgi.framework.FrameworkUtil;
75 import org.slf4j.Logger;
76 import org.slf4j.LoggerFactory;
77
78 /**
79  * The class describes SwitchManager which is the central repository of all the
80  * inventory data including nodes, node connectors, properties attached, Layer3
81  * configurations, Span configurations, node configurations, network device
82  * representations viewed by Controller Web applications. One SwitchManager
83  * instance per container of the network. All the node/nodeConnector properties
84  * are maintained in the default container only.
85  */
86 public class SwitchManager implements ISwitchManager,
87 IConfigurationContainerAware, IObjectReader,
88 ICacheUpdateAware<Long, String>, IListenInventoryUpdates,
89 CommandProvider {
90     private static Logger log = LoggerFactory.getLogger(SwitchManager.class);
91     private static String ROOT = GlobalConstants.STARTUPHOME.toString();
92     private static final String SAVE = "Save";
93     private String subnetFileName, spanFileName, switchConfigFileName;
94     private final List<NodeConnector> spanNodeConnectors = new CopyOnWriteArrayList<NodeConnector>();
95     // Collection of Subnets keyed by the InetAddress
96     private ConcurrentMap<InetAddress, Subnet> subnets;
97     private ConcurrentMap<String, SubnetConfig> subnetsConfigList;
98     private ConcurrentMap<SpanConfig, SpanConfig> spanConfigList;
99     // manually configured parameters for the node such as name, tier, mode
100     private ConcurrentMap<String, SwitchConfig> nodeConfigList;
101     private ConcurrentMap<Long, String> configSaveEvent;
102     private ConcurrentMap<Node, Map<String, Property>> nodeProps;
103     private ConcurrentMap<NodeConnector, Map<String, Property>> nodeConnectorProps;
104     private ConcurrentMap<Node, Map<String, NodeConnector>> nodeConnectorNames;
105     private ConcurrentMap<String, Property> controllerProps;
106     private IInventoryService inventoryService;
107     private final Set<ISwitchManagerAware> switchManagerAware = Collections
108             .synchronizedSet(new HashSet<ISwitchManagerAware>());
109     private final Set<IInventoryListener> inventoryListeners = Collections
110             .synchronizedSet(new HashSet<IInventoryListener>());
111     private final Set<ISpanAware> spanAware = Collections.synchronizedSet(new HashSet<ISpanAware>());
112     private static boolean hostRefresh = true;
113     private int hostRetryCount = 5;
114     private IClusterContainerServices clusterContainerService = null;
115     private String containerName = null;
116     private boolean isDefaultContainer = true;
117     private static final int REPLACE_RETRY = 1;
118
119     public void notifySubnetChange(Subnet sub, boolean add) {
120         synchronized (switchManagerAware) {
121             for (Object subAware : switchManagerAware) {
122                 try {
123                     ((ISwitchManagerAware) subAware).subnetNotify(sub, add);
124                 } catch (Exception e) {
125                     log.error("Failed to notify Subnet change {}",
126                             e.getMessage());
127                 }
128             }
129         }
130     }
131
132     public void notifySpanPortChange(Node node, List<NodeConnector> ports, boolean add) {
133         synchronized (spanAware) {
134             for (Object sa : spanAware) {
135                 try {
136                     ((ISpanAware) sa).spanUpdate(node, ports, add);
137                 } catch (Exception e) {
138                     log.error("Failed to notify Span Interface change {}",
139                             e.getMessage());
140                 }
141             }
142         }
143     }
144
145     private void notifyModeChange(Node node, boolean proactive) {
146         synchronized (switchManagerAware) {
147             for (ISwitchManagerAware service : switchManagerAware) {
148                 try {
149                     service.modeChangeNotify(node, proactive);
150                 } catch (Exception e) {
151                     log.error("Failed to notify Subnet change {}",
152                             e.getMessage());
153                 }
154             }
155         }
156     }
157
158     public void startUp() {
159         String container = this.getContainerName();
160         // Initialize configuration file names
161         subnetFileName = ROOT + "subnets_" + container + ".conf";
162         spanFileName = ROOT + "spanPorts_" + container + ".conf";
163         switchConfigFileName = ROOT + "switchConfig_" + container + ".conf";
164
165         // Instantiate cluster synced variables
166         allocateCaches();
167         retrieveCaches();
168
169         /*
170          * Read startup and build database if we have not already gotten the
171          * configurations synced from another node
172          */
173         if (subnetsConfigList.isEmpty()) {
174             loadSubnetConfiguration();
175         }
176         if (spanConfigList.isEmpty()) {
177             loadSpanConfiguration();
178         }
179         if (nodeConfigList.isEmpty()) {
180             loadSwitchConfiguration();
181         }
182
183         // Add controller MAC, if first node in the cluster
184         if (!controllerProps.containsKey(MacAddress.name)) {
185             byte controllerMac[] = getHardwareMAC();
186             if (controllerMac != null) {
187                 Property existing = controllerProps.putIfAbsent(MacAddress.name, new MacAddress(controllerMac));
188                 if (existing == null && log.isTraceEnabled()) {
189                     log.trace("Container {}: Setting controller MAC address in the cluster: {}", container,
190                             HexEncode.bytesToHexStringFormat(controllerMac));
191                 }
192             }
193         }
194     }
195
196     public void shutDown() {
197     }
198
199     @SuppressWarnings("deprecation")
200     private void allocateCaches() {
201         if (this.clusterContainerService == null) {
202             this.nonClusterObjectCreate();
203             log.warn("un-initialized clusterContainerService, can't create cache");
204             return;
205         }
206
207         try {
208             clusterContainerService.createCache(
209                     "switchmanager.subnetsConfigList",
210                     EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
211             clusterContainerService.createCache("switchmanager.spanConfigList",
212                     EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
213             clusterContainerService.createCache("switchmanager.nodeConfigList",
214                     EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
215             clusterContainerService.createCache("switchmanager.subnets",
216                     EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
217             clusterContainerService.createCache(
218                     "switchmanager.configSaveEvent",
219                     EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
220             clusterContainerService.createCache("switchmanager.nodeProps",
221                     EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
222             clusterContainerService.createCache(
223                     "switchmanager.nodeConnectorProps",
224                     EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
225             clusterContainerService.createCache(
226                     "switchmanager.nodeConnectorNames",
227                     EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
228             clusterContainerService.createCache(
229                     "switchmanager.controllerProps",
230                     EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
231         } catch (CacheConfigException cce) {
232             log.error("\nCache configuration invalid - check cache mode");
233         } catch (CacheExistException ce) {
234             log.error("\nCache already exits - destroy and recreate if needed");
235         }
236     }
237
238     @SuppressWarnings({ "unchecked", "deprecation" })
239     private void retrieveCaches() {
240         if (this.clusterContainerService == null) {
241             log.info("un-initialized clusterContainerService, can't create cache");
242             return;
243         }
244
245         subnetsConfigList = (ConcurrentMap<String, SubnetConfig>) clusterContainerService
246                 .getCache("switchmanager.subnetsConfigList");
247         if (subnetsConfigList == null) {
248             log.error("\nFailed to get cache for subnetsConfigList");
249         }
250
251         spanConfigList = (ConcurrentMap<SpanConfig, SpanConfig>) clusterContainerService
252                 .getCache("switchmanager.spanConfigList");
253         if (spanConfigList == null) {
254             log.error("\nFailed to get cache for spanConfigList");
255         }
256
257         nodeConfigList = (ConcurrentMap<String, SwitchConfig>) clusterContainerService
258                 .getCache("switchmanager.nodeConfigList");
259         if (nodeConfigList == null) {
260             log.error("\nFailed to get cache for nodeConfigList");
261         }
262
263         subnets = (ConcurrentMap<InetAddress, Subnet>) clusterContainerService
264                 .getCache("switchmanager.subnets");
265         if (subnets == null) {
266             log.error("\nFailed to get cache for subnets");
267         }
268
269         configSaveEvent = (ConcurrentMap<Long, String>) clusterContainerService
270                 .getCache("switchmanager.configSaveEvent");
271         if (configSaveEvent == null) {
272             log.error("\nFailed to get cache for configSaveEvent");
273         }
274
275         nodeProps = (ConcurrentMap<Node, Map<String, Property>>) clusterContainerService
276                 .getCache("switchmanager.nodeProps");
277         if (nodeProps == null) {
278             log.error("\nFailed to get cache for nodeProps");
279         }
280
281         nodeConnectorProps = (ConcurrentMap<NodeConnector, Map<String, Property>>) clusterContainerService
282                 .getCache("switchmanager.nodeConnectorProps");
283         if (nodeConnectorProps == null) {
284             log.error("\nFailed to get cache for nodeConnectorProps");
285         }
286
287         nodeConnectorNames = (ConcurrentMap<Node, Map<String, NodeConnector>>) clusterContainerService
288                 .getCache("switchmanager.nodeConnectorNames");
289         if (nodeConnectorNames == null) {
290             log.error("\nFailed to get cache for nodeConnectorNames");
291         }
292
293         controllerProps = (ConcurrentMap<String, Property>) clusterContainerService
294                 .getCache("switchmanager.controllerProps");
295         if (controllerProps == null) {
296             log.error("\nFailed to get cache for controllerProps");
297         }
298     }
299
300     private void nonClusterObjectCreate() {
301         subnetsConfigList = new ConcurrentHashMap<String, SubnetConfig>();
302         spanConfigList = new ConcurrentHashMap<SpanConfig, SpanConfig>();
303         nodeConfigList = new ConcurrentHashMap<String, SwitchConfig>();
304         subnets = new ConcurrentHashMap<InetAddress, Subnet>();
305         configSaveEvent = new ConcurrentHashMap<Long, String>();
306         nodeProps = new ConcurrentHashMap<Node, Map<String, Property>>();
307         nodeConnectorProps = new ConcurrentHashMap<NodeConnector, Map<String, Property>>();
308         nodeConnectorNames = new ConcurrentHashMap<Node, Map<String, NodeConnector>>();
309         controllerProps = new ConcurrentHashMap<String, Property>();
310     }
311
312     @Override
313     public List<SubnetConfig> getSubnetsConfigList() {
314         return new ArrayList<SubnetConfig>(subnetsConfigList.values());
315     }
316
317     @Override
318     public SubnetConfig getSubnetConfig(String subnet) {
319         return subnetsConfigList.get(subnet);
320     }
321
322     private List<SpanConfig> getSpanConfigList(Node node) {
323         List<SpanConfig> confList = new ArrayList<SpanConfig>();
324         String nodeId = node.toString();
325         for (SpanConfig conf : spanConfigList.values()) {
326             if (conf.matchNode(nodeId)) {
327                 confList.add(conf);
328             }
329         }
330         return confList;
331     }
332
333     public List<SwitchConfig> getNodeConfigList() {
334         return new ArrayList<SwitchConfig>(nodeConfigList.values());
335     }
336
337     @Override
338     public SwitchConfig getSwitchConfig(String switchId) {
339         return nodeConfigList.get(switchId);
340     }
341
342     public Switch getSwitchByNode(Node node) {
343         Switch sw = new Switch(node);
344         sw.setNode(node);
345         MacAddress mac = (MacAddress) this.getNodeProp(node,
346                 MacAddress.name);
347         if (mac != null) {
348             sw.setDataLayerAddress(mac.getMacAddress());
349         }
350         Set<NodeConnector> ncSet = getPhysicalNodeConnectors(node);
351         sw.setNodeConnectors(ncSet);
352
353         List<NodeConnector> ncList = new ArrayList<NodeConnector>();
354         for (NodeConnector nodeConnector : ncSet) {
355             if (spanNodeConnectors.contains(nodeConnector)) {
356                 ncList.add(nodeConnector);
357             }
358         }
359         sw.addSpanPorts(ncList);
360
361         return sw;
362     }
363
364     @Override
365     public List<Switch> getNetworkDevices() {
366         Set<Node> nodeSet = getNodes();
367         List<Switch> swList = new ArrayList<Switch>();
368         if (nodeSet != null) {
369             for (Node node : nodeSet) {
370                 swList.add(getSwitchByNode(node));
371             }
372         }
373
374         return swList;
375     }
376
377     private Status updateConfig(SubnetConfig conf, boolean add) {
378         if (add) {
379             if(subnetsConfigList.putIfAbsent(conf.getName(), conf) != null) {
380                 String msg = "Cluster conflict: Subnet with name " + conf.getName() + "already exists.";
381                 return new Status(StatusCode.CONFLICT, msg);
382             }
383         } else {
384             subnetsConfigList.remove(conf.getName());
385         }
386         return new Status(StatusCode.SUCCESS);
387     }
388
389     private Status updateDatabase(SubnetConfig conf, boolean add) {
390         if (add) {
391             Subnet subnetCurr = subnets.get(conf.getIPnum());
392             Subnet subnet;
393             if (subnetCurr == null) {
394                 subnet = new Subnet(conf);
395             } else {
396                 subnet = subnetCurr.clone();
397             }
398             // In case of API3 call we may receive the ports along with the
399             // subnet creation
400             if (!conf.isGlobal()) {
401                 Set<NodeConnector> sp = conf.getSubnetNodeConnectors();
402                 subnet.addNodeConnectors(sp);
403             }
404             boolean putNewSubnet = false;
405             if(subnetCurr == null) {
406                 if(subnets.putIfAbsent(conf.getIPnum(), subnet) == null) {
407                     putNewSubnet = true;
408                 }
409             } else {
410                 putNewSubnet = subnets.replace(conf.getIPnum(), subnetCurr, subnet);
411             }
412             if(!putNewSubnet) {
413                 String msg = "Cluster conflict: Conflict while adding the subnet " + conf.getIPnum();
414                 return new Status(StatusCode.CONFLICT, msg);
415             }
416
417         // Subnet removal case
418         } else {
419             subnets.remove(conf.getIPnum());
420         }
421         return new Status(StatusCode.SUCCESS);
422     }
423
424     private Status semanticCheck(SubnetConfig conf) {
425         Subnet newSubnet = new Subnet(conf);
426         Set<InetAddress> IPs = subnets.keySet();
427         if (IPs == null) {
428             return new Status(StatusCode.SUCCESS);
429         }
430         for (InetAddress i : IPs) {
431             Subnet existingSubnet = subnets.get(i);
432             if ((existingSubnet != null)
433                     && !existingSubnet.isMutualExclusive(newSubnet)) {
434                 return new Status(StatusCode.CONFLICT);
435             }
436         }
437         return new Status(StatusCode.SUCCESS);
438     }
439
440     private Status addRemoveSubnet(SubnetConfig conf, boolean isAdding) {
441         // Valid config check
442         if (!conf.isValidConfig()) {
443             String msg = "Invalid Subnet configuration";
444             log.warn(msg);
445             return new Status(StatusCode.BADREQUEST, msg);
446         }
447
448         if (isAdding) {
449             // Presence check
450             if (subnetsConfigList.containsKey(conf.getName())) {
451                 return new Status(StatusCode.CONFLICT,
452                         "Subnet with the specified name already configured.");
453             }
454             // Semantic check
455             Status rc = semanticCheck(conf);
456             if (!rc.isSuccess()) {
457                 return rc;
458             }
459         }
460
461         // Update Database
462         Status rc = updateDatabase(conf, isAdding);
463
464         if (rc.isSuccess()) {
465             // Update Configuration
466             rc = updateConfig(conf, isAdding);
467             if(!rc.isSuccess()) {
468                 updateDatabase(conf, (!isAdding));
469             }
470         }
471
472         return rc;
473     }
474
475     /**
476      * Adds Subnet configured in GUI or API3
477      */
478     @Override
479     public Status addSubnet(SubnetConfig conf) {
480         return this.addRemoveSubnet(conf, true);
481     }
482
483     @Override
484     public Status removeSubnet(SubnetConfig conf) {
485         return this.addRemoveSubnet(conf, false);
486     }
487
488     @Override
489     public Status removeSubnet(String name) {
490         SubnetConfig conf = subnetsConfigList.get(name);
491         if (conf == null) {
492             return new Status(StatusCode.SUCCESS, "Subnet not present");
493         }
494         return this.addRemoveSubnet(conf, false);
495     }
496
497     @Override
498     public Status addPortsToSubnet(String name, String switchPorts) {
499         SubnetConfig confCurr = subnetsConfigList.get(name);
500         if (confCurr == null) {
501             return new Status(StatusCode.NOTFOUND, "Subnet does not exist");
502         }
503         if (!confCurr.isValidSwitchPort(switchPorts)) {
504             return new Status(StatusCode.BADREQUEST, "Invalid switchports");
505         }
506
507         Subnet subCurr = subnets.get(confCurr.getIPnum());
508         if (subCurr == null) {
509             log.debug("Cluster conflict: Subnet entry {} is not present in the subnets cache.", confCurr.getIPnum());
510             return new Status(StatusCode.NOTFOUND, "Subnet does not exist");
511         }
512
513         // Update Database
514         Subnet sub = subCurr.clone();
515         Set<NodeConnector> sp = confCurr.getNodeConnectors(switchPorts);
516         sub.addNodeConnectors(sp);
517         boolean subnetsReplaced = subnets.replace(confCurr.getIPnum(), subCurr, sub);
518         if (!subnetsReplaced) {
519             String msg = "Cluster conflict: Conflict while adding ports to the subnet " + name;
520             return new Status(StatusCode.CONFLICT, msg);
521         }
522
523         // Update Configuration
524         SubnetConfig conf = confCurr.clone();
525         conf.addNodeConnectors(switchPorts);
526         boolean configReplaced = subnetsConfigList.replace(name, confCurr, conf);
527         if (!configReplaced) {
528             // TODO: recovery using Transactionality
529             String msg = "Cluster conflict: Conflict while adding ports to the subnet " + name;
530             return new Status(StatusCode.CONFLICT, msg);
531         }
532
533         return new Status(StatusCode.SUCCESS);
534     }
535
536     @Override
537     public Status removePortsFromSubnet(String name, String switchPorts) {
538         SubnetConfig confCurr = subnetsConfigList.get(name);
539         if (confCurr == null) {
540             return new Status(StatusCode.NOTFOUND, "Subnet does not exist");
541         }
542
543         Subnet subCurr = subnets.get(confCurr.getIPnum());
544         if (subCurr == null) {
545             log.debug("Cluster conflict: Subnet entry {} is not present in the subnets cache.", confCurr.getIPnum());
546             return new Status(StatusCode.NOTFOUND, "Subnet does not exist");
547         }
548
549         // Update Database
550         Subnet sub = subCurr.clone();
551         Set<NodeConnector> sp = confCurr.getNodeConnectors(switchPorts);
552         sub.deleteNodeConnectors(sp);
553         boolean subnetsReplace = subnets.replace(confCurr.getIPnum(), subCurr, sub);
554         if (!subnetsReplace) {
555             String msg = "Cluster conflict: Conflict while removing ports from the subnet " + name;
556             return new Status(StatusCode.CONFLICT, msg);
557         }
558
559         // Update Configuration
560         SubnetConfig conf = confCurr.clone();
561         conf.removeNodeConnectors(switchPorts);
562         boolean result = subnetsConfigList.replace(name, confCurr, conf);
563         if (!result) {
564             // TODO: recovery using Transactionality
565             String msg = "Cluster conflict: Conflict while removing ports from " + conf;
566             return new Status(StatusCode.CONFLICT, msg);
567         }
568
569         return new Status(StatusCode.SUCCESS);
570     }
571
572     public String getContainerName() {
573         if (containerName == null) {
574             return GlobalConstants.DEFAULT.toString();
575         }
576         return containerName;
577     }
578
579     @Override
580     public Subnet getSubnetByNetworkAddress(InetAddress networkAddress) {
581         Subnet sub;
582         Set<InetAddress> indices = subnets.keySet();
583         for (InetAddress i : indices) {
584             sub = subnets.get(i);
585             if (sub.isSubnetOf(networkAddress)) {
586                 return sub;
587             }
588         }
589         return null;
590     }
591
592     @Override
593     public Object readObject(ObjectInputStream ois)
594             throws FileNotFoundException, IOException, ClassNotFoundException {
595         // Perform the class deserialization locally, from inside the package
596         // where the class is defined
597         return ois.readObject();
598     }
599
600     @SuppressWarnings("unchecked")
601     private void loadSubnetConfiguration() {
602         ObjectReader objReader = new ObjectReader();
603         ConcurrentMap<String, SubnetConfig> confList = (ConcurrentMap<String, SubnetConfig>) objReader
604                 .read(this, subnetFileName);
605
606         if (confList == null) {
607             return;
608         }
609
610         for (SubnetConfig conf : confList.values()) {
611             addSubnet(conf);
612         }
613     }
614
615     @SuppressWarnings("unchecked")
616     private void loadSpanConfiguration() {
617         ObjectReader objReader = new ObjectReader();
618         ConcurrentMap<Integer, SpanConfig> confList = (ConcurrentMap<Integer, SpanConfig>) objReader
619                 .read(this, spanFileName);
620
621         if (confList == null) {
622             return;
623         }
624
625         for (SpanConfig conf : confList.values()) {
626             addSpanConfig(conf);
627         }
628     }
629
630     @SuppressWarnings("unchecked")
631     private void loadSwitchConfiguration() {
632         ObjectReader objReader = new ObjectReader();
633         ConcurrentMap<String, SwitchConfig> confList = (ConcurrentMap<String, SwitchConfig>) objReader
634                 .read(this, switchConfigFileName);
635
636         if (confList == null) {
637             return;
638         }
639
640         for (SwitchConfig conf : confList.values()) {
641             updateNodeConfig(conf);
642         }
643     }
644
645     @Override
646     public void updateSwitchConfig(SwitchConfig cfgObject) {
647         // update default container only
648         if (!isDefaultContainer) {
649             return;
650         }
651
652         SwitchConfig sc = nodeConfigList.get(cfgObject.getNodeId());
653         if (sc == null) {
654             if (nodeConfigList.putIfAbsent(cfgObject.getNodeId(), cfgObject) != null) {
655                 return;
656             }
657         } else {
658             if (!nodeConfigList.replace(cfgObject.getNodeId(), sc, cfgObject)) {
659                 return;
660             }
661         }
662
663         boolean modeChange = false;
664
665         if ((sc == null) || !cfgObject.getMode().equals(sc.getMode())) {
666             modeChange = true;
667         }
668
669         String nodeId = cfgObject.getNodeId();
670         Node node = Node.fromString(nodeId);
671         Map<String, Property> propMapCurr = nodeProps.get(node);
672         if (propMapCurr == null) {
673             return;
674         }
675         Map<String, Property> propMap = new HashMap<String, Property>(propMapCurr);
676         Property desc = new Description(cfgObject.getNodeDescription());
677         propMap.put(desc.getName(), desc);
678         Property tier = new Tier(Integer.parseInt(cfgObject.getTier()));
679         propMap.put(tier.getName(), tier);
680
681         if (!nodeProps.replace(node, propMapCurr, propMap)) {
682             // TODO rollback using Transactionality
683             return;
684         }
685
686         log.info("Set Node {}'s Mode to {}", nodeId, cfgObject.getMode());
687
688         if (modeChange) {
689             notifyModeChange(node, cfgObject.isProactive());
690         }
691     }
692
693     @Override
694     public Status updateNodeConfig(SwitchConfig switchConfig) {
695         Status status = switchConfig.validate();
696         if (!status.isSuccess()) {
697             return status;
698         }
699
700         Map<String, Property> updateProperties = switchConfig.getNodeProperties();
701         String nodeId = switchConfig.getNodeId();
702         ForwardingMode mode = (ForwardingMode) updateProperties.get(ForwardingMode.name);
703         if (mode != null) {
704             if (isDefaultContainer) {
705                 if (!mode.isValid()) {
706                     return new Status(StatusCode.BADREQUEST, "Invalid Forwarding Mode Value.");
707                 }
708             } else {
709                 return new Status(StatusCode.NOTACCEPTABLE,
710                         "Forwarding Mode modification is allowed only in default container");
711             }
712         }
713         boolean modeChange = false;
714         SwitchConfig sc = nodeConfigList.get(nodeId);
715         Map<String, Property> prevNodeProperties = new HashMap<String, Property>();
716         if (sc == null) {
717             if ((mode != null) && mode.isProactive()) {
718                 modeChange = true;
719             }
720             if (!updateProperties.isEmpty()) {
721                 if (nodeConfigList.putIfAbsent(nodeId, switchConfig) != null) {
722                     return new Status(StatusCode.CONFLICT, "Cluster conflict: Unable to update node configuration");
723                 }
724             }
725         } else {
726             prevNodeProperties = new HashMap<String, Property>(sc.getNodeProperties());
727             ForwardingMode prevMode = (ForwardingMode) sc.getProperty(ForwardingMode.name);
728             if (mode == null) {
729                 if ((prevMode != null) && (prevMode.isProactive())) {
730                     modeChange = true;
731                 }
732             } else {
733                 if (((prevMode != null) && (prevMode.getValue() != mode.getValue()))
734                         || (prevMode == null && mode.isProactive())) {
735                     modeChange = true;
736                 }
737             }
738             if (updateProperties.isEmpty()) {
739                 nodeConfigList.remove(nodeId);
740             } else {
741                 if (!nodeConfigList.replace(nodeId, sc, switchConfig)) {
742                     return new Status(StatusCode.CONFLICT, "Cluster conflict: Unable to update node configuration");
743                 }
744             }
745         }
746         Node node = Node.fromString(nodeId);
747         Map<String, Property> propMapCurr = nodeProps.get(node);
748         if (propMapCurr == null) {
749             return new Status(StatusCode.SUCCESS);
750         }
751         Map<String, Property> propMap = new HashMap<String, Property>(propMapCurr);
752         if (!prevNodeProperties.isEmpty()) {
753             for (String prop : prevNodeProperties.keySet()) {
754                 if (!updateProperties.containsKey(prop)) {
755                     if (prop.equals(Description.propertyName)) {
756                         Map<Node, Map<String, Property>> nodeProp = this.inventoryService.getNodeProps();
757                         if (nodeProp.get(node) != null) {
758                             propMap.put(Description.propertyName, nodeProp.get(node).get(Description.propertyName));
759                             continue;
760                         }
761                     }
762                     propMap.remove(prop);
763                 }
764             }
765         }
766         propMap.putAll(updateProperties);
767         if (!nodeProps.replace(node, propMapCurr, propMap)) {
768             // TODO rollback using Transactionality
769             return new Status(StatusCode.CONFLICT, "Cluster conflict: Unable to update node configuration.");
770         }
771         if (modeChange) {
772             notifyModeChange(node, (mode == null) ? false : mode.isProactive());
773         }
774         return new Status(StatusCode.SUCCESS);
775     }
776
777     @Override
778     public Status removeNodeConfig(String nodeId) {
779         if ((nodeId == null) || (nodeId.isEmpty())) {
780             return new Status(StatusCode.BADREQUEST, "nodeId cannot be empty.");
781         }
782         Map<String, Property> nodeProperties = getSwitchConfig(nodeId).getNodeProperties();
783         Node node = Node.fromString(nodeId);
784         Map<String, Property> propMapCurr = nodeProps.get(node);
785         if ((propMapCurr != null) && (nodeProperties != null) && (!nodeProperties.isEmpty())) {
786             Map<String, Property> propMap = new HashMap<String, Property>(propMapCurr);
787             for (String prop : nodeProperties.keySet()) {
788                 if (prop.equals(Description.propertyName)) {
789                     Map<Node, Map<String, Property>> nodeProp = this.inventoryService.getNodeProps();
790                     if (nodeProp.get(node) != null) {
791                         propMap.put(Description.propertyName, nodeProp.get(node).get(Description.propertyName));
792                         continue;
793                     }
794                 }
795                 propMap.remove(prop);
796             }
797             if (!nodeProps.replace(node, propMapCurr, propMap)) {
798                 return new Status(StatusCode.CONFLICT, "Cluster conflict: Unable to update node configuration.");
799             }
800         }
801         if (nodeConfigList != null) {
802             nodeConfigList.remove(nodeId);
803         }
804         return new Status(StatusCode.SUCCESS);
805     }
806
807     @Override
808     public Status saveSwitchConfig() {
809         // Publish the save config event to the cluster nodes
810         configSaveEvent.put(new Date().getTime(), SAVE);
811         return saveSwitchConfigInternal();
812     }
813
814     public Status saveSwitchConfigInternal() {
815         Status retS = null, retP = null;
816         ObjectWriter objWriter = new ObjectWriter();
817
818         retS = objWriter.write(new ConcurrentHashMap<String, SubnetConfig>(
819                 subnetsConfigList), subnetFileName);
820         retP = objWriter.write(new ConcurrentHashMap<SpanConfig, SpanConfig>(
821                 spanConfigList), spanFileName);
822         retS = objWriter.write(new ConcurrentHashMap<String, SwitchConfig>(
823                 nodeConfigList), switchConfigFileName);
824         if (retS.equals(retP)) {
825             if (retS.isSuccess()) {
826                 return retS;
827             } else {
828                 return new Status(StatusCode.INTERNALERROR, "Save failed");
829             }
830         } else {
831             return new Status(StatusCode.INTERNALERROR, "Partial save failure");
832         }
833     }
834
835     @Override
836     public List<SpanConfig> getSpanConfigList() {
837         return new ArrayList<SpanConfig>(spanConfigList.values());
838     }
839
840     @Override
841     public Status addSpanConfig(SpanConfig conf) {
842         // Valid config check
843         if (!conf.isValidConfig()) {
844             String msg = "Invalid Span configuration";
845             log.warn(msg);
846             return new Status(StatusCode.BADREQUEST, msg);
847         }
848
849         // Presence check
850         if (spanConfigList.containsKey(conf)) {
851             return new Status(StatusCode.CONFLICT, "Same span config exists");
852         }
853
854         // Update configuration
855         if (spanConfigList.putIfAbsent(conf, conf) == null) {
856             // Update database and notify clients
857             addSpanPorts(conf.getNode(), conf.getPortArrayList());
858         }
859
860         return new Status(StatusCode.SUCCESS);
861     }
862
863     @Override
864     public Status removeSpanConfig(SpanConfig conf) {
865         removeSpanPorts(conf.getNode(), conf.getPortArrayList());
866
867         // Update configuration
868         spanConfigList.remove(conf);
869
870         return new Status(StatusCode.SUCCESS);
871     }
872
873     @Override
874     public List<NodeConnector> getSpanPorts(Node node) {
875         List<NodeConnector> ncList = new ArrayList<NodeConnector>();
876
877         for (NodeConnector nodeConnector : spanNodeConnectors) {
878             if (nodeConnector.getNode().equals(node)) {
879                 ncList.add(nodeConnector);
880             }
881         }
882         return ncList;
883     }
884
885     @Override
886     public void entryCreated(Long key, String cacheName, boolean local) {
887     }
888
889     @Override
890     public void entryUpdated(Long key, String new_value, String cacheName,
891             boolean originLocal) {
892         saveSwitchConfigInternal();
893     }
894
895     @Override
896     public void entryDeleted(Long key, String cacheName, boolean originLocal) {
897     }
898
899     private void addNode(Node node, Set<Property> props) {
900         log.trace("{} added, props: {}", node, props);
901         if (nodeProps == null) {
902             return;
903         }
904
905         Map<String, Property> propMapCurr = nodeProps.get(node);
906         Map<String, Property> propMap = (propMapCurr == null) ? new HashMap<String, Property>()
907                 : new HashMap<String, Property>(propMapCurr);
908
909         // copy node properties from plugin
910         if (props != null) {
911             for (Property prop : props) {
912                 propMap.put(prop.getName(), prop);
913             }
914         }
915
916         // copy node properties from config
917         boolean proactiveForwarding = false;
918         if (nodeConfigList != null) {
919             String nodeId = node.toString();
920             SwitchConfig conf = nodeConfigList.get(nodeId);
921             if (conf != null && (conf.getNodeProperties() != null)) {
922                 Map<String, Property> nodeProperties = conf.getNodeProperties();
923                 propMap.putAll(nodeProperties);
924                 if (nodeProperties.get(ForwardingMode.name) != null) {
925                     ForwardingMode mode = (ForwardingMode) nodeProperties.get(ForwardingMode.name);
926                     proactiveForwarding = mode.isProactive();
927                 }
928             }
929         }
930
931         boolean result = false;
932         if (propMapCurr == null) {
933             if (nodeProps.putIfAbsent(node, propMap) == null) {
934                 result = true;
935             }
936         } else {
937             result = nodeProps.replace(node, propMapCurr, propMap);
938         }
939         if (!result) {
940             log.debug("Cluster conflict: Conflict while adding the node properties. Node: {}  Properties: {}",
941                     node.getID(), props);
942             addNodeProps(node, propMap);
943         }
944
945         // check if span ports are configed
946         addSpanPorts(node);
947
948         // notify node listeners
949         notifyNode(node, UpdateType.ADDED, propMap);
950
951         // notify proactive mode forwarding
952         if (proactiveForwarding) {
953             notifyModeChange(node, true);
954         }
955     }
956
957     private void removeNode(Node node) {
958         log.trace("{} removed", node);
959         if (nodeProps == null) {
960             return;
961         }
962         nodeProps.remove(node);
963
964         // check if span ports need to be cleaned up
965         removeSpanPorts(node);
966
967         /* notify node listeners */
968         notifyNode(node, UpdateType.REMOVED, null);
969     }
970
971     private void updateNode(Node node, Set<Property> props) {
972         log.trace("{} updated, props: {}", node, props);
973         if (nodeProps == null || !nodeProps.containsKey(node) ||
974                 props == null || props.isEmpty()) {
975             return;
976         }
977
978         Map<String, Property> propMapCurr = nodeProps.get(node);
979         Map<String, Property> propMap = (propMapCurr == null) ? new HashMap<String, Property>()
980                 : new HashMap<String, Property>(propMapCurr);
981
982         // copy node properties from plugin
983         String nodeId = node.toString();
984         for (Property prop : props) {
985             if (nodeConfigList != null) {
986                 SwitchConfig conf = nodeConfigList.get(nodeId);
987                 if (conf != null && (conf.getNodeProperties() != null)
988                         && conf.getNodeProperties().containsKey(prop.getName())) {
989                     continue;
990                 }
991             }
992             propMap.put(prop.getName(), prop);
993         }
994
995         if (propMapCurr == null) {
996             if (nodeProps.putIfAbsent(node, propMap) != null) {
997                 log.debug("Cluster conflict: Conflict while updating the node. Node: {}  Properties: {}",
998                         node.getID(), props);
999                 addNodeProps(node, propMap);
1000             }
1001         } else {
1002             if (!nodeProps.replace(node, propMapCurr, propMap)) {
1003                 log.debug("Cluster conflict: Conflict while updating the node. Node: {}  Properties: {}",
1004                         node.getID(), props);
1005                 addNodeProps(node, propMap);
1006             }
1007         }
1008
1009         /* notify node listeners */
1010         notifyNode(node, UpdateType.CHANGED, propMap);
1011     }
1012
1013     @Override
1014     public void updateNode(Node node, UpdateType type, Set<Property> props) {
1015         log.debug("updateNode: {} type {} props {} for container {}",
1016                 new Object[] { node, type, props, containerName });
1017         switch (type) {
1018         case ADDED:
1019             addNode(node, props);
1020             break;
1021         case CHANGED:
1022             updateNode(node, props);
1023             break;
1024         case REMOVED:
1025             removeNode(node);
1026             break;
1027         default:
1028             break;
1029         }
1030     }
1031
1032     @Override
1033     public void updateNodeConnector(NodeConnector nodeConnector,
1034             UpdateType type, Set<Property> props) {
1035         Map<String, Property> propMap = new HashMap<String, Property>();
1036
1037         log.debug("updateNodeConnector: {} type {} props {} for container {}",
1038                 new Object[] { nodeConnector, type, props, containerName });
1039
1040         if (nodeConnectorProps == null) {
1041             return;
1042         }
1043
1044         switch (type) {
1045         case ADDED:
1046         case CHANGED:
1047             if (props != null) {
1048                 for (Property prop : props) {
1049                     addNodeConnectorProp(nodeConnector, prop);
1050                     propMap.put(prop.getName(), prop);
1051                 }
1052             } else {
1053                 addNodeConnectorProp(nodeConnector, null);
1054             }
1055
1056             addSpanPort(nodeConnector);
1057             break;
1058         case REMOVED:
1059             removeNodeConnectorAllProps(nodeConnector);
1060
1061             // clean up span config
1062             removeSpanPort(nodeConnector);
1063             break;
1064         default:
1065             break;
1066         }
1067
1068         notifyNodeConnector(nodeConnector, type, propMap);
1069     }
1070
1071     @Override
1072     public Set<Node> getNodes() {
1073         return (nodeProps != null) ? new HashSet<Node>(nodeProps.keySet())
1074                 : null;
1075     }
1076
1077     /*
1078      * Returns a copy of a list of properties for a given node
1079      *
1080      * (non-Javadoc)
1081      *
1082      * @see
1083      * org.opendaylight.controller.switchmanager.ISwitchManager#getNodeProps
1084      * (org.opendaylight.controller.sal.core.Node)
1085      */
1086     @Override
1087     public Map<String, Property> getNodeProps(Node node) {
1088         Map<String, Property> rv = new HashMap<String, Property>();
1089         if (this.nodeProps != null) {
1090             rv = this.nodeProps.get(node);
1091             if (rv != null) {
1092                 /* make a copy of it */
1093                 rv = new HashMap<String, Property>(rv);
1094             }
1095         }
1096         return rv;
1097     }
1098
1099     @Override
1100     public Property getNodeProp(Node node, String propName) {
1101         Map<String, Property> propMap = getNodeProps(node);
1102         return (propMap != null) ? propMap.get(propName) : null;
1103     }
1104
1105     @Override
1106     public void setNodeProp(Node node, Property prop) {
1107
1108         for (int i = 0; i <= REPLACE_RETRY; i++) {
1109             /* Get a copy of the property map */
1110             Map<String, Property> propMapCurr = getNodeProps(node);
1111             if (propMapCurr == null) {
1112                 return;
1113             }
1114
1115             Map<String, Property> propMap = new HashMap<String, Property>(propMapCurr);
1116             propMap.put(prop.getName(), prop);
1117
1118             if (nodeProps.replace(node, propMapCurr, propMap)) {
1119                 return;
1120             }
1121             if (!propMapCurr.get(prop.getName()).equals(nodeProps.get(node).get(prop.getName()))) {
1122                 log.debug("Cluster conflict: Unable to add property {} to node {}.", prop.getName(), node.getID());
1123                 return;
1124             }
1125         }
1126         log.warn("Cluster conflict: Unable to add property {} to node {}.", prop.getName(), node.getID());
1127     }
1128
1129     @Override
1130     public Status removeNodeProp(Node node, String propName) {
1131         for (int i = 0; i <= REPLACE_RETRY; i++) {
1132             Map<String, Property> propMapCurr = getNodeProps(node);
1133             if (propMapCurr != null) {
1134                 if (!propMapCurr.containsKey(propName)) {
1135                     return new Status(StatusCode.SUCCESS);
1136                 }
1137                 Map<String, Property> propMap = new HashMap<String, Property>(propMapCurr);
1138                 propMap.remove(propName);
1139                 if (nodeProps.replace(node, propMapCurr, propMap)) {
1140                     return new Status(StatusCode.SUCCESS);
1141                 }
1142                 if (!propMapCurr.get(propName).equals(nodeProps.get(node).get(propName))) {
1143                     String msg = "Cluster conflict: Unable to remove property " + propName + " for node "
1144                             + node.getID();
1145                     return new Status(StatusCode.CONFLICT, msg);
1146                 }
1147
1148             } else {
1149                 return new Status(StatusCode.SUCCESS);
1150             }
1151         }
1152         String msg = "Cluster conflict: Unable to remove property " + propName + " for node " + node.getID();
1153         return new Status(StatusCode.CONFLICT, msg);
1154     }
1155
1156     @Override
1157     public Status removeNodeAllProps(Node node) {
1158         this.nodeProps.remove(node);
1159         return new Status(StatusCode.SUCCESS);
1160     }
1161
1162     @Override
1163     public Set<NodeConnector> getUpNodeConnectors(Node node) {
1164         if (nodeConnectorProps == null) {
1165             return null;
1166         }
1167
1168         Set<NodeConnector> nodeConnectorSet = new HashSet<NodeConnector>();
1169         for (NodeConnector nodeConnector : nodeConnectorProps.keySet()) {
1170             if (!nodeConnector.getNode().equals(node)) {
1171                 continue;
1172             }
1173             if (isNodeConnectorEnabled(nodeConnector)) {
1174                 nodeConnectorSet.add(nodeConnector);
1175             }
1176         }
1177
1178         return nodeConnectorSet;
1179     }
1180
1181     @Override
1182     public Set<NodeConnector> getNodeConnectors(Node node) {
1183         if (nodeConnectorProps == null) {
1184             return null;
1185         }
1186
1187         Set<NodeConnector> nodeConnectorSet = new HashSet<NodeConnector>();
1188         for (NodeConnector nodeConnector : nodeConnectorProps.keySet()) {
1189             if (!nodeConnector.getNode().equals(node)) {
1190                 continue;
1191             }
1192             nodeConnectorSet.add(nodeConnector);
1193         }
1194
1195         return nodeConnectorSet;
1196     }
1197
1198     @Override
1199     public Set<NodeConnector> getPhysicalNodeConnectors(Node node) {
1200         if (nodeConnectorProps == null) {
1201             return null;
1202         }
1203
1204         Set<NodeConnector> nodeConnectorSet = new HashSet<NodeConnector>();
1205         for (NodeConnector nodeConnector : nodeConnectorProps.keySet()) {
1206             if (!nodeConnector.getNode().equals(node)
1207                     || isSpecial(nodeConnector)) {
1208                 continue;
1209             }
1210             nodeConnectorSet.add(nodeConnector);
1211         }
1212
1213         return nodeConnectorSet;
1214     }
1215
1216     @Override
1217     public Map<String, Property> getNodeConnectorProps(NodeConnector nodeConnector) {
1218         Map<String, Property> rv = new HashMap<String, Property>();
1219         if (this.nodeConnectorProps != null) {
1220             rv = this.nodeConnectorProps.get(nodeConnector);
1221             if (rv != null) {
1222                 rv = new HashMap<String, Property>(rv);
1223             }
1224         }
1225         return rv;
1226     }
1227
1228     @Override
1229     public Property getNodeConnectorProp(NodeConnector nodeConnector,
1230             String propName) {
1231         Map<String, Property> propMap = getNodeConnectorProps(nodeConnector);
1232         return (propMap != null) ? propMap.get(propName) : null;
1233     }
1234
1235     private byte[] getHardwareMAC() {
1236         Enumeration<NetworkInterface> nis;
1237         byte[] macAddress = null;
1238
1239         try {
1240             nis = NetworkInterface.getNetworkInterfaces();
1241         } catch (SocketException e) {
1242             log.error("Failed to acquire controller MAC: ", e);
1243             return macAddress;
1244         }
1245
1246         while (nis.hasMoreElements()) {
1247             NetworkInterface ni = nis.nextElement();
1248             try {
1249                 macAddress = ni.getHardwareAddress();
1250             } catch (SocketException e) {
1251                 log.error("Failed to acquire controller MAC: ", e);
1252             }
1253             if (macAddress != null) {
1254                 break;
1255             }
1256         }
1257         if (macAddress == null) {
1258             log.warn("Failed to acquire controller MAC: No physical interface found");
1259             // This happens when running controller on windows VM, for example
1260             // Try parsing the OS command output
1261         }
1262         return macAddress;
1263     }
1264
1265     @Override
1266     public byte[] getControllerMAC() {
1267         MacAddress macProperty = (MacAddress)controllerProps.get(MacAddress.name);
1268         return (macProperty == null) ? null : macProperty.getMacAddress();
1269     }
1270
1271     @Override
1272     public boolean isHostRefreshEnabled() {
1273         return hostRefresh;
1274     }
1275
1276     @Override
1277     public int getHostRetryCount() {
1278         return hostRetryCount;
1279     }
1280
1281     @Override
1282     public NodeConnector getNodeConnector(Node node, String nodeConnectorName) {
1283         if (nodeConnectorNames == null) {
1284             return null;
1285         }
1286
1287         Map<String, NodeConnector> map = nodeConnectorNames.get(node);
1288         if (map == null) {
1289             return null;
1290         }
1291
1292         return map.get(nodeConnectorName);
1293     }
1294
1295     /**
1296      * Adds a node connector and its property if any
1297      *
1298      * @param nodeConnector
1299      *            {@link org.opendaylight.controller.sal.core.NodeConnector}
1300      * @param propName
1301      *            name of {@link org.opendaylight.controller.sal.core.Property}
1302      * @return success or failed reason
1303      */
1304     @Override
1305     public Status addNodeConnectorProp(NodeConnector nodeConnector,
1306             Property prop) {
1307         Map<String, Property> propMapCurr = getNodeConnectorProps(nodeConnector);
1308         Map<String, Property> propMap = (propMapCurr == null) ? new HashMap<String, Property>()
1309                 : new HashMap<String, Property>(propMapCurr);
1310
1311         String msg = "Cluster conflict: Unable to add NodeConnector Property.";
1312         // Just add the nodeConnector if prop is not available (in a non-default
1313         // container)
1314         if (prop == null) {
1315             if (propMapCurr == null) {
1316                 if (nodeConnectorProps.putIfAbsent(nodeConnector, propMap) != null) {
1317                     return new Status(StatusCode.CONFLICT, msg);
1318                 }
1319             } else {
1320                 if (!nodeConnectorProps.replace(nodeConnector, propMapCurr, propMap)) {
1321                     return new Status(StatusCode.CONFLICT, msg);
1322                 }
1323             }
1324             return new Status(StatusCode.SUCCESS);
1325         }
1326
1327         propMap.put(prop.getName(), prop);
1328         if (propMapCurr == null) {
1329             if (nodeConnectorProps.putIfAbsent(nodeConnector, propMap) != null) {
1330                 return new Status(StatusCode.CONFLICT, msg);
1331             }
1332         } else {
1333             if (!nodeConnectorProps.replace(nodeConnector, propMapCurr, propMap)) {
1334                 return new Status(StatusCode.CONFLICT, msg);
1335             }
1336         }
1337
1338         if (prop.getName().equals(Name.NamePropName)) {
1339             if (nodeConnectorNames != null) {
1340                 Node node = nodeConnector.getNode();
1341                 Map<String, NodeConnector> mapCurr = nodeConnectorNames.get(node);
1342                 Map<String, NodeConnector> map = new HashMap<String, NodeConnector>();
1343                 if (mapCurr != null) {
1344                     for (String s : mapCurr.keySet()) {
1345                         try {
1346                             map.put(s, new NodeConnector(mapCurr.get(s)));
1347                         } catch (ConstructionException e) {
1348                             e.printStackTrace();
1349                         }
1350                     }
1351                 }
1352
1353                 map.put(((Name) prop).getValue(), nodeConnector);
1354                 if (mapCurr == null) {
1355                     if (nodeConnectorNames.putIfAbsent(node, map) != null) {
1356                         // TODO: recovery using Transactionality
1357                         return new Status(StatusCode.CONFLICT, msg);
1358                     }
1359                 } else {
1360                     if (!nodeConnectorNames.replace(node, mapCurr, map)) {
1361                         // TODO: recovery using Transactionality
1362                         return new Status(StatusCode.CONFLICT, msg);
1363                     }
1364                 }
1365             }
1366         }
1367
1368         return new Status(StatusCode.SUCCESS);
1369     }
1370
1371     /**
1372      * Removes one property of a node connector
1373      *
1374      * @param nodeConnector
1375      *            {@link org.opendaylight.controller.sal.core.NodeConnector}
1376      * @param propName
1377      *            name of {@link org.opendaylight.controller.sal.core.Property}
1378      * @return success or failed reason
1379      */
1380     @Override
1381     public Status removeNodeConnectorProp(NodeConnector nodeConnector, String propName) {
1382         Map<String, Property> propMapCurr = getNodeConnectorProps(nodeConnector);
1383
1384         if (propMapCurr == null) {
1385             /* Nothing to remove */
1386             return new Status(StatusCode.SUCCESS);
1387         }
1388
1389         Map<String, Property> propMap = new HashMap<String, Property>(propMapCurr);
1390         propMap.remove(propName);
1391         boolean result = nodeConnectorProps.replace(nodeConnector, propMapCurr, propMap);
1392         String msg = "Cluster conflict: Unable to remove NodeConnector property.";
1393         if (!result) {
1394             return new Status(StatusCode.CONFLICT, msg);
1395         }
1396
1397         if (propName.equals(Name.NamePropName)) {
1398             if (nodeConnectorNames != null) {
1399                 Name name = ((Name) getNodeConnectorProp(nodeConnector, Name.NamePropName));
1400                 if (name != null) {
1401                     Node node = nodeConnector.getNode();
1402                     Map<String, NodeConnector> mapCurr = nodeConnectorNames.get(node);
1403                     if (mapCurr != null) {
1404                         Map<String, NodeConnector> map = new HashMap<String, NodeConnector>();
1405                         for (String s : mapCurr.keySet()) {
1406                             try {
1407                                 map.put(s, new NodeConnector(mapCurr.get(s)));
1408                             } catch (ConstructionException e) {
1409                                 e.printStackTrace();
1410                             }
1411                         }
1412                         map.remove(name.getValue());
1413                         if (!nodeConnectorNames.replace(node, mapCurr, map)) {
1414                             // TODO: recovery using Transactionality
1415                             return new Status(StatusCode.CONFLICT, msg);
1416                         }
1417                     }
1418                 }
1419             }
1420         }
1421
1422         return new Status(StatusCode.SUCCESS);
1423     }
1424
1425     /**
1426      * Removes all the properties of a node connector
1427      *
1428      * @param nodeConnector
1429      *            {@link org.opendaylight.controller.sal.core.NodeConnector}
1430      * @return success or failed reason
1431      */
1432     @Override
1433     public Status removeNodeConnectorAllProps(NodeConnector nodeConnector) {
1434         if (nodeConnectorNames != null) {
1435             Name name = ((Name) getNodeConnectorProp(nodeConnector, Name.NamePropName));
1436             if (name != null) {
1437                 Node node = nodeConnector.getNode();
1438                 Map<String, NodeConnector> mapCurr = nodeConnectorNames.get(node);
1439                 if (mapCurr != null) {
1440                     Map<String, NodeConnector> map = new HashMap<String, NodeConnector>();
1441                     for (String s : mapCurr.keySet()) {
1442                         try {
1443                             map.put(s, new NodeConnector(mapCurr.get(s)));
1444                         } catch (ConstructionException e) {
1445                             e.printStackTrace();
1446                         }
1447                     }
1448                     map.remove(name.getValue());
1449                     if (!nodeConnectorNames.replace(node, mapCurr, map)) {
1450                         log.warn("Cluster conflict: Unable remove Name property of nodeconnector {}, skip.",
1451                                 nodeConnector.getID());
1452                     }
1453                 }
1454
1455             }
1456         }
1457         nodeConnectorProps.remove(nodeConnector);
1458
1459         return new Status(StatusCode.SUCCESS);
1460     }
1461
1462     /**
1463      * Function called by the dependency manager when all the required
1464      * dependencies are satisfied
1465      *
1466      */
1467     void init(Component c) {
1468         Dictionary<?, ?> props = c.getServiceProperties();
1469         if (props != null) {
1470             this.containerName = (String) props.get("containerName");
1471             log.trace("Running containerName: {}", this.containerName);
1472         } else {
1473             // In the Global instance case the containerName is empty
1474             this.containerName = "";
1475         }
1476         isDefaultContainer = containerName.equals(GlobalConstants.DEFAULT
1477                 .toString());
1478
1479         startUp();
1480     }
1481
1482     /**
1483      * Function called by the dependency manager when at least one dependency
1484      * become unsatisfied or when the component is shutting down because for
1485      * example bundle is being stopped.
1486      *
1487      */
1488     void destroy() {
1489         shutDown();
1490     }
1491
1492     /**
1493      * Function called by dependency manager after "init ()" is called and after
1494      * the services provided by the class are registered in the service registry
1495      *
1496      */
1497     void start() {
1498         // OSGI console
1499         registerWithOSGIConsole();
1500     }
1501
1502     /**
1503      * Function called after registered the service in OSGi service registry.
1504      */
1505     void started() {
1506         // solicit for existing inventories
1507         getInventories();
1508     }
1509
1510     /**
1511      * Function called by the dependency manager before the services exported by
1512      * the component are unregistered, this will be followed by a "destroy ()"
1513      * calls
1514      *
1515      */
1516     void stop() {
1517     }
1518
1519     public void setInventoryService(IInventoryService service) {
1520         log.trace("Got inventory service set request {}", service);
1521         this.inventoryService = service;
1522
1523         // solicit for existing inventories
1524         getInventories();
1525     }
1526
1527     public void unsetInventoryService(IInventoryService service) {
1528         log.trace("Got a service UNset request");
1529         this.inventoryService = null;
1530
1531         // clear existing inventories
1532         clearInventories();
1533     }
1534
1535     public void setSwitchManagerAware(ISwitchManagerAware service) {
1536         log.trace("Got inventory service set request {}", service);
1537         if (this.switchManagerAware != null) {
1538             this.switchManagerAware.add(service);
1539         }
1540
1541         // bulk update for newly joined
1542         switchManagerAwareNotify(service);
1543     }
1544
1545     public void unsetSwitchManagerAware(ISwitchManagerAware service) {
1546         log.trace("Got a service UNset request");
1547         if (this.switchManagerAware != null) {
1548             this.switchManagerAware.remove(service);
1549         }
1550     }
1551
1552     public void setInventoryListener(IInventoryListener service) {
1553         log.trace("Got inventory listener set request {}", service);
1554         if (this.inventoryListeners != null) {
1555             this.inventoryListeners.add(service);
1556         }
1557
1558         // bulk update for newly joined
1559         bulkUpdateService(service);
1560     }
1561
1562     public void unsetInventoryListener(IInventoryListener service) {
1563         log.trace("Got a service UNset request");
1564         if (this.inventoryListeners != null) {
1565             this.inventoryListeners.remove(service);
1566         }
1567     }
1568
1569     public void setSpanAware(ISpanAware service) {
1570         log.trace("Got SpanAware set request {}", service);
1571         if (this.spanAware != null) {
1572             this.spanAware.add(service);
1573         }
1574
1575         // bulk update for newly joined
1576         spanAwareNotify(service);
1577     }
1578
1579     public void unsetSpanAware(ISpanAware service) {
1580         log.trace("Got a service UNset request");
1581         if (this.spanAware != null) {
1582             this.spanAware.remove(service);
1583         }
1584     }
1585
1586     void setClusterContainerService(IClusterContainerServices s) {
1587         log.trace("Cluster Service set");
1588         this.clusterContainerService = s;
1589     }
1590
1591     void unsetClusterContainerService(IClusterContainerServices s) {
1592         if (this.clusterContainerService == s) {
1593             log.trace("Cluster Service removed!");
1594             this.clusterContainerService = null;
1595         }
1596     }
1597
1598     private void getInventories() {
1599         if (inventoryService == null) {
1600             log.trace("inventory service not avaiable");
1601             return;
1602         }
1603
1604         Map<Node, Map<String, Property>> nodeProp = this.inventoryService.getNodeProps();
1605         for (Map.Entry<Node, Map<String, Property>> entry : nodeProp.entrySet()) {
1606             Node node = entry.getKey();
1607             log.debug("getInventories: {} added for container {}", new Object[] { node, containerName });
1608             Map<String, Property> propMap = entry.getValue();
1609             Set<Property> props = new HashSet<Property>();
1610             for (Property property : propMap.values()) {
1611                 props.add(property);
1612             }
1613             addNode(node, props);
1614         }
1615
1616         Map<NodeConnector, Map<String, Property>> nodeConnectorProp = this.inventoryService.getNodeConnectorProps();
1617         for (Map.Entry<NodeConnector, Map<String, Property>> entry : nodeConnectorProp.entrySet()) {
1618             Map<String, Property> propMap = entry.getValue();
1619             for (Property property : propMap.values()) {
1620                 addNodeConnectorProp(entry.getKey(), property);
1621             }
1622         }
1623     }
1624
1625     private void clearInventories() {
1626         nodeProps.clear();
1627         nodeConnectorProps.clear();
1628         nodeConnectorNames.clear();
1629         spanNodeConnectors.clear();
1630     }
1631
1632     private void notifyNode(Node node, UpdateType type,
1633             Map<String, Property> propMap) {
1634         synchronized (inventoryListeners) {
1635             for (IInventoryListener service : inventoryListeners) {
1636                 service.notifyNode(node, type, propMap);
1637             }
1638         }
1639     }
1640
1641     private void notifyNodeConnector(NodeConnector nodeConnector,
1642             UpdateType type, Map<String, Property> propMap) {
1643         synchronized (inventoryListeners) {
1644             for (IInventoryListener service : inventoryListeners) {
1645                 service.notifyNodeConnector(nodeConnector, type, propMap);
1646             }
1647         }
1648     }
1649
1650     /*
1651      * For those joined late, bring them up-to-date.
1652      */
1653     private void switchManagerAwareNotify(ISwitchManagerAware service) {
1654         for (Subnet sub : subnets.values()) {
1655             service.subnetNotify(sub, true);
1656         }
1657
1658         for (Node node : getNodes()) {
1659             SwitchConfig sc = getSwitchConfig(node.toString());
1660             if ((sc != null) && isDefaultContainer) {
1661                 ForwardingMode mode = (ForwardingMode) sc.getProperty(ForwardingMode.name);
1662                 service.modeChangeNotify(node, (mode == null) ? false : mode.isProactive());
1663             }
1664         }
1665     }
1666
1667     private void bulkUpdateService(IInventoryListener service) {
1668         Map<String, Property> propMap;
1669         UpdateType type = UpdateType.ADDED;
1670
1671         for (Node node : getNodes()) {
1672             propMap = nodeProps.get(node);
1673             service.notifyNode(node, type, propMap);
1674         }
1675
1676         for (NodeConnector nodeConnector : nodeConnectorProps.keySet()) {
1677             propMap = nodeConnectorProps.get(nodeConnector);
1678             service.notifyNodeConnector(nodeConnector, type, propMap);
1679         }
1680     }
1681
1682     private void spanAwareNotify(ISpanAware service) {
1683         for (Node node : getNodes()) {
1684             for (SpanConfig conf : getSpanConfigList(node)) {
1685                 service.spanUpdate(node, conf.getPortArrayList(), true);
1686             }
1687         }
1688     }
1689
1690     private void registerWithOSGIConsole() {
1691         BundleContext bundleContext = FrameworkUtil.getBundle(this.getClass())
1692                 .getBundleContext();
1693         bundleContext.registerService(CommandProvider.class.getName(), this,
1694                 null);
1695     }
1696
1697     @Override
1698     public Boolean isNodeConnectorEnabled(NodeConnector nodeConnector) {
1699         if (nodeConnector == null) {
1700             return false;
1701         }
1702
1703         Config config = (Config) getNodeConnectorProp(nodeConnector,
1704                 Config.ConfigPropName);
1705         State state = (State) getNodeConnectorProp(nodeConnector,
1706                 State.StatePropName);
1707         return ((config != null) && (config.getValue() == Config.ADMIN_UP)
1708                 && (state != null) && (state.getValue() == State.EDGE_UP));
1709     }
1710
1711     @Override
1712     public String getHelp() {
1713         StringBuffer help = new StringBuffer();
1714         help.append("---Switch Manager---\n");
1715         help.append("\t pns                    - Print connected nodes\n");
1716         help.append("\t pncs <node id>         - Print node connectors for a given node\n");
1717         help.append("\t pencs <node id>        - Print enabled node connectors for a given node\n");
1718         help.append("\t pdm <node id>          - Print switch ports in device map\n");
1719         help.append("\t snt <node id> <tier>   - Set node tier number\n");
1720         help.append("\t hostRefresh <on/off/?> - Enable/Disable/Query host refresh\n");
1721         help.append("\t hostRetry <count>      - Set host retry count\n");
1722         return help.toString();
1723     }
1724
1725     public void _pns(CommandInterpreter ci) {
1726         ci.println("           Node               Type           MAC            Name      Tier");
1727         if (nodeProps == null) {
1728             return;
1729         }
1730         Set<Node> nodeSet = nodeProps.keySet();
1731         if (nodeSet == null) {
1732             return;
1733         }
1734         List<String> nodeArray = new ArrayList<String>();
1735         for (Node node : nodeSet) {
1736             nodeArray.add(node.toString());
1737         }
1738         Collections.sort(nodeArray);
1739         for (String str: nodeArray) {
1740             Node node = Node.fromString(str);
1741             Description desc = ((Description) getNodeProp(node,
1742                     Description.propertyName));
1743             Tier tier = ((Tier) getNodeProp(node, Tier.TierPropName));
1744             String nodeName = (desc == null) ? "" : desc.getValue();
1745             MacAddress mac = (MacAddress) getNodeProp(node,
1746                     MacAddress.name);
1747             String macAddr = (mac == null) ? "" : HexEncode
1748                     .bytesToHexStringFormat(mac.getMacAddress());
1749             int tierNum = (tier == null) ? 0 : tier.getValue();
1750             ci.println(node + "     " + node.getType() + "     " + macAddr
1751                     + "     " + nodeName + "     " + tierNum);
1752         }
1753         ci.println("Total number of Nodes: " + nodeSet.size());
1754     }
1755
1756     public void _pencs(CommandInterpreter ci) {
1757         String st = ci.nextArgument();
1758         if (st == null) {
1759             ci.println("Please enter node id");
1760             return;
1761         }
1762
1763         Node node = Node.fromString(st);
1764         if (node == null) {
1765             ci.println("Please enter node id");
1766             return;
1767         }
1768
1769         Set<NodeConnector> nodeConnectorSet = getUpNodeConnectors(node);
1770         if (nodeConnectorSet == null) {
1771             return;
1772         }
1773         for (NodeConnector nodeConnector : nodeConnectorSet) {
1774             if (nodeConnector == null) {
1775                 continue;
1776             }
1777             ci.println(nodeConnector);
1778         }
1779         ci.println("Total number of NodeConnectors: " + nodeConnectorSet.size());
1780     }
1781
1782     public void _pncs(CommandInterpreter ci) {
1783         String st = ci.nextArgument();
1784         if (st == null) {
1785             ci.println("Please enter node id");
1786             return;
1787         }
1788
1789         Node node = Node.fromString(st);
1790         if (node == null) {
1791             ci.println("Please enter node id");
1792             return;
1793         }
1794
1795         ci.println("          NodeConnector               BandWidth(Gbps)     Admin     State");
1796         Set<NodeConnector> nodeConnectorSet = getNodeConnectors(node);
1797         if (nodeConnectorSet == null) {
1798             return;
1799         }
1800         for (NodeConnector nodeConnector : nodeConnectorSet) {
1801             if (nodeConnector == null) {
1802                 continue;
1803             }
1804             Map<String, Property> propMap = getNodeConnectorProps(nodeConnector);
1805             Bandwidth bw = (Bandwidth) propMap.get(Bandwidth.BandwidthPropName);
1806             Config config = (Config) propMap.get(Config.ConfigPropName);
1807             State state = (State) propMap.get(State.StatePropName);
1808             String out = nodeConnector + "           ";
1809             out += (bw != null) ? bw.getValue() / Math.pow(10, 9) : "    ";
1810             out += "             ";
1811             out += (config != null) ? config.getValue() : " ";
1812             out += "          ";
1813             out += (state != null) ? state.getValue() : " ";
1814             ci.println(out);
1815         }
1816         ci.println("Total number of NodeConnectors: " + nodeConnectorSet.size());
1817     }
1818
1819     public void _pdm(CommandInterpreter ci) {
1820         String st = ci.nextArgument();
1821         if (st == null) {
1822             ci.println("Please enter node id");
1823             return;
1824         }
1825
1826         Node node = Node.fromString(st);
1827         if (node == null) {
1828             ci.println("Please enter node id");
1829             return;
1830         }
1831
1832         Switch sw = getSwitchByNode(node);
1833
1834         ci.println("          NodeConnector                        Name");
1835         if (sw == null) {
1836             return;
1837         }
1838         Set<NodeConnector> nodeConnectorSet = sw.getNodeConnectors();
1839         String nodeConnectorName;
1840         if (nodeConnectorSet != null && nodeConnectorSet.size() > 0) {
1841             for (NodeConnector nodeConnector : nodeConnectorSet) {
1842                 Map<String, Property> propMap = getNodeConnectorProps(nodeConnector);
1843                 nodeConnectorName = (propMap == null) ? null : ((Name) propMap
1844                         .get(Name.NamePropName)).getValue();
1845                 if (nodeConnectorName != null) {
1846                     Node nd = nodeConnector.getNode();
1847                     if (!nd.equals(node)) {
1848                         log.debug("node not match {} {}", nd, node);
1849                     }
1850                     Map<String, NodeConnector> map = nodeConnectorNames
1851                             .get(node);
1852                     if (map != null) {
1853                         NodeConnector nc = map.get(nodeConnectorName);
1854                         if (nc == null) {
1855                             log.debug("no nodeConnector named {}",
1856                                     nodeConnectorName);
1857                         } else if (!nc.equals(nodeConnector)) {
1858                             log.debug("nodeConnector not match {} {}", nc,
1859                                     nodeConnector);
1860                         }
1861                     }
1862                 }
1863
1864                 ci.println(nodeConnector
1865                         + "            "
1866                         + ((nodeConnectorName == null) ? "" : nodeConnectorName)
1867                         + "(" + nodeConnector.getID() + ")");
1868             }
1869             ci.println("Total number of NodeConnectors: "
1870                     + nodeConnectorSet.size());
1871         }
1872     }
1873
1874     public void _snt(CommandInterpreter ci) {
1875         String st = ci.nextArgument();
1876         if (st == null) {
1877             ci.println("Please enter node id");
1878             return;
1879         }
1880
1881         Node node = Node.fromString(st);
1882         if (node == null) {
1883             ci.println("Please enter node id");
1884             return;
1885         }
1886
1887         st = ci.nextArgument();
1888         if (st == null) {
1889             ci.println("Please enter tier number");
1890             return;
1891         }
1892         Integer tid = Integer.decode(st);
1893         Tier tier = new Tier(tid);
1894         setNodeProp(node, tier);
1895     }
1896
1897     public void _hostRefresh(CommandInterpreter ci) {
1898         String mode = ci.nextArgument();
1899         if (mode == null) {
1900             ci.println("expecting on/off/?");
1901             return;
1902         }
1903         if (mode.toLowerCase().equals("on")) {
1904             hostRefresh = true;
1905         } else if (mode.toLowerCase().equals("off")) {
1906             hostRefresh = false;
1907         } else if (mode.equals("?")) {
1908             if (hostRefresh) {
1909                 ci.println("host refresh is ON");
1910             } else {
1911                 ci.println("host refresh is OFF");
1912             }
1913         } else {
1914             ci.println("expecting on/off/?");
1915         }
1916         return;
1917     }
1918
1919     public void _hostRetry(CommandInterpreter ci) {
1920         String retry = ci.nextArgument();
1921         if (retry == null) {
1922             ci.println("Please enter a valid number. Current retry count is "
1923                     + hostRetryCount);
1924             return;
1925         }
1926         try {
1927             hostRetryCount = Integer.parseInt(retry);
1928         } catch (Exception e) {
1929             ci.println("Please enter a valid number");
1930         }
1931         return;
1932     }
1933
1934     @Override
1935     public byte[] getNodeMAC(Node node) {
1936         MacAddress mac = (MacAddress) this.getNodeProp(node,
1937                 MacAddress.name);
1938         return (mac != null) ? mac.getMacAddress() : null;
1939     }
1940
1941     @Override
1942     public boolean isSpecial(NodeConnector p) {
1943         if (p.getType().equals(NodeConnectorIDType.CONTROLLER)
1944                 || p.getType().equals(NodeConnectorIDType.ALL)
1945                 || p.getType().equals(NodeConnectorIDType.SWSTACK)
1946                 || p.getType().equals(NodeConnectorIDType.HWPATH)) {
1947             return true;
1948         }
1949         return false;
1950     }
1951
1952     /*
1953      * Add span configuration to local cache and notify clients
1954      */
1955     private void addSpanPorts(Node node, List<NodeConnector> nodeConnectors) {
1956         List<NodeConnector> ncLists = new ArrayList<NodeConnector>();
1957
1958         for (NodeConnector nodeConnector : nodeConnectors) {
1959             if (!spanNodeConnectors.contains(nodeConnector)) {
1960                 ncLists.add(nodeConnector);
1961             }
1962         }
1963
1964         if (ncLists.size() > 0) {
1965             spanNodeConnectors.addAll(ncLists);
1966             notifySpanPortChange(node, ncLists, true);
1967         }
1968     }
1969
1970     private void addSpanPorts(Node node) {
1971         for (SpanConfig conf : getSpanConfigList(node)) {
1972             addSpanPorts(node, conf.getPortArrayList());
1973         }
1974     }
1975
1976     private void addSpanPort(NodeConnector nodeConnector) {
1977         // only add if span is configured on this nodeConnector
1978         for (SpanConfig conf : getSpanConfigList(nodeConnector.getNode())) {
1979             if (conf.getPortArrayList().contains(nodeConnector)) {
1980                 List<NodeConnector> ncLists = new ArrayList<NodeConnector>();
1981                 ncLists.add(nodeConnector);
1982                 addSpanPorts(nodeConnector.getNode(), ncLists);
1983                 return;
1984             }
1985         }
1986     }
1987
1988     /*
1989      * Remove span configuration to local cache and notify clients
1990      */
1991     private void removeSpanPorts(Node node, List<NodeConnector> nodeConnectors) {
1992         List<NodeConnector> ncLists = new ArrayList<NodeConnector>();
1993
1994         for (NodeConnector nodeConnector : nodeConnectors) {
1995             if (spanNodeConnectors.contains(nodeConnector)) {
1996                 ncLists.add(nodeConnector);
1997             }
1998         }
1999
2000         if (ncLists.size() > 0) {
2001             spanNodeConnectors.removeAll(ncLists);
2002             notifySpanPortChange(node, ncLists, false);
2003         }
2004     }
2005
2006     private void removeSpanPorts(Node node) {
2007         for (SpanConfig conf : getSpanConfigList(node)) {
2008             addSpanPorts(node, conf.getPortArrayList());
2009         }
2010     }
2011
2012     private void removeSpanPort(NodeConnector nodeConnector) {
2013         if (spanNodeConnectors.contains(nodeConnector)) {
2014             List<NodeConnector> ncLists = new ArrayList<NodeConnector>();
2015             ncLists.add(nodeConnector);
2016             removeSpanPorts(nodeConnector.getNode(), ncLists);
2017         }
2018     }
2019
2020     private void addNodeProps(Node node, Map<String, Property> propMap) {
2021         if (propMap == null) {
2022             propMap = new HashMap<String, Property>();
2023         }
2024         nodeProps.put(node, propMap);
2025     }
2026
2027     private void removeNodeProps(Node node) {
2028         if (getUpNodeConnectors(node).size() == 0) {
2029             nodeProps.remove(node);
2030         }
2031     }
2032
2033     @Override
2034     public Status saveConfiguration() {
2035         return saveSwitchConfig();
2036     }
2037
2038     /**
2039      * Creates a Name/Tier/Bandwidth Property object based on given property
2040      * name and value. Other property types are not supported yet.
2041      *
2042      * @param propName
2043      *            Name of the Property
2044      * @param propValue
2045      *            Value of the Property
2046      * @return {@link org.opendaylight.controller.sal.core.Property}
2047      */
2048     @Override
2049     public Property createProperty(String propName, String propValue) {
2050         if (propName == null) {
2051             log.debug("propName is null");
2052             return null;
2053         }
2054         if (propValue == null) {
2055             log.debug("propValue is null");
2056             return null;
2057         }
2058
2059         try {
2060             if (propName.equalsIgnoreCase(Description.propertyName)) {
2061                 return new Description(propValue);
2062             } else if (propName.equalsIgnoreCase(Tier.TierPropName)) {
2063                 int tier = Integer.parseInt(propValue);
2064                 return new Tier(tier);
2065             } else if (propName.equalsIgnoreCase(Bandwidth.BandwidthPropName)) {
2066                 long bw = Long.parseLong(propValue);
2067                 return new Bandwidth(bw);
2068             } else if (propName.equalsIgnoreCase(ForwardingMode.name)) {
2069                 int mode = Integer.parseInt(propValue);
2070                 return new ForwardingMode(mode);
2071             } else {
2072                 log.debug("Not able to create {} property", propName);
2073             }
2074         } catch (Exception e) {
2075             log.debug("createProperty caught exception {}", e.getMessage());
2076         }
2077
2078         return null;
2079     }
2080
2081     @Override
2082     public String getNodeDescription(Node node) {
2083         // Check first if user configured a name
2084         SwitchConfig config = getSwitchConfig(node.toString());
2085         if (config != null) {
2086             String configuredDesc = config.getNodeDescription();
2087             if (configuredDesc != null && !configuredDesc.isEmpty()) {
2088                 return configuredDesc;
2089             }
2090         }
2091
2092         // No name configured by user, get the node advertised name
2093         Description desc = (Description) getNodeProp(node,
2094                 Description.propertyName);
2095         return (desc == null /* || desc.getValue().equalsIgnoreCase("none") */) ? ""
2096                 : desc.getValue();
2097     }
2098 }