ONOS-1636 Added code to mark devices offline when openflow provider is deactivated; fixed a few NPEs.

Change-Id: I5f0e90b14bf1f00abd58e12590a3339b93695122
diff --git a/providers/lldp/src/main/java/org/onosproject/provider/lldp/impl/LLDPLinkProvider.java b/providers/lldp/src/main/java/org/onosproject/provider/lldp/impl/LLDPLinkProvider.java
index 97c4d2f..a840f85 100644
--- a/providers/lldp/src/main/java/org/onosproject/provider/lldp/impl/LLDPLinkProvider.java
+++ b/providers/lldp/src/main/java/org/onosproject/provider/lldp/impl/LLDPLinkProvider.java
@@ -396,7 +396,7 @@
                     synchronized (discoverers) {
                         ld = discoverers.get(deviceId);
                         if (ld == null) {
-                            if (rules.isSuppressed(device)) {
+                            if (rules != null && rules.isSuppressed(device)) {
                                 log.debug("LinkDiscovery from {} disabled by configuration", device.id());
                                 return;
                             }
diff --git a/providers/openflow/device/src/main/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProvider.java b/providers/openflow/device/src/main/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProvider.java
index 0aea805..2108ba4 100644
--- a/providers/openflow/device/src/main/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProvider.java
+++ b/providers/openflow/device/src/main/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProvider.java
@@ -119,6 +119,7 @@
 public class OpenFlowDeviceProvider extends AbstractProvider implements DeviceProvider {
 
     private static final Logger LOG = getLogger(OpenFlowDeviceProvider.class);
+
     private static final long MBPS = 1_000 * 1_000;
     private static final Frequency FREQ100 = Frequency.ofGHz(100);
     private static final Frequency FREQ193_1 = Frequency.ofTHz(193.1);
@@ -158,27 +159,16 @@
         providerService = providerRegistry.register(this);
         controller.addListener(listener);
         controller.addEventListener(listener);
-        for (OpenFlowSwitch sw : controller.getSwitches()) {
-            try {
-                listener.switchAdded(new Dpid(sw.getId()));
-            } catch (Exception e) {
-                LOG.warn("Failed initially adding {} : {}", sw.getStringId(), e.getMessage());
-                LOG.debug("Error details:", e);
-                // disconnect to trigger switch-add later
-                sw.disconnectSwitch();
-            }
-            PortStatsCollector psc = new PortStatsCollector(sw, portStatsPollFrequency);
-            psc.start();
-            collectors.put(new Dpid(sw.getId()), psc);
-        }
+        connectInitialDevices();
         LOG.info("Started");
     }
 
     @Deactivate
     public void deactivate(ComponentContext context) {
         cfgService.unregisterProperties(getClass(), false);
-        providerRegistry.unregister(this);
         controller.removeListener(listener);
+        disconnectDevices();
+        providerRegistry.unregister(this);
         collectors.values().forEach(PortStatsCollector::stop);
         providerService = null;
         LOG.info("Stopped");
@@ -204,13 +194,31 @@
         LOG.info("Settings: portStatsPollFrequency={}", portStatsPollFrequency);
     }
 
+    private void connectInitialDevices() {
+        for (OpenFlowSwitch sw : controller.getSwitches()) {
+            try {
+                listener.switchAdded(new Dpid(sw.getId()));
+            } catch (Exception e) {
+                LOG.warn("Failed initially adding {} : {}", sw.getStringId(), e.getMessage());
+                LOG.debug("Error details:", e);
+                // disconnect to trigger switch-add later
+                sw.disconnectSwitch();
+            }
+            PortStatsCollector psc = new PortStatsCollector(sw, portStatsPollFrequency);
+            psc.start();
+            collectors.put(new Dpid(sw.getId()), psc);
+        }
+    }
+
+    private void disconnectDevices() {
+        // Only disconnect the devices for which we are currently master.
+        controller.getMasterSwitches().forEach(sw -> listener.switchRemoved(new Dpid(sw.getId())));
+    }
+
     @Override
     public boolean isReachable(DeviceId deviceId) {
         OpenFlowSwitch sw = controller.getSwitch(dpid(deviceId.uri()));
-        if (sw == null || !sw.isConnected()) {
-            return false;
-        }
-        return true;
+        return sw != null && sw.isConnected();
     }
 
     @Override
diff --git a/providers/openflow/device/src/test/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProviderTest.java b/providers/openflow/device/src/test/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProviderTest.java
index 7b4d792..d0838bb 100644
--- a/providers/openflow/device/src/test/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProviderTest.java
+++ b/providers/openflow/device/src/test/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProviderTest.java
@@ -16,6 +16,7 @@
 package org.onosproject.provider.of.device.impl;
 
 import com.google.common.collect.HashMultimap;
+import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Multimap;
 
@@ -236,7 +237,7 @@
 
         @Override
         public Iterable<OpenFlowSwitch> getMasterSwitches() {
-            return null;
+            return ImmutableSet.of();
         }
 
         @Override
diff --git a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/OpenFlowRuleProvider.java b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/OpenFlowRuleProvider.java
index 4c38d7a..6374ca5 100644
--- a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/OpenFlowRuleProvider.java
+++ b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/OpenFlowRuleProvider.java
@@ -273,7 +273,10 @@
 
         if (adaptiveFlowSampling) {
             // Add TypedFlowEntry to deviceFlowEntries in NewAdaptiveFlowStatsCollector
-            afsCollectors.get(dpid).addWithFlowRule(flowRule);
+            NewAdaptiveFlowStatsCollector collector = afsCollectors.get(dpid);
+            if (collector != null) {
+                collector.addWithFlowRule(flowRule);
+            }
         }
     }
 
@@ -299,7 +302,10 @@
 
         if (adaptiveFlowSampling) {
             // Remove TypedFlowEntry to deviceFlowEntries in NewAdaptiveFlowStatsCollector
-            afsCollectors.get(dpid).removeFlows(flowRule);
+            NewAdaptiveFlowStatsCollector collector = afsCollectors.get(dpid);
+            if (collector != null) {
+                collector.removeFlows(flowRule);
+            }
         }
     }
 
@@ -327,32 +333,30 @@
                 sw.sendMsg(msg);
                 continue;
             }
