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