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