-            FlowModBuilder builder = FlowModBuilder.builder(fbe.target(), sw
-                    .factory(), Optional.of(batch.id()));
+            FlowModBuilder builder =
+                    FlowModBuilder.builder(fbe.target(), sw.factory(), Optional.of(batch.id()));
+            NewAdaptiveFlowStatsCollector collector = afsCollectors.get(dpid);
             switch (fbe.operator()) {
                 case ADD:
                     mod = builder.buildFlowAdd();
-
-                    if (adaptiveFlowSampling) {
+                    if (adaptiveFlowSampling && collector != null) {
                         // Add TypedFlowEntry to deviceFlowEntries in NewAdaptiveFlowStatsCollector
-                        afsCollectors.get(dpid).addWithFlowRule(fbe.target());
+                        collector.addWithFlowRule(fbe.target());
                     }
                     break;
                 case REMOVE:
                     mod = builder.buildFlowDel();
-
-                    if (adaptiveFlowSampling) {
+                    if (adaptiveFlowSampling && collector != null) {
                         // Remove TypedFlowEntry to deviceFlowEntries in NewAdaptiveFlowStatsCollector
-                        afsCollectors.get(dpid).removeFlows(fbe.target());
+                        collector.removeFlows(fbe.target());
                     }
                     break;
                 case MODIFY:
                     mod = builder.buildFlowMod();
-
-                    if (adaptiveFlowSampling) {
+                    if (adaptiveFlowSampling && collector != null) {
                         // Add or Update TypedFlowEntry to deviceFlowEntries in NewAdaptiveFlowStatsCollector
                         // afsCollectors.get(dpid).addWithFlowRule(fbe.target()); //check if add is good or not
-                        afsCollectors.get(dpid).addOrUpdateFlows((FlowEntry) fbe.target());
+                        collector.addOrUpdateFlows((FlowEntry) fbe.target());
                     }
                     break;
                 default:
@@ -424,7 +428,10 @@
 
                     if (adaptiveFlowSampling) {
                         // Removed TypedFlowEntry to deviceFlowEntries in NewAdaptiveFlowStatsCollector
-                        afsCollectors.get(dpid).flowRemoved(fr);
+                        NewAdaptiveFlowStatsCollector collector = afsCollectors.get(dpid);
+                        if (collector != null) {
+                            collector.flowRemoved(fr);
+                        }
                     }
                     break;
                 case STATS_REPLY: