Merge "Split off tracking of node presence"
authorTony Tkacik <ttkacik@cisco.com>
Sat, 15 Feb 2014 01:36:41 +0000 (01:36 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Sat, 15 Feb 2014 01:36:41 +0000 (01:36 +0000)
19 files changed:
opendaylight/configuration/api/src/main/java/org/opendaylight/controller/configuration/IConfigurationContainerService.java
opendaylight/configuration/implementation/src/main/java/org/opendaylight/controller/configuration/internal/ConfigurationService.java
opendaylight/configuration/implementation/src/main/java/org/opendaylight/controller/configuration/internal/ContainerConfigurationService.java
opendaylight/containermanager/implementation/src/main/java/org/opendaylight/controller/containermanager/internal/ContainerManager.java
opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/ComponentActivator.xtend
opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/FlowProgrammerAdapter.xtend
opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/InventoryAndReadAdapter.xtend
opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/InventoryNotificationProvider.java [new file with mode: 0644]
opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/NodeConnectorDataChangeListener.java [new file with mode: 0644]
opendaylight/md-sal/inventory-manager/src/main/java/org/opendaylight/controller/md/inventory/manager/FlowCapableInventoryProvider.xtend
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentConnector.java
opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/routing/RoutingUtils.java
opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RpcProvisionRegistry.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerImpl.xtend
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/ConsumerContextImpl.xtend
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/MountPointImpl.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/RpcProvisionRegistryProxy.java
opendaylight/samples/simpleforwarding/src/main/java/org/opendaylight/controller/samples/simpleforwarding/internal/SimpleBroadcastHandlerImpl.java
opendaylight/switchmanager/implementation/src/main/java/org/opendaylight/controller/switchmanager/internal/SwitchManager.java

index 2123f6b9eb9c1004d6dcc2dd34cf26726168c153..ee571b83e1c9c4e919eb688f0f965ab633219b21 100644 (file)
@@ -13,4 +13,12 @@ package org.opendaylight.controller.configuration;
  * Container configuration service
  */
 public interface IConfigurationContainerService extends IConfigurationServiceCommon {
+
+    /**
+     * Bundle will call this function to ask ContainerConfigurationService to provide the
+     * directory location of container
+     *
+     * @return The path to active container directory
+     */
+    String getConfigurationRoot();
 }
index e4d55d11fb39e126d2dbb99f0ceb0cb6672d7069..4c0f3a2da5f08b409e6c751e9e8828359ce7e850 100644 (file)
@@ -9,6 +9,7 @@
 
 package org.opendaylight.controller.configuration.internal;
 
+import java.io.File;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.EnumSet;
@@ -25,6 +26,7 @@ import org.opendaylight.controller.clustering.services.IClusterServices;
 import org.opendaylight.controller.configuration.ConfigurationEvent;
 import org.opendaylight.controller.configuration.ConfigurationObject;
 import org.opendaylight.controller.configuration.IConfigurationAware;
+import org.opendaylight.controller.configuration.IConfigurationContainerService;
 import org.opendaylight.controller.configuration.IConfigurationService;
 import org.opendaylight.controller.sal.utils.GlobalConstants;
 import org.opendaylight.controller.sal.utils.IObjectReader;
@@ -46,7 +48,7 @@ public class ConfigurationService implements IConfigurationService, ICacheUpdate
     private static final Logger logger = LoggerFactory
             .getLogger(ConfigurationService.class);
     public static final String SAVE_EVENT_CACHE = "config.event.save";
-    private static final Object ROOT = GlobalConstants.STARTUPHOME.toString();
+    private static final String ROOT = GlobalConstants.STARTUPHOME.toString();
     private IClusterGlobalServices clusterServices;
     private ConcurrentMap <ConfigurationEvent, String> configEvent;
     private Set<IConfigurationAware> configurationAwareList = Collections
@@ -105,21 +107,66 @@ public class ConfigurationService implements IConfigurationService, ICacheUpdate
         return saveConfigurationsInternal();
     }
 
+
+    private List<String> getContainerDirectoryList() {
+        List<String> containerList = new ArrayList<String>();
+        for (IConfigurationAware configurationAware : this.configurationAwareList) {
+            if (configurationAware instanceof IConfigurationContainerService) {
+                String containerFilePath = ((ContainerConfigurationService)configurationAware).getConfigurationRoot();
+                containerList.add(containerFilePath);
+            }
+        }
+        return containerList;
+    }
+
+    private void createContainerDirectory(IConfigurationAware configurationAware) {
+        String containerFilePath = ((ContainerConfigurationService) configurationAware).getConfigurationRoot();
+        if (!new File(containerFilePath).exists()) {
+            boolean created = new File(containerFilePath).mkdir();
+            if (!created) {
+               logger.error("Failed to create startup config directory: {}", containerFilePath);
+            }
+        }
+    }
+
+    private void clearStaleContainerDirectories() {
+        List<String> activeContainers = getContainerDirectoryList();
+        for (File file : new File(ROOT).listFiles()) {
+            if (file.isDirectory() && !activeContainers.contains(file.toPath() + File.separator)) {
+                logger.trace("Removing directory for container {}", file.getName());
+                for (File innerFile : file.listFiles()) {
+                      innerFile.delete();
+                }
+                boolean removed = file.delete();
+                if (!removed) {
+                   logger.warn("Failed to remove stale directory: {}", file.getName());
+                }
+            }
+        }
+    }
+
+
     private Status saveConfigurationsInternal() {
         boolean success = true;
         for (IConfigurationAware configurationAware : configurationAwareList) {
+            if (configurationAware instanceof IConfigurationContainerService) {
+                // Create directory for new containers
+                createContainerDirectory(configurationAware);
+            }
             Status status = configurationAware.saveConfiguration();
             if (!status.isSuccess()) {
                 success = false;
-                logger.warn("Failed to save config for {}",
-                        configurationAware.getClass().getName());
+                logger.warn("Failed to save config for {}", configurationAware.getClass().getName());
             }
         }
+        // Remove startup directories of containers that were removed from
+        // the configuration but not saved
+        clearStaleContainerDirectories();
+
         if (success) {
             return new Status(StatusCode.SUCCESS);
         } else {
-            return new Status(StatusCode.INTERNALERROR,
-                    "Failed to Save All Configurations");
+            return new Status(StatusCode.INTERNALERROR, "Failed to Save All Configurations");
         }
     }
 
index 9c1d391daa7b8e80eec73ce454e30a6b768efe4d..3e067254edb721cd6e5b7adb109c1e96badbadb2 100644 (file)
@@ -9,7 +9,6 @@
 
 package org.opendaylight.controller.configuration.internal;
 
-import java.io.File;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Dictionary;
@@ -52,14 +51,10 @@ public class ContainerConfigurationService implements IConfigurationContainerSer
     private static final Logger logger = LoggerFactory.getLogger(ContainerConfigurationService.class);
     private IClusterContainerServices clusterServices;
     private ConcurrentMap <ConfigurationEvent, String> containerConfigEvent;
-    /*
-     * Collection containing the configuration objects.
-     * This is configuration world: container names (also the map key)
-     * are maintained as they were configured by user, same case
-     */
+    // Directory which contains the startup files for this container
+    private String root;
     private Set<IConfigurationContainerAware> configurationAwareList = Collections
             .synchronizedSet(new HashSet<IConfigurationContainerAware>());
-    private String root;
     private ObjectReader objReader;
     private ObjectWriter objWriter;
 
@@ -93,14 +88,9 @@ public class ContainerConfigurationService implements IConfigurationContainerSer
 
     void init(Component c) {
         Dictionary<?, ?> props = c.getServiceProperties();
-        String containerName = (props != null) ? (String) props.get("containerName") : GlobalConstants.DEFAULT.toString();
-        root = String.format("%s%s/", GlobalConstants.STARTUPHOME.toString(), containerName);
-        if (!new File(root).exists()) {
-            boolean created = new File(root).mkdir();
-            if (!created) {
-                logger.error("Failed to create startup config directory for container {}", containerName);
-            }
-        }
+        String containerName = (props != null) ? (String) props.get("containerName") :
+            GlobalConstants.DEFAULT.toString();
+        root =  String.format("%s%s/", GlobalConstants.STARTUPHOME.toString(), containerName);
     }
 
     public void start() {
@@ -119,17 +109,18 @@ public class ContainerConfigurationService implements IConfigurationContainerSer
      * Function called by the dependency manager before Container is Stopped and Destroyed.
      */
     public void containerStop() {
-        // Remove container directory along with its startup files
-        File[] files = new File(root).listFiles();
-        for (File file : files) {
-            file.delete();
-        }
-        new File(root).delete();
+        // Do nothing
+    }
+
+    @Override
+    public String getConfigurationRoot() {
+        return root;
     }
 
     @Override
     public Status saveConfiguration() {
         boolean success = true;
+
         for (IConfigurationContainerAware configurationAware : configurationAwareList) {
             logger.trace("Save Config triggered for {}", configurationAware.getClass().getSimpleName());
 
index ad897fd6899b01a2645aee018198fd0b8742129a..0fee183b67b8c1be06725b310c4111fbf3f9f8a8 100644 (file)
@@ -9,7 +9,6 @@
 
 package org.opendaylight.controller.containermanager.internal;
 
-import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.ObjectInputStream;
@@ -751,26 +750,6 @@ public class ContainerManager extends Authorization<String> implements IContaine
         return status;
     }
 
-    private void removeComponentsStartUpfiles(String containerName) {
-        String startupLocation = String.format("./%s", GlobalConstants.STARTUPHOME.toString());
-        String containerPrint = String.format("_%s.", containerName.toLowerCase(Locale.ENGLISH));
-
-        File directory = new File(startupLocation);
-        String[] fileList = directory.list();
-
-        logger.trace("Deleting startup configuration files for container {}", containerName);
-        if (fileList != null) {
-            for (String fileName : fileList) {
-                if (fileName.contains(containerPrint)) {
-                    String fullPath = String.format("%s/%s", startupLocation, fileName);
-                    File file = new File(fullPath);
-                    boolean done = file.delete();
-                    logger.trace("{} {}", (done ? "Deleted: " : "Failed to delete: "), fileName);
-                }
-            }
-        }
-    }
-
     /**
      * Create and initialize default all resource group and create association
      * with default well known users and profiles, if not already learnt from
@@ -1013,19 +992,6 @@ public class ContainerManager extends Authorization<String> implements IContaine
         notifyContainerModeChange(delete, notifyLocal);
         // Notify listeners
         notifyContainerAwareListeners(container, delete);
-
-        /*
-         * This is a quick fix until configuration service becomes the
-         * centralized configuration management place. Here container manager
-         * will remove the startup files for all the bundles that are present in
-         * the container being deleted. Do the cleanup here in Container manger
-         * as do not want to put this temporary code in Configuration manager
-         * yet which is ODL.
-         */
-        if (delete) {
-            // TODO: remove when Config Mgr takes over
-            removeComponentsStartUpfiles(containerName);
-        }
     }
 
     private void notifyContainerEntryChangeInternal(String containerName, List<NodeConnector> ncList, UpdateType update, boolean notifyLocal) {
index a6fc4b0a23b609e30452bda7f8879b26ee436d06..a59c2c1636514dba415dc933774ec4c6d16353cf 100644 (file)
@@ -251,6 +251,7 @@ package class SalCompatibilityProvider implements BindingAwareProvider {
         topology.dataService = session.getSALService(DataProviderService)
         tpProvider.dataService = session.getSALService(DataProviderService)
 
+        inventory.start();
 
         tpProvider.start();
 
index fac12ee10d642f3acb0cad9057c699e10d9446fd..8a0874ee3123da1d919db48a5d32e476afb839fc 100644 (file)
@@ -199,9 +199,11 @@ class FlowProgrammerAdapter implements IPluginInFlowProgrammerService, SalFlowLi
     }
 
     private def Future<RpcResult<TransactionStatus>> internalModifyFlowAsync(Node node, Flow oldFlow, Flow newFlow, long rid) {
-        val flowId = getCache().remove(oldFlow);
+        var flowId = getCache().remove(oldFlow);
         if(flowId == null){
-            throw new IllegalArgumentException("oldFlow is unknown");
+            LOG.error("oldFlow not found in cache : " + oldFlow.hashCode);
+            flowId = UUID.randomUUID();
+            getCache().put(oldFlow, flowId);
         }
 
         getCache().put(newFlow, flowId);
@@ -212,7 +214,9 @@ class FlowProgrammerAdapter implements IPluginInFlowProgrammerService, SalFlowLi
     private def Future<RpcResult<TransactionStatus>> internalRemoveFlowAsync(Node node, Flow adflow, long rid){
         val flowId = getCache().remove(adflow);
         if(flowId == null){
-            throw new IllegalArgumentException("adflow is unknown");
+            //throw new IllegalArgumentException("adflow not found in cache : " + adflow.hashCode);
+            LOG.error("adflow not found in cache : " + adflow.hashCode);
+            return null;
         }
         val flow = adflow.toMDFlow(flowId.toString());
         val modification = this._dataBrokerService.beginTransaction();
@@ -227,6 +231,10 @@ class FlowProgrammerAdapter implements IPluginInFlowProgrammerService, SalFlowLi
     }
 
     private def toFutureStatus(Future<RpcResult<TransactionStatus>> future){
+        if(future == null){
+            return toStatus(true);
+        }
+
         try {
             val result = future.get();
             return toStatus(result);
index 60e43247c2810383f49b05a24699d14c1c1f355b..0c211fd0aa432547071654bda94233d69e2496c0 100644 (file)
@@ -11,6 +11,9 @@ import java.util.ArrayList
 import java.util.Collections
 import java.util.List
 import java.util.Set
+import java.util.ArrayList;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.concurrent.locks.Lock;
 import java.util.concurrent.CopyOnWriteArrayList;
 import org.opendaylight.controller.sal.binding.api.data.DataBrokerService
 import org.opendaylight.controller.sal.binding.api.data.DataProviderService
@@ -76,17 +79,18 @@ import static extension org.opendaylight.controller.sal.compatibility.NodeMappin
 import org.opendaylight.controller.md.sal.binding.util.TypeSafeDataReader
 import java.util.concurrent.ConcurrentHashMap
 import java.util.Map
+import java.util.HashMap
 
 class InventoryAndReadAdapter implements IPluginInReadService,
-                                                                                        IPluginInInventoryService,
-                                                                                        OpendaylightInventoryListener,
-                                                                                        OpendaylightFlowStatisticsListener,
-                                                                                        OpendaylightFlowTableStatisticsListener,
-                                                                                        OpendaylightPortStatisticsListener {
+                                             IPluginInInventoryService,
+                                             OpendaylightInventoryListener,
+                                             OpendaylightFlowStatisticsListener,
+                                             OpendaylightFlowTableStatisticsListener,
+                                             OpendaylightPortStatisticsListener {
 
     private static val LOG = LoggerFactory.getLogger(InventoryAndReadAdapter);
 
-       private static val OPENFLOWV10_TABLE_ID = new Integer(0).shortValue;
+    private static val OPENFLOWV10_TABLE_ID = new Integer(0).shortValue;
     @Property
     DataBrokerService dataService;
 
@@ -111,21 +115,34 @@ class InventoryAndReadAdapter implements IPluginInReadService,
     @Property
     List<IPluginOutInventoryService> inventoryPublisher = new CopyOnWriteArrayList<IPluginOutInventoryService>();
 
-       def setInventoryPublisher(IPluginOutInventoryService listener){
+    private final InventoryNotificationProvider inventoryNotificationProvider = new InventoryNotificationProvider();
+
+    private final Map<InstanceIdentifier.PathArgument, List<InstanceIdentifier.PathArgument>> nodeToNodeConnectorsMap = new ConcurrentHashMap<InstanceIdentifier.PathArgument, List<InstanceIdentifier.PathArgument>>();
+
+    private final Lock nodeToNodeConnectorsLock = new ReentrantLock();
+
+
+    def start(){
+        inventoryNotificationProvider.dataProviderService = dataProviderService;
+        inventoryNotificationProvider.inventoryPublisher = inventoryPublisher;
+        // inventoryNotificationProvider.start();
+    }
+
+    def setInventoryPublisher(IPluginOutInventoryService listener){
         inventoryPublisher.add(listener);
-       }
+    }
 
-       def unsetInventoryPublisher(IPluginOutInventoryService listener){
+    def unsetInventoryPublisher(IPluginOutInventoryService listener){
         inventoryPublisher.remove(listener);
-       }
+    }
 
     def setReadPublisher(IPluginOutReadService listener) {
-       statisticsPublisher.add(listener);
+        statisticsPublisher.add(listener);
     }
     
     def unsetReadPublisher (IPluginOutReadService listener) {
-       if( listener != null)
-               statisticsPublisher.remove(listener);
+        if( listener != null)
+            statisticsPublisher.remove(listener);
     }
 
     protected def startChange() {
@@ -140,33 +157,33 @@ class InventoryAndReadAdapter implements IPluginInReadService,
     override readAllFlow(Node node, boolean cached) {
 
         val output = new ArrayList<FlowOnNode>();
-               val tableRef = InstanceIdentifier.builder(Nodes)
-                                                                               .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, InventoryMapping.toNodeKey(node))
-                                                       .augmentation(FlowCapableNode).child(Table, new TableKey(OPENFLOWV10_TABLE_ID)).toInstance();
-               
-               val it = this.startChange();
-               
-               val table= it.readConfigurationData(tableRef) as Table;
-               
-               if(table != null){
-                       LOG.trace("Number of flows installed in table 0 of node {} : {}",node,table.flow.size);
-                       
-                       for(flow : table.flow){
-                               
-                               val adsalFlow = ToSalConversionsUtils.toFlow(flow,node);
-                               val statsFromDataStore = flow.getAugmentation(FlowStatisticsData);
-                               
-                               if(statsFromDataStore != null){
-                                       val it = new FlowOnNode(adsalFlow);
-                                       byteCount =  statsFromDataStore.flowStatistics.byteCount.value.longValue;
-                                       packetCount = statsFromDataStore.flowStatistics.packetCount.value.longValue;
-                                       durationSeconds = statsFromDataStore.flowStatistics.duration.second.value.intValue;
-                                       durationNanoseconds = statsFromDataStore.flowStatistics.duration.nanosecond.value.intValue;
-                                       
-                                       output.add(it);
-                               }
-                       }
-               }
+        val tableRef = InstanceIdentifier.builder(Nodes)
+                                        .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, InventoryMapping.toNodeKey(node))
+                                        .augmentation(FlowCapableNode).child(Table, new TableKey(OPENFLOWV10_TABLE_ID)).toInstance();
+        
+        val it = this.startChange();
+        
+        val table= it.readConfigurationData(tableRef) as Table;
+        
+        if(table != null){
+            LOG.trace("Number of flows installed in table 0 of node {} : {}",node,table.flow.size);
+            
+            for(flow : table.flow){
+                
+                val adsalFlow = ToSalConversionsUtils.toFlow(flow,node);
+                val statsFromDataStore = flow.getAugmentation(FlowStatisticsData);
+                
+                if(statsFromDataStore != null){
+                    val it = new FlowOnNode(adsalFlow);
+                    byteCount =  statsFromDataStore.flowStatistics.byteCount.value.longValue;
+                    packetCount = statsFromDataStore.flowStatistics.packetCount.value.longValue;
+                    durationSeconds = statsFromDataStore.flowStatistics.duration.second.value.intValue;
+                    durationNanoseconds = statsFromDataStore.flowStatistics.duration.nanosecond.value.intValue;
+                    
+                    output.add(it);
+                }
+            }
+        }
         
         //TODO (main): Shell we send request to the switch? It will make async request to the switch.
         // Once plugin receive response, it will let adaptor know through onFlowStatisticsUpdate()
@@ -180,35 +197,35 @@ class InventoryAndReadAdapter implements IPluginInReadService,
     }
 
     override readAllNodeConnector(Node node, boolean cached) {
-       
-       val ret = new ArrayList<NodeConnectorStatistics>();
-               val nodeRef = InstanceIdentifier.builder(Nodes)
-                                                                       .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, InventoryMapping.toNodeKey(node))
-                                                                       .toInstance();
-               
-               val provider = this.startChange();
-               
-               val dsNode= provider.readConfigurationData(nodeRef) as org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
-               
-               if(dsNode != null){
-                       
-                       for (dsNodeConnector : dsNode.nodeConnector){
-                               val nodeConnectorRef = InstanceIdentifier.builder(Nodes)
-                                                                       .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, InventoryMapping.toNodeKey(node))
-                                                                       .child(NodeConnector, dsNodeConnector.key)
-                                                                       .toInstance();
-                               
-                               val nodeConnectorFromDS = provider.readConfigurationData(nodeConnectorRef) as NodeConnector;
-                               
-                               if(nodeConnectorFromDS != null){
-                                       val nodeConnectorStatsFromDs = nodeConnectorFromDS.getAugmentation(FlowCapableNodeConnectorStatisticsData) as FlowCapableNodeConnectorStatistics;
-                                       
-                                       ret.add(toNodeConnectorStatistics(nodeConnectorStatsFromDs.flowCapableNodeConnectorStatistics,dsNode.id,dsNodeConnector.id));
-                               }
-                       }
-               }
-
-               //TODO: Refer TODO (main)
+        
+        val ret = new ArrayList<NodeConnectorStatistics>();
+        val nodeRef = InstanceIdentifier.builder(Nodes)
+                                    .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, InventoryMapping.toNodeKey(node))
+                                    .toInstance();
+        
+        val provider = this.startChange();
+        
+        val dsNode= provider.readConfigurationData(nodeRef) as org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+        
+         if(dsNode != null){
+             
+             for (dsNodeConnector : dsNode.nodeConnector){
+                val nodeConnectorRef = InstanceIdentifier.builder(Nodes)
+                                    .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, InventoryMapping.toNodeKey(node))
+                                    .child(NodeConnector, dsNodeConnector.key)
+                                    .toInstance();
+                 
+                 val nodeConnectorFromDS = provider.readConfigurationData(nodeConnectorRef) as NodeConnector;
+                 
+                 if(nodeConnectorFromDS != null){
+                     val nodeConnectorStatsFromDs = nodeConnectorFromDS.getAugmentation(FlowCapableNodeConnectorStatisticsData) as FlowCapableNodeConnectorStatistics;
+                     
+                    ret.add(toNodeConnectorStatistics(nodeConnectorStatsFromDs.flowCapableNodeConnectorStatistics,dsNode.id,dsNodeConnector.id));
+                 }
+             }
+         }
+
+        //TODO: Refer TODO (main)
         val input = new GetAllNodeConnectorsStatisticsInputBuilder();
         input.setNode(node.toNodeRef);
         nodeConnectorStatisticsService.getAllNodeConnectorsStatistics(input.build());
@@ -216,23 +233,23 @@ class InventoryAndReadAdapter implements IPluginInReadService,
     }
 
     override readAllNodeTable(Node node, boolean cached) {
-       val ret = new ArrayList<NodeTableStatistics>();
-       
-               val dsFlowCapableNode= readFlowCapableNode(node.toNodeRef)
-               
-               if(dsFlowCapableNode != null){
-                       
-                       for (table : dsFlowCapableNode.table){
-                               
-                               val tableStats = table.getAugmentation(FlowTableStatisticsData);
-                               
-                               if(tableStats != null){
-                                       ret.add(toNodeTableStatistics(tableStats.flowTableStatistics,table.id,node));
-                               }
-                       }
-               }
-
-               //TODO: Refer TODO (main)
+        val ret = new ArrayList<NodeTableStatistics>();
+        
+        val dsFlowCapableNode= readFlowCapableNode(node.toNodeRef)
+        
+         if(dsFlowCapableNode != null){
+             
+             for (table : dsFlowCapableNode.table){
+                 
+                 val tableStats = table.getAugmentation(FlowTableStatisticsData);
+                 
+                 if(tableStats != null){
+                     ret.add(toNodeTableStatistics(tableStats.flowTableStatistics,table.id,node));
+                 }
+             }
+         }
+
+        //TODO: Refer TODO (main)
         val input = new GetFlowTablesStatisticsInputBuilder();
         input.setNode(node.toNodeRef);
         flowTableStatisticsService.getFlowTablesStatistics(input.build);
@@ -241,39 +258,39 @@ class InventoryAndReadAdapter implements IPluginInReadService,
 
     override readDescription(Node node, boolean cached) {
         return toNodeDescription(node.toNodeRef);
-       }
+    }
 
     override readFlow(Node node, Flow targetFlow, boolean cached) {
-               var FlowOnNode ret= null;
-               
-               val tableRef = InstanceIdentifier.builder(Nodes)
-                                                                               .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, InventoryMapping.toNodeKey(node))
-                                                       .augmentation(FlowCapableNode).child(Table, new TableKey(OPENFLOWV10_TABLE_ID)).toInstance();
-               
-               val it = this.startChange();
-               
-               val table= it.readConfigurationData(tableRef) as Table;
-               
-               if(table != null){
-                       LOG.trace("Number of flows installed in table 0 of node {} : {}",node,table.flow.size);
-                       
-                       for(mdsalFlow : table.flow){
-                               if(FromSalConversionsUtils.flowEquals(mdsalFlow, MDFlowMapping.toMDSalflow(targetFlow))){
-                                       val statsFromDataStore = mdsalFlow.getAugmentation(FlowStatisticsData);
-                                       
-                                       if(statsFromDataStore != null){
-                                               LOG.debug("Found matching flow in the data store flow table ");
-                                               val it = new FlowOnNode(targetFlow);
-                                               byteCount =  statsFromDataStore.flowStatistics.byteCount.value.longValue;
-                                               packetCount = statsFromDataStore.flowStatistics.packetCount.value.longValue;
-                                               durationSeconds = statsFromDataStore.flowStatistics.duration.second.value.intValue;
-                                               durationNanoseconds = statsFromDataStore.flowStatistics.duration.nanosecond.value.intValue;
-                                               
-                                               ret = it;
-                                       }
-                               }                       
-                       }
-               }
+        var FlowOnNode ret= null;
+        
+        val tableRef = InstanceIdentifier.builder(Nodes)
+                                        .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, InventoryMapping.toNodeKey(node))
+                                        .augmentation(FlowCapableNode).child(Table, new TableKey(OPENFLOWV10_TABLE_ID)).toInstance();
+        
+        val it = this.startChange();
+        
+        val table= it.readConfigurationData(tableRef) as Table;
+        
+        if(table != null){
+            LOG.trace("Number of flows installed in table 0 of node {} : {}",node,table.flow.size);
+            
+            for(mdsalFlow : table.flow){
+                if(FromSalConversionsUtils.flowEquals(mdsalFlow, MDFlowMapping.toMDSalflow(targetFlow))){
+                    val statsFromDataStore = mdsalFlow.getAugmentation(FlowStatisticsData);
+                    
+                    if(statsFromDataStore != null){
+                        LOG.debug("Found matching flow in the data store flow table ");
+                        val it = new FlowOnNode(targetFlow);
+                        byteCount =  statsFromDataStore.flowStatistics.byteCount.value.longValue;
+                        packetCount = statsFromDataStore.flowStatistics.packetCount.value.longValue;
+                        durationSeconds = statsFromDataStore.flowStatistics.duration.second.value.intValue;
+                        durationNanoseconds = statsFromDataStore.flowStatistics.duration.nanosecond.value.intValue;
+                        
+                        ret = it;
+                    }
+                }            
+            }
+        }
         
         //TODO: Refer TODO (main)
         val input = new GetFlowStatisticsFromFlowTableInputBuilder;
@@ -282,30 +299,30 @@ class InventoryAndReadAdapter implements IPluginInReadService,
         flowStatisticsService.getFlowStatisticsFromFlowTable(input.build)
         
         return ret;
-       
+        
     }
 
     override readNodeConnector(org.opendaylight.controller.sal.core.NodeConnector connector, boolean cached) {
-       var NodeConnectorStatistics  nodeConnectorStatistics = null;
-       
-               val nodeConnectorRef = InstanceIdentifier.builder(Nodes)
-                                                                       .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, InventoryMapping.toNodeKey(connector.node))
-                                                                       .child(NodeConnector, InventoryMapping.toNodeConnectorKey(connector))
-                                                                       .toInstance();
-               val provider = this.startChange();
-                               
-               val nodeConnectorFromDS = provider.readConfigurationData(nodeConnectorRef) as NodeConnector;
-                               
-               if(nodeConnectorFromDS != null){
-                       val nodeConnectorStatsFromDs = nodeConnectorFromDS.getAugmentation(FlowCapableNodeConnectorStatisticsData) as FlowCapableNodeConnectorStatistics;
-                       if(nodeConnectorStatsFromDs != null) {
-                               nodeConnectorStatistics = toNodeConnectorStatistics(nodeConnectorStatsFromDs.flowCapableNodeConnectorStatistics,
-                                                                                                                                               InventoryMapping.toNodeKey(connector.node).id,
-                                                                                                                                               InventoryMapping.toNodeConnectorKey(connector).id);
-                       }
-               }
-
-               //TODO: Refer TODO (main)
+        var NodeConnectorStatistics  nodeConnectorStatistics = null;
+    
+        val nodeConnectorRef = InstanceIdentifier.builder(Nodes)
+                                    .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, InventoryMapping.toNodeKey(connector.node))
+                                    .child(NodeConnector, InventoryMapping.toNodeConnectorKey(connector))
+                                    .toInstance();
+         val provider = this.startChange();
+                 
+         val nodeConnectorFromDS = provider.readConfigurationData(nodeConnectorRef) as NodeConnector;
+                 
+         if(nodeConnectorFromDS != null){
+            val nodeConnectorStatsFromDs = nodeConnectorFromDS.getAugmentation(FlowCapableNodeConnectorStatisticsData) as FlowCapableNodeConnectorStatistics;
+            if(nodeConnectorStatsFromDs != null) {
+                nodeConnectorStatistics = toNodeConnectorStatistics(nodeConnectorStatsFromDs.flowCapableNodeConnectorStatistics,
+                                                                        InventoryMapping.toNodeKey(connector.node).id,
+                                                                        InventoryMapping.toNodeConnectorKey(connector).id);
+            }
+        }
+
+        //TODO: Refer TODO (main)
         val input = new GetNodeConnectorStatisticsInputBuilder();
         input.setNode(connector.node.toNodeRef);
         input.setNodeConnectorId(InventoryMapping.toNodeConnectorKey(connector).id);
@@ -314,25 +331,25 @@ class InventoryAndReadAdapter implements IPluginInReadService,
     }
 
     override readNodeTable(NodeTable nodeTable, boolean cached) {
-       var NodeTableStatistics nodeStats = null
-       
-       val tableRef = InstanceIdentifier.builder(Nodes)
-                                                                               .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, InventoryMapping.toNodeKey(nodeTable.node))
-                                                       .augmentation(FlowCapableNode).child(Table, new TableKey(nodeTable.ID as Short)).toInstance();
-               
-               val it = this.startChange();
-               
-               val table= it.readConfigurationData(tableRef) as Table;
-               
-               if(table != null){
-                       val tableStats = table.getAugmentation(FlowTableStatisticsData);
-                               
-                       if(tableStats != null){
-                               nodeStats =  toNodeTableStatistics(tableStats.flowTableStatistics,table.id,nodeTable.node);
-                       }
-               }
-
-               //TODO: Refer TODO (main)
+        var NodeTableStatistics nodeStats = null
+        
+        val tableRef = InstanceIdentifier.builder(Nodes)
+                                        .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, InventoryMapping.toNodeKey(nodeTable.node))
+                                        .augmentation(FlowCapableNode).child(Table, new TableKey(nodeTable.ID as Short)).toInstance();
+        
+        val it = this.startChange();
+        
+        val table= it.readConfigurationData(tableRef) as Table;
+        
+        if(table != null){
+            val tableStats = table.getAugmentation(FlowTableStatisticsData);
+                 
+             if(tableStats != null){
+                 nodeStats =  toNodeTableStatistics(tableStats.flowTableStatistics,table.id,nodeTable.node);
+            }
+        }
+
+        //TODO: Refer TODO (main)
         val input = new GetFlowTablesStatisticsInputBuilder();
         input.setNode(nodeTable.node.toNodeRef);
         flowTableStatisticsService.getFlowTablesStatistics(input.build);
@@ -341,19 +358,22 @@ class InventoryAndReadAdapter implements IPluginInReadService,
     }
 
     override onNodeConnectorRemoved(NodeConnectorRemoved update) {
-        // NOOP
+        // Never received
     }
 
     override onNodeRemoved(NodeRemoved notification) {
         val properties = Collections.<org.opendaylight.controller.sal.core.Property>emptySet();
 
+        removeNodeConnectors(notification.nodeRef.value);
+
         publishNodeUpdate(notification.nodeRef.toADNode, UpdateType.REMOVED, properties);
     }
 
     override onNodeConnectorUpdated(NodeConnectorUpdated update) {
         var updateType = UpdateType.CHANGED;
-        if ( this._dataService.readOperationalData(update.nodeConnectorRef.value as InstanceIdentifier<? extends DataObject>) == null ){
+        if(!isKnownNodeConnector(update.nodeConnectorRef.value)){
             updateType = UpdateType.ADDED;
+            recordNodeConnector(update.nodeConnectorRef.value);
         }
 
         var nodeConnector = update.nodeConnectorRef.toADNodeConnector
@@ -369,16 +389,16 @@ class InventoryAndReadAdapter implements IPluginInReadService,
             updateType = UpdateType.ADDED;
         }
         publishNodeUpdate(notification.nodeRef.toADNode, updateType, notification.toADNodeProperties);
-        
-               //Notify the listeners of IPluginOutReadService
-        
+
+        //Notify the listeners of IPluginOutReadService
+
         for (statsPublisher : statisticsPublisher){
-                       val nodeRef = InstanceIdentifier.builder(Nodes).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node,new NodeKey(notification.id)).toInstance;
+            val nodeRef = InstanceIdentifier.builder(Nodes).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node,new NodeKey(notification.id)).toInstance;
             val description = notification.nodeRef.toNodeDescription
             if(description != null) {
-                         statsPublisher.descriptionStatisticsUpdated(nodeRef.toADNode,description);
-                       }
-               }
+              statsPublisher.descriptionStatisticsUpdated(nodeRef.toADNode,description);
+            }
+        }
     }
 
     override getNodeProps() {
@@ -461,50 +481,50 @@ class InventoryAndReadAdapter implements IPluginInReadService,
 
     private def toNodeConnectorStatistics(
         org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.NodeConnectorStatistics nodeConnectorStatistics, NodeId nodeId, NodeConnectorId nodeConnectorId) {
-               
-                       val it = new NodeConnectorStatistics();
-                       
-                       receivePacketCount = nodeConnectorStatistics.packets.received.longValue;
-                       transmitPacketCount = nodeConnectorStatistics.packets.transmitted.longValue;
-                       
-                       receiveByteCount = nodeConnectorStatistics.bytes.received.longValue;
-                       transmitByteCount = nodeConnectorStatistics.bytes.transmitted.longValue;
-                       
-                       receiveDropCount = nodeConnectorStatistics.receiveDrops.longValue;
-                       transmitDropCount = nodeConnectorStatistics.transmitDrops.longValue;
-                       
-                       receiveErrorCount = nodeConnectorStatistics.receiveErrors.longValue;
-                       transmitErrorCount = nodeConnectorStatistics.transmitErrors.longValue;
-                       
-                       receiveFrameErrorCount = nodeConnectorStatistics.receiveFrameError.longValue;
-                       receiveOverRunErrorCount = nodeConnectorStatistics.receiveOverRunError.longValue;
-                       receiveCRCErrorCount = nodeConnectorStatistics.receiveCrcError.longValue;
-                       collisionCount = nodeConnectorStatistics.collisionCount.longValue;
-                       
-                       val nodeConnectorRef = InstanceIdentifier.builder(Nodes)
-                                                               .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node,new NodeKey(nodeId))
-                                                               .child(NodeConnector,new NodeConnectorKey(nodeConnectorId)).toInstance;
-                       
-                       nodeConnector = NodeMapping.toADNodeConnector(new NodeConnectorRef(nodeConnectorRef));
-                       
-                       return it;
-    }
-
-       private def toNodeTableStatistics(
-               FlowTableStatistics tableStats,
-               Short tableId,Node node){
-               var it = new NodeTableStatistics();
-               
-               activeCount = tableStats.activeFlows.value.intValue;
-               lookupCount = tableStats.packetsLookedUp.value.intValue;
-               matchedCount = tableStats.packetsMatched.value.intValue;
-               name = tableId.toString;
-               nodeTable = new NodeTable(NodeMapping.MD_SAL_TYPE,tableId,node);
-               return it;
-       }
-       
-       private def toNodeDescription(NodeRef nodeRef){
-               val capableNode = readFlowCapableNode(nodeRef);
+            
+            val it = new NodeConnectorStatistics();
+            
+            receivePacketCount = nodeConnectorStatistics.packets.received.longValue;
+            transmitPacketCount = nodeConnectorStatistics.packets.transmitted.longValue;
+            
+            receiveByteCount = nodeConnectorStatistics.bytes.received.longValue;
+            transmitByteCount = nodeConnectorStatistics.bytes.transmitted.longValue;
+            
+            receiveDropCount = nodeConnectorStatistics.receiveDrops.longValue;
+            transmitDropCount = nodeConnectorStatistics.transmitDrops.longValue;
+            
+            receiveErrorCount = nodeConnectorStatistics.receiveErrors.longValue;
+            transmitErrorCount = nodeConnectorStatistics.transmitErrors.longValue;
+            
+            receiveFrameErrorCount = nodeConnectorStatistics.receiveFrameError.longValue;
+            receiveOverRunErrorCount = nodeConnectorStatistics.receiveOverRunError.longValue;
+            receiveCRCErrorCount = nodeConnectorStatistics.receiveCrcError.longValue;
+            collisionCount = nodeConnectorStatistics.collisionCount.longValue;
+            
+            val nodeConnectorRef = InstanceIdentifier.builder(Nodes)
+                                .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node,new NodeKey(nodeId))
+                                .child(NodeConnector,new NodeConnectorKey(nodeConnectorId)).toInstance;
+            
+            nodeConnector = NodeMapping.toADNodeConnector(new NodeConnectorRef(nodeConnectorRef));
+            
+            return it;
+    }
+
+    private def toNodeTableStatistics(
+        FlowTableStatistics tableStats,
+        Short tableId,Node node){
+        var it = new NodeTableStatistics();
+        
+        activeCount = tableStats.activeFlows.value.intValue;
+        lookupCount = tableStats.packetsLookedUp.value.intValue;
+        matchedCount = tableStats.packetsMatched.value.intValue;
+        name = tableId.toString;
+        nodeTable = new NodeTable(NodeMapping.MD_SAL_TYPE,tableId,node);
+        return it;
+    }
+    
+    private def toNodeDescription(NodeRef nodeRef){
+        val capableNode = readFlowCapableNode(nodeRef);
         if(capableNode !=null) {
             val it = new NodeDescription()
             manufacturer = capableNode.manufacturer
@@ -515,101 +535,148 @@ class InventoryAndReadAdapter implements IPluginInReadService,
             return it;
          }
          return null;
-       }
+    }
     
     
     def Edge toADEdge(Link link) {
         new Edge(link.source.toADNodeConnector,link.destination.toADNodeConnector)
     }
-       
-       /*
-        * OpendaylightFlowStatisticsListener interface implementation
-        */
-       override onAggregateFlowStatisticsUpdate(AggregateFlowStatisticsUpdate notification) {
+    
+    /*
+     * OpendaylightFlowStatisticsListener interface implementation
+     */
+    override onAggregateFlowStatisticsUpdate(AggregateFlowStatisticsUpdate notification) {
         //Ignoring this notification as there does not seem to be a way to bubble this up to AD-SAL
-       }
-       
-       override onFlowsStatisticsUpdate(FlowsStatisticsUpdate notification) {
-               
-               val adsalFlowsStatistics = new ArrayList<FlowOnNode>();
-               val nodeRef = InstanceIdentifier.builder(Nodes).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node,new NodeKey(notification.id)).toInstance;
-               
-               for(flowStats : notification.flowAndStatisticsMapList){
-                       if(flowStats.tableId == 0)
-                               adsalFlowsStatistics.add(toFlowOnNode(flowStats,nodeRef.toADNode));
-               }
-               
-               for (statsPublisher : statisticsPublisher){
-                       statsPublisher.nodeFlowStatisticsUpdated(nodeRef.toADNode,adsalFlowsStatistics);
-               }
-               
-       }
-       /*
-        * OpendaylightFlowTableStatisticsListener interface implementation
-        */     
-       override onFlowTableStatisticsUpdate(FlowTableStatisticsUpdate notification) {
-               var adsalFlowTableStatistics = new ArrayList<NodeTableStatistics>();
-               
-               for(stats : notification.flowTableAndStatisticsMap){
-                       if (stats.tableId.value == 0){
-                               val it = new NodeTableStatistics();
-                               activeCount = stats.activeFlows.value.intValue;
-                               lookupCount = stats.packetsLookedUp.value.longValue;
-                               matchedCount = stats.packetsMatched.value.longValue;
-                               
-                               adsalFlowTableStatistics.add(it);
-                       }
-               }
-               for (statsPublisher : statisticsPublisher){
-                       val nodeRef = InstanceIdentifier.builder(Nodes).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node,new NodeKey(notification.id)).toInstance;
-                       statsPublisher.nodeTableStatisticsUpdated(nodeRef.toADNode,adsalFlowTableStatistics);
-               }
-       }
-       
-       /*
-        * OpendaylightPortStatisticsUpdate interface implementation
-        */
-       override onNodeConnectorStatisticsUpdate(NodeConnectorStatisticsUpdate notification) {
-               
-               val adsalPortStatistics  = new ArrayList<NodeConnectorStatistics>();
-               
-               for(nodeConnectorStatistics : notification.nodeConnectorStatisticsAndPortNumberMap){
-                       adsalPortStatistics.add(toNodeConnectorStatistics(nodeConnectorStatistics,notification.id,nodeConnectorStatistics.nodeConnectorId));
-               }
-               
-               for (statsPublisher : statisticsPublisher){
-                       val nodeRef = InstanceIdentifier.builder(Nodes).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node,new NodeKey(notification.id)).toInstance;
-                       statsPublisher.nodeConnectorStatisticsUpdated(nodeRef.toADNode,adsalPortStatistics);
-               }
-               
-       }
-       
-       private static def toFlowOnNode (FlowAndStatisticsMapList flowAndStatsMap,Node node){
-               
-               val it = new FlowOnNode(ToSalConversionsUtils.toFlow(flowAndStatsMap,node));
-               
-               byteCount = flowAndStatsMap.byteCount.value.longValue;
-               packetCount = flowAndStatsMap.packetCount.value.longValue;
-               durationSeconds = flowAndStatsMap.duration.second.value.intValue;
-               durationNanoseconds = flowAndStatsMap.duration.nanosecond.value.intValue;
-               
-               return it;
-       }
-
-       override  getConfiguredNotConnectedNodes() {
+    }
+    
+    override onFlowsStatisticsUpdate(FlowsStatisticsUpdate notification) {
+        
+        val adsalFlowsStatistics = new ArrayList<FlowOnNode>();
+        val nodeRef = InstanceIdentifier.builder(Nodes).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node,new NodeKey(notification.id)).toInstance;
+        
+        for(flowStats : notification.flowAndStatisticsMapList){
+            if(flowStats.tableId == 0)
+                adsalFlowsStatistics.add(toFlowOnNode(flowStats,nodeRef.toADNode));
+        }
+        
+        for (statsPublisher : statisticsPublisher){
+            statsPublisher.nodeFlowStatisticsUpdated(nodeRef.toADNode,adsalFlowsStatistics);
+        }
+        
+    }
+    /*
+     * OpendaylightFlowTableStatisticsListener interface implementation
+     */    
+    override onFlowTableStatisticsUpdate(FlowTableStatisticsUpdate notification) {
+        var adsalFlowTableStatistics = new ArrayList<NodeTableStatistics>();
+        
+        for(stats : notification.flowTableAndStatisticsMap){
+            if (stats.tableId.value == 0){
+                val it = new NodeTableStatistics();
+                activeCount = stats.activeFlows.value.intValue;
+                lookupCount = stats.packetsLookedUp.value.longValue;
+                matchedCount = stats.packetsMatched.value.longValue;
+                
+                adsalFlowTableStatistics.add(it);
+            }
+        }
+        for (statsPublisher : statisticsPublisher){
+            val nodeRef = InstanceIdentifier.builder(Nodes).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node,new NodeKey(notification.id)).toInstance;
+            statsPublisher.nodeTableStatisticsUpdated(nodeRef.toADNode,adsalFlowTableStatistics);
+        }
+    }
+    
+    /*
+     * OpendaylightPortStatisticsUpdate interface implementation
+     */
+    override onNodeConnectorStatisticsUpdate(NodeConnectorStatisticsUpdate notification) {
+        
+        val adsalPortStatistics  = new ArrayList<NodeConnectorStatistics>();
+        
+        for(nodeConnectorStatistics : notification.nodeConnectorStatisticsAndPortNumberMap){
+            adsalPortStatistics.add(toNodeConnectorStatistics(nodeConnectorStatistics,notification.id,nodeConnectorStatistics.nodeConnectorId));
+        }
+        
+        for (statsPublisher : statisticsPublisher){
+            val nodeRef = InstanceIdentifier.builder(Nodes).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node,new NodeKey(notification.id)).toInstance;
+            statsPublisher.nodeConnectorStatisticsUpdated(nodeRef.toADNode,adsalPortStatistics);
+        }
+        
+    }
+    
+    private static def toFlowOnNode (FlowAndStatisticsMapList flowAndStatsMap,Node node){
+        
+        val it = new FlowOnNode(ToSalConversionsUtils.toFlow(flowAndStatsMap,node));
+        
+        byteCount = flowAndStatsMap.byteCount.value.longValue;
+        packetCount = flowAndStatsMap.packetCount.value.longValue;
+        durationSeconds = flowAndStatsMap.duration.second.value.intValue;
+        durationNanoseconds = flowAndStatsMap.duration.nanosecond.value.intValue;
+        
+        return it;
+    }
+
+    override  getConfiguredNotConnectedNodes() {
         return Collections.emptySet();
-       }
+    }
+
+
+    private def publishNodeUpdate(Node node, UpdateType updateType, Set<org.opendaylight.controller.sal.core.Property> properties){
+        for( publisher : inventoryPublisher){
+            publisher.updateNode(node, updateType, properties);
+        }
+    }
+
+    private def publishNodeConnectorUpdate(org.opendaylight.controller.sal.core.NodeConnector nodeConnector, UpdateType updateType, Set<org.opendaylight.controller.sal.core.Property> properties){
+        for( publisher : inventoryPublisher){
+            publisher.updateNodeConnector(nodeConnector, updateType, properties);
+        }
+    }
+
+    private def isKnownNodeConnector(InstanceIdentifier<? extends Object> nodeConnectorIdentifier){
+        if(nodeConnectorIdentifier.path.size() < 3) {
+            return false;
+        }
 
+        val nodePath = nodeConnectorIdentifier.path.get(1);
+        val nodeConnectorPath = nodeConnectorIdentifier.getPath().get(2);
 
-       private def publishNodeUpdate(Node node, UpdateType updateType, Set<org.opendaylight.controller.sal.core.Property> properties){
-           for( publisher : inventoryPublisher){
-               publisher.updateNode(node, updateType, properties);
-           }
-       }
+        val nodeConnectors = nodeToNodeConnectorsMap.get(nodePath);
 
-       private def publishNodeConnectorUpdate(org.opendaylight.controller.sal.core.NodeConnector nodeConnector, UpdateType updateType, Set<org.opendaylight.controller.sal.core.Property> properties){
-           for( publisher : inventoryPublisher){
-               publisher.updateNodeConnector(nodeConnector, updateType, properties);
-           }
-       }
+        if(nodeConnectors == null){
+            return false;
+        }
+        return nodeConnectors.contains(nodeConnectorPath);
+    }
+
+
+    private def recordNodeConnector(InstanceIdentifier<? extends Object> nodeConnectorIdentifier){
+        if(nodeConnectorIdentifier.path.size() < 3) {
+            return false;
+        }
+
+        val nodePath = nodeConnectorIdentifier.path.get(1);
+        val nodeConnectorPath = nodeConnectorIdentifier.getPath().get(2);
+
+        nodeToNodeConnectorsLock.lock();
+
+        try {
+            var nodeConnectors = nodeToNodeConnectorsMap.get(nodePath);
+
+            if(nodeConnectors == null){
+                nodeConnectors = new ArrayList<InstanceIdentifier.PathArgument>();
+                nodeToNodeConnectorsMap.put(nodePath, nodeConnectors);
+            }
+
+            nodeConnectors.add(nodeConnectorPath);
+        } finally {
+            nodeToNodeConnectorsLock.unlock();
+        }
+    }
+
+    private def removeNodeConnectors(InstanceIdentifier<? extends Object> nodeIdentifier){
+        val nodePath = nodeIdentifier.path.get(1);
+
+        nodeToNodeConnectorsMap.remove(nodePath);
+    }
 }
diff --git a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/InventoryNotificationProvider.java b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/InventoryNotificationProvider.java
new file mode 100644 (file)
index 0000000..23a98ff
--- /dev/null
@@ -0,0 +1,59 @@
+package org.opendaylight.controller.sal.compatibility;
+
+import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
+import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
+import org.opendaylight.controller.sal.inventory.IPluginOutInventoryService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+
+public class InventoryNotificationProvider implements AutoCloseable{
+
+    private ListenerRegistration<DataChangeListener> nodeConnectorDataChangeListenerRegistration;
+
+    private NodeConnectorDataChangeListener nodeConnectorDataChangeListener;
+
+    private DataProviderService dataProviderService;
+
+    private List<IPluginOutInventoryService> inventoryPublisher;
+
+    private final static Logger LOG = LoggerFactory.getLogger(NodeConnectorDataChangeListener.class);
+
+    public void start(){
+
+        LOG.info("InventoryNotificationProvider started");
+
+        if(dataProviderService != null
+                && inventoryPublisher!= null){
+
+            if(nodeConnectorDataChangeListener == null){
+                InstanceIdentifier nodeConnectorPath = InstanceIdentifier.builder(Nodes.class).child(Node.class).child(NodeConnector.class).build();
+                nodeConnectorDataChangeListener = new NodeConnectorDataChangeListener();
+                nodeConnectorDataChangeListener.setInventoryPublisher(inventoryPublisher);
+                nodeConnectorDataChangeListenerRegistration = dataProviderService.registerDataChangeListener(nodeConnectorPath, nodeConnectorDataChangeListener);
+            }
+
+        }
+    }
+
+    @Override
+    public void close() throws Exception {
+        if(nodeConnectorDataChangeListenerRegistration != null){
+            nodeConnectorDataChangeListenerRegistration.close();
+        }
+    }
+
+    public void setDataProviderService(DataProviderService dataProviderService) {
+        this.dataProviderService = dataProviderService;
+    }
+
+    public void setInventoryPublisher(List<IPluginOutInventoryService> inventoryPublisher) {
+        this.inventoryPublisher = inventoryPublisher;
+    }
+}
diff --git a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/NodeConnectorDataChangeListener.java b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/NodeConnectorDataChangeListener.java
new file mode 100644 (file)
index 0000000..eebba74
--- /dev/null
@@ -0,0 +1,77 @@
+package org.opendaylight.controller.sal.compatibility;
+
+import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent;
+import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
+import org.opendaylight.controller.sal.core.ConstructionException;
+import org.opendaylight.controller.sal.core.NodeConnector;
+import org.opendaylight.controller.sal.core.Property;
+import org.opendaylight.controller.sal.core.UpdateType;
+import org.opendaylight.controller.sal.inventory.IPluginOutInventoryService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+// org.opendaylight.controller.sal.compatibility.NodeConnectorDataChangeListener
+public class NodeConnectorDataChangeListener implements DataChangeListener{
+    private final static Logger LOG = LoggerFactory.getLogger(NodeConnectorDataChangeListener.class);
+
+    private List<IPluginOutInventoryService> inventoryPublisher;
+
+    public List<IPluginOutInventoryService> getInventoryPublisher() {
+      return this.inventoryPublisher;
+    }
+
+    public void setInventoryPublisher(final List<IPluginOutInventoryService> inventoryPublisher) {
+      this.inventoryPublisher = inventoryPublisher;
+    }
+
+    @Override
+    public void onDataChanged(DataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
+        final Map<InstanceIdentifier<?>,DataObject> createdOperationalData = change.getCreatedOperationalData();
+        final Map<InstanceIdentifier<?>,DataObject> updatedOperationalData = change.getUpdatedOperationalData();
+
+        final Set<Map.Entry<InstanceIdentifier<?>,DataObject>> createdEntries = createdOperationalData.entrySet();
+        final Set<Map.Entry<InstanceIdentifier<?>,DataObject>> updatedEntries = new HashSet<>();
+
+        updatedEntries.addAll(updatedOperationalData.entrySet());
+        updatedEntries.removeAll(createdEntries);
+
+        for(final Map.Entry<InstanceIdentifier<?>,DataObject> entry : createdEntries){
+            publishNodeConnectorUpdate(entry, UpdateType.ADDED);
+        }
+
+        for(final Map.Entry<InstanceIdentifier<?>,DataObject> entry : updatedEntries){
+            publishNodeConnectorUpdate(entry, UpdateType.CHANGED);
+        }
+    }
+
+    private void publishNodeConnectorUpdate(final Map.Entry<InstanceIdentifier<?>,DataObject> entry, final UpdateType updateType) {
+        if (entry.getKey().getTargetType().equals(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector.class)) {
+            NodeConnectorRef nodeConnectorRef = new NodeConnectorRef(entry.getKey());
+            NodeConnector nodeConnector = null;
+            try {
+                nodeConnector = NodeMapping.toADNodeConnector(nodeConnectorRef);
+            } catch (ConstructionException e) {
+                e.printStackTrace();
+            }
+            HashSet<Property> _aDNodeConnectorProperties = NodeMapping.toADNodeConnectorProperties((org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector) entry.getValue());
+            this.publishNodeConnectorUpdate(nodeConnector, updateType, _aDNodeConnectorProperties);
+        }
+    }
+
+    private void publishNodeConnectorUpdate(final NodeConnector nodeConnector, final UpdateType updateType, final Set<Property> properties) {
+      LOG.debug("Publishing NodeConnector " + updateType.toString() + " nodeConnector Id = " + nodeConnector.getNodeConnectorIdAsString());
+
+      List<IPluginOutInventoryService> _inventoryPublisher = getInventoryPublisher();
+      for (final IPluginOutInventoryService publisher : _inventoryPublisher) {
+        publisher.updateNodeConnector(nodeConnector, updateType, properties);
+      }
+    }
+}
index 1a66b3ba16316b4c5a1c92485e909cf061c3d398..43f48a50e56175a2297e78e32478f80404ff839d 100644 (file)
@@ -64,6 +64,8 @@ class FlowCapableInventoryProvider implements AutoCloseable {
 
 class NodeChangeCommiter implements OpendaylightInventoryListener {
 
+    static val LOG = LoggerFactory.getLogger(NodeChangeCommiter);
+
     @Property
     val FlowCapableInventoryProvider manager;
 
@@ -76,6 +78,9 @@ class NodeChangeCommiter implements OpendaylightInventoryListener {
 
         // Check path
         val it = manager.startChange()
+
+        LOG.debug("removing node connector : " + ref.value.toString());
+
         removeOperationalData(ref.value as InstanceIdentifier<? extends DataObject>);
         commit()
     }
@@ -93,6 +98,8 @@ class NodeChangeCommiter implements OpendaylightInventoryListener {
             data.addAugmentation(FlowCapableNodeConnector, augment)
         }
 
+        LOG.debug("updating node connector : " + ref.value.toString());
+
         putOperationalData(ref.value as InstanceIdentifier<NodeConnector>, data.build());
         commit()
     }
@@ -101,6 +108,8 @@ class NodeChangeCommiter implements OpendaylightInventoryListener {
         val ref = node.nodeRef;
         val it = manager.startChange()
 
+        LOG.debug("removing node : " + ref.value.toString());
+
         removeOperationalData(ref.value as InstanceIdentifier<? extends DataObject>);
         commit()
     }
@@ -117,6 +126,8 @@ class NodeChangeCommiter implements OpendaylightInventoryListener {
             data.addAugmentation(FlowCapableNode, augment)
         }
 
+        LOG.debug("updating node : " + ref.value.toString());
+
         putOperationalData(ref.value as InstanceIdentifier<Node>, data.build())
         commit()
     }
index 5b947a5922589605abd146183802ffa07b6b84b4..e48ebbc0577f1b6101a772284ba9e07b3e6580cf 100644 (file)
@@ -149,8 +149,6 @@ public class BindingIndependentConnector implements //
 
     private RpcProviderRegistryImpl baRpcRegistryImpl;
 
-    private org.opendaylight.controller.sal.dom.broker.spi.RpcRouter biRouter;
-
     private NotificationProviderService baNotifyService;
 
     private NotificationPublishService domNotificationService;
@@ -319,9 +317,6 @@ public class BindingIndependentConnector implements //
                 baRpcRegistryImpl.registerRouterInstantiationListener(domToBindingRpcManager.getInstance());
                 baRpcRegistryImpl.registerGlobalRpcRegistrationListener(domToBindingRpcManager.getInstance());
             }
-            if (biRpcRegistry instanceof org.opendaylight.controller.sal.dom.broker.spi.RpcRouter) {
-                biRouter = (org.opendaylight.controller.sal.dom.broker.spi.RpcRouter) biRpcRegistry;
-            }
             rpcForwarding = true;
         }
     }
@@ -804,10 +799,10 @@ public class BindingIndependentConnector implements //
 
         @Override
         public Future<RpcResult<?>> forwardToDomBroker(DataObject input) {
-            if(biRouter != null) {
+            if(biRpcRegistry != null) {
                 CompositeNode xml = mappingService.toDataDom(input);
                 CompositeNode wrappedXml = ImmutableCompositeNode.create(rpc, ImmutableList.<Node<?>> of(xml));
-                RpcResult<CompositeNode> result = biRouter.invokeRpc(rpc, wrappedXml);
+                RpcResult<CompositeNode> result = biRpcRegistry.invokeRpc(rpc, wrappedXml);
                 Object baResultValue = null;
                 if (result.getResult() != null) {
                     baResultValue = mappingService.dataObjectFromDataDom(outputClass.get(), result.getResult());
@@ -867,10 +862,10 @@ public class BindingIndependentConnector implements //
 
         @Override
         public Future<RpcResult<?>> forwardToDomBroker(DataObject input) {
-            if(biRouter != null) {
+            if(biRpcRegistry != null) {
                 CompositeNode xml = mappingService.toDataDom(input);
                 CompositeNode wrappedXml = ImmutableCompositeNode.create(rpc,ImmutableList.<Node<?>>of(xml));
-                RpcResult<CompositeNode> result = biRouter.invokeRpc(rpc, wrappedXml);
+                RpcResult<CompositeNode> result = biRpcRegistry.invokeRpc(rpc, wrappedXml);
                 Object baResultValue = null;
                 RpcResult<?> baResult = Rpcs.<Void>getRpcResult(result.isSuccessful(), null, result.getErrors());
                 return Futures.<RpcResult<?>>immediateFuture(baResult);
index bfa4f36c18ca1d23f852a3da9c554942aa0b3e0e..274f084f01d420cf291723d96949382da5c0cd7d 100644 (file)
@@ -42,7 +42,7 @@ public class RoutingUtils {
         private final Map<C, Set<P>> removal;
         private final Map<C, Set<P>> announcement;
 
-        public RouteChangeImpl(ImmutableMap<C, Set<P>> removal, ImmutableMap<C, Set<P>> announcement) {
+        public RouteChangeImpl(ImmutableMap<C, Set<P>> announcement, ImmutableMap<C, Set<P>> removal) {
             super();
             this.removal = removal;
             this.announcement = announcement;
index 24cb99f8c367cd566c576f877cb6bcb20b6519e9..8a9d1678657c6b3555ba23d4a3c536cae5d3d30d 100644 (file)
@@ -14,7 +14,7 @@ import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
 
-public interface RpcProvisionRegistry extends BrokerService, RouteChangePublisher<RpcRoutingContext, InstanceIdentifier> {
+public interface RpcProvisionRegistry extends RpcImplementation, BrokerService, RouteChangePublisher<RpcRoutingContext, InstanceIdentifier> {
 
     /**
      * Registers an implementation of the rpc.
index aa5138a04db226d777c70dbd8ece6d3df5b77736..8f734d7d4c3934a22c1ca91af146534a0a5fac5b 100644 (file)
@@ -73,7 +73,7 @@ public class BrokerImpl implements Broker, RpcProvisionRegistry, AutoCloseable {
         return session;
     }
 
-    protected def Future<RpcResult<CompositeNode>> invokeRpc(QName rpc, CompositeNode input) {
+    protected def Future<RpcResult<CompositeNode>> invokeRpcAsync(QName rpc, CompositeNode input) {
         val result = executor.submit([|router.invokeRpc(rpc, input)] as Callable<RpcResult<CompositeNode>>);
         return result;
     }
@@ -135,5 +135,13 @@ public class BrokerImpl implements Broker, RpcProvisionRegistry, AutoCloseable {
     override <L extends RouteChangeListener<RpcRoutingContext, InstanceIdentifier>> registerRouteChangeListener(L listener) {
         return router.registerRouteChangeListener(listener);
     }
+
+    override invokeRpc(QName rpc,CompositeNode input){
+        return router.invokeRpc(rpc,input)
+    }
+
+    override getSupportedRpcs() {
+        return router.getSupportedRpcs();
+    }
     
 }
index e4808e9bd6ddfdc86dace504e67f8173eb1e8ca9..813f52b67d4bab0632fdefb6a9fe7d23d8054792 100644 (file)
@@ -37,7 +37,7 @@ class ConsumerContextImpl implements ConsumerSession {
     }
 
     override rpc(QName rpc, CompositeNode input) {
-        return broker.invokeRpc(rpc, input);
+        return broker.invokeRpcAsync(rpc, input);
     }
 
     override <T extends BrokerService> T getService(Class<T> service) {
index 5a3e060a3c9a52a2c55b4876b283ec5559de63e5..a8bdddb5108d3ab0242024b7c3db4df3a1d1694a 100644 (file)
@@ -219,4 +219,6 @@ public class MountPointImpl implements MountProvisionInstance, SchemaContextProv
             L listener) {
         return rpcs.registerRouteChangeListener(listener);
     }
+
+
 }
index e375e14cf2e96bf9e4ca29998a156df402ec3420..e218a957826f110bd36d3acb3fe059fc69b5092a 100644 (file)
@@ -16,9 +16,13 @@ import org.opendaylight.controller.sal.core.api.RpcRegistrationListener;
 import org.opendaylight.controller.sal.core.api.RpcRoutingContext;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
 import org.osgi.framework.ServiceReference;
 
+import java.util.Set;
+
 public class RpcProvisionRegistryProxy extends AbstractBrokerServiceProxy<RpcProvisionRegistry>
                                        implements RpcProvisionRegistry {
 
@@ -45,4 +49,15 @@ public class RpcProvisionRegistryProxy extends AbstractBrokerServiceProxy<RpcPro
     public <L extends RouteChangeListener<RpcRoutingContext, InstanceIdentifier>> ListenerRegistration<L> registerRouteChangeListener(L listener) {
         return getDelegate().registerRouteChangeListener(listener);
     }
+
+
+  @Override
+  public Set<QName> getSupportedRpcs() {
+    return getDelegate().getSupportedRpcs();
+  }
+
+  @Override
+  public RpcResult<CompositeNode> invokeRpc(QName rpc, CompositeNode input) {
+    return getDelegate().invokeRpc(rpc,input);
+  }
 }
index fec6bbe6b466519f9c5e8ed3cc5d89aa2558b66e..d2016b1f6337b6923662268ae7d8029d34ae85b0 100644 (file)
@@ -48,7 +48,7 @@ public class SimpleBroadcastHandlerImpl implements IBroadcastHandler, IListenDat
 
     protected ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
 
-    BroadcastMode mode = BroadcastMode.BROADCAST_TO_NONINTERNAL;
+    BroadcastMode mode = BroadcastMode.DISABLED;
 
     @Override
     public PacketResult receiveDataPacket(RawPacket inPkt) {
index 19f45e63c591dbde396e0929141c5c042a55adf5..615bb4df8379284df696363b9efd8461ec353f2b 100644 (file)
@@ -1004,7 +1004,8 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa
             }
         }
 
-        boolean proactiveForwarding = false;
+        boolean forwardingModeChanged = false;
+
         // copy node properties from config
         if (nodeConfigList != null) {
             String nodeId = node.toString();
@@ -1014,7 +1015,7 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa
                 propMap.putAll(nodeProperties);
                 if (nodeProperties.get(ForwardingMode.name) != null) {
                     ForwardingMode mode = (ForwardingMode) nodeProperties.get(ForwardingMode.name);
-                    proactiveForwarding = mode.isProactive();
+                    forwardingModeChanged = mode.isProactive();
                 }
             }
         }
@@ -1023,28 +1024,35 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa
             Property defaultMode = new ForwardingMode(ForwardingMode.REACTIVE_FORWARDING);
             propMap.put(ForwardingMode.name, defaultMode);
         }
-        boolean result = false;
-        if (propMapCurr == null) {
-            if (nodeProps.putIfAbsent(node, propMap) == null) {
-                result = true;
-            }
+
+        boolean propsAdded = false;
+        // Attempt initial add
+        if (nodeProps.putIfAbsent(node, propMap) == null) {
+                propsAdded = true;
+
+                /* Notify listeners only for initial node addition
+                 * to avoid expensive tasks triggered by redundant notifications
+                 */
+                notifyNode(node, UpdateType.ADDED, propMap);
         } else {
-            result = nodeProps.replace(node, propMapCurr, propMap);
+
+            propsAdded = nodeProps.replace(node, propMapCurr, propMap);
+
+            // check whether forwarding mode changed
+            if (propMapCurr.get(ForwardingMode.name) != null) {
+                ForwardingMode mode = (ForwardingMode) propMapCurr.get(ForwardingMode.name);
+                forwardingModeChanged ^= mode.isProactive();
+            }
         }
-        if (!result) {
-            log.debug("Cluster conflict: Conflict while adding the node properties. Node: {}  Properties: {}",
-                    node.getID(), props);
+        if (!propsAdded) {
+            log.debug("Cluster conflict while adding node {}. Overwriting with latest props: {}", node.getID(), props);
             addNodeProps(node, propMap);
         }
 
-        // check if span ports are configed
+        // check if span ports are configured
         addSpanPorts(node);
-
-        // notify node listeners
-        notifyNode(node, UpdateType.ADDED, propMap);
-
         // notify proactive mode forwarding
-        if (proactiveForwarding) {
+        if (forwardingModeChanged) {
             notifyModeChange(node, true);
         }
     }
@@ -1054,7 +1062,12 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa
         if (nodeProps == null) {
             return;
         }
-        nodeProps.remove(node);
+
+        if (nodeProps.remove(node) == null) {
+            log.debug("Received redundant node REMOVED udate for {}. Skipping..", node);
+            return;
+        }
+
         nodeConnectorNames.remove(node);
         Set<NodeConnector> removeNodeConnectorSet = new HashSet<NodeConnector>();
         for (Map.Entry<NodeConnector, Map<String, Property>> entry : nodeConnectorProps.entrySet()) {
@@ -1149,6 +1162,13 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa
 
         switch (type) {
         case ADDED:
+            // Skip redundant ADDED update (e.g. cluster switch-over)
+            if (nodeConnectorProps.containsKey(nodeConnector)) {
+                log.debug("Redundant nodeconnector ADDED for {}, props {} for container {}",
+                        nodeConnector, props, containerName);
+                update = false;
+            }
+
             if (props != null) {
                 for (Property prop : props) {
                     addNodeConnectorProp(nodeConnector, prop);
@@ -1158,6 +1178,7 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa
                 addNodeConnectorProp(nodeConnector, null);
             }
 
+
             addSpanPort(nodeConnector);
             break;
         case CHANGED:
@@ -2026,9 +2047,9 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa
         // only add if span is configured on this nodeConnector
         for (SpanConfig conf : getSpanConfigList(nodeConnector.getNode())) {
             if (conf.getPortArrayList().contains(nodeConnector)) {
-                List<NodeConnector> ncLists = new ArrayList<NodeConnector>();
-                ncLists.add(nodeConnector);
-                addSpanPorts(nodeConnector.getNode(), ncLists);
+                List<NodeConnector> ncList = new ArrayList<NodeConnector>();
+                ncList.add(nodeConnector);
+                addSpanPorts(nodeConnector.getNode(), ncList);
                 return;
             }
         }