VOL-458: NPE when executing ONOS aaa-users command after an disable ONU

Change-Id: I81720d2de540aee392b1038b443d8ed6c8fadc75
(cherry picked from commit 3f8ee43464a91bbd169cb44798c69291cdea853d)
diff --git a/src/main/java/org/opencord/aaa/AaaManager.java b/src/main/java/org/opencord/aaa/AaaManager.java
index ebe356c..7100704 100755
--- a/src/main/java/org/opencord/aaa/AaaManager.java
+++ b/src/main/java/org/opencord/aaa/AaaManager.java
@@ -41,6 +41,8 @@
 import org.onosproject.net.config.NetworkConfigEvent;
 import org.onosproject.net.config.NetworkConfigListener;
 import org.onosproject.net.config.NetworkConfigRegistry;
+import org.onosproject.net.device.DeviceEvent;
+import org.onosproject.net.device.DeviceListener;
 import org.onosproject.net.device.DeviceService;
 import org.onosproject.net.flow.DefaultTrafficTreatment;
 import org.onosproject.net.flow.TrafficTreatment;
@@ -63,6 +65,7 @@
 
 import java.net.InetAddress;
 import java.nio.ByteBuffer;
+import java.util.Map;
 
 /**
  * AAA application for ONOS.
@@ -98,6 +101,8 @@
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected AccessDeviceService accessDeviceService;
 
+    private final DeviceListener deviceListener = new InternalDeviceListener();
+
     // NAS IP address
     protected InetAddress nasIpAddress;
 
@@ -228,6 +233,8 @@
 
         impl.requestIntercepts();
 
+        deviceService.addListener(deviceListener);
+
         log.info("Started");
     }
 
@@ -240,6 +247,7 @@
         StateMachine.destroyMaps();
         netCfgService.removeListener(cfgListener);
         impl.deactivate();
+        deviceService.removeListener(deviceListener);
 
         log.info("Stopped");
     }
@@ -586,4 +594,27 @@
             }
         }
     }
+
+    private class InternalDeviceListener implements DeviceListener {
+        @Override
+        public void event(DeviceEvent event) {
+
+            switch (event.type()) {
+                case PORT_REMOVED:
+                    DeviceId devId = event.subject().id();
+                    PortNumber portNumber = event.port().number();
+                    String sessionId = devId.toString() + portNumber.toString();
+
+                    Map<String, StateMachine> sessionIdMap = StateMachine.sessionIdMap();
+                    StateMachine removed = sessionIdMap.remove(sessionId);
+                    if (removed != null) {
+                        StateMachine.deleteStateMachineMapping(removed);
+                    }
+
+                    break;
+                default:
+                    return;
+            }
+        }
+    }
 }
diff --git a/src/main/java/org/opencord/aaa/AaaShowUsersCommand.java b/src/main/java/org/opencord/aaa/AaaShowUsersCommand.java
index e64a6fe..f05dd8a 100644
--- a/src/main/java/org/opencord/aaa/AaaShowUsersCommand.java
+++ b/src/main/java/org/opencord/aaa/AaaShowUsersCommand.java
@@ -46,13 +46,20 @@
         for (StateMachine stateMachine : StateMachine.sessionIdMap().values()) {
             String deviceId = stateMachine.supplicantConnectpoint().deviceId().toString();
             String portNum = stateMachine.supplicantConnectpoint().port().toString();
-            String username = new String(stateMachine.username());
-            String mac = stateMachine.supplicantAddress().toString();
+
+            String username = "UNKNOWN";
+            if (stateMachine.username() != null) {
+                username = new String(stateMachine.username());
+            }
+            String mac = "UNKNOWN";
+            if (stateMachine.supplicantAddress() != null) {
+                mac = stateMachine.supplicantAddress().toString();
+            }
 
             String nasPortId = devService.getPort(stateMachine.supplicantConnectpoint()).
                     annotations().value(AnnotationKeys.PORT_NAME);
 
-            String subsId = "Unknown";
+            String subsId = "UNKNOWN";
             SubscriberAndDeviceInformation subscriber = subsService.get(nasPortId);
             if (subscriber != null) {
                 subsId = subscriber.nasPortId();
diff --git a/src/main/java/org/opencord/aaa/SamplePacketCustomizer.java b/src/main/java/org/opencord/aaa/SamplePacketCustomizer.java
index 358890e..bc8a0d4 100755
--- a/src/main/java/org/opencord/aaa/SamplePacketCustomizer.java
+++ b/src/main/java/org/opencord/aaa/SamplePacketCustomizer.java
@@ -102,9 +102,8 @@
         inPkt.setAttribute(RADIUSAttribute.RADIUS_ATTR_NAS_PORT_TYPE,
                 ByteBuffer.allocate(4).putInt(15).array());
 
-        // Check - This may not be needed but was used in PoC2
         inPkt.setAttribute(RADIUSAttribute.RADIUS_ATTR_NAS_PORT,
-                ByteBuffer.allocate(4).putInt(46178304).array());
+                ByteBuffer.allocate(4).putInt((int) p.number().toLong()).array());
         // Check - If this is needed, worked with this value in PoC2
         inPkt.setAttribute(RADIUSAttribute.RADIUS_ATTR_ACCT_SESSION_ID,
                 "023:27:46:00000".getBytes());
diff --git a/src/test/java/org/opencord/aaa/AaaManagerTest.java b/src/test/java/org/opencord/aaa/AaaManagerTest.java
index dadcc71..456c7b6 100644
--- a/src/test/java/org/opencord/aaa/AaaManagerTest.java
+++ b/src/test/java/org/opencord/aaa/AaaManagerTest.java
@@ -120,6 +120,8 @@
         aaaManager.netCfgService = new TestNetworkConfigRegistry();
         aaaManager.coreService = new CoreServiceAdapter();
         aaaManager.packetService = new MockPacketService();
+        aaaManager.deviceService = new TestDeviceService();
+        aaaManager.subsService = new MockSubService();
         aaaManager.activate();
     }
 
diff --git a/src/test/java/org/opencord/aaa/AaaTestBase.java b/src/test/java/org/opencord/aaa/AaaTestBase.java
index 2c72d9c..cb2c5d1 100644
--- a/src/test/java/org/opencord/aaa/AaaTestBase.java
+++ b/src/test/java/org/opencord/aaa/AaaTestBase.java
@@ -20,7 +20,16 @@
 import org.onlab.packet.EAPOL;
 import org.onlab.packet.EthType;
 import org.onlab.packet.Ethernet;
+import org.onlab.packet.Ip4Address;
 import org.onlab.packet.MacAddress;
+import org.onlab.packet.VlanId;
+
+import org.onosproject.net.Annotations;
+import org.onosproject.net.device.DeviceServiceAdapter;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.Element;
+import org.onosproject.net.Port;
+import org.onosproject.net.PortNumber;
 import org.onosproject.net.packet.DefaultInboundPacket;
 import org.onosproject.net.packet.DefaultPacketContext;
 import org.onosproject.net.packet.InboundPacket;
@@ -29,10 +38,14 @@
 import org.onosproject.net.packet.PacketProcessor;
 import org.onosproject.net.packet.PacketServiceAdapter;
 
+import org.opencord.sadis.SubscriberAndDeviceInformation;
+import org.opencord.sadis.SubscriberAndDeviceInformationService;
+
 import java.nio.ByteBuffer;
 import java.security.MessageDigest;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Set;
 
 import static org.hamcrest.Matchers.instanceOf;
 import static org.hamcrest.Matchers.is;
@@ -87,6 +100,88 @@
     }
 
     /**
+     * Mocks the DeviceService.
+     */
+    final class TestDeviceService extends DeviceServiceAdapter {
+        @Override
+        public Port getPort(ConnectPoint cp) {
+            return new MockPort();
+        }
+    }
+    private class  MockPort implements Port {
+
+        @Override
+        public boolean isEnabled() {
+            return true;
+        }
+        public long portSpeed() {
+            return 1000;
+        }
+        public Element element() {
+            return null;
+        }
+        public PortNumber number() {
+            return null;
+        }
+        public Annotations annotations() {
+            return new MockAnnotations();
+        }
+        public Type type() {
+            return Port.Type.FIBER;
+        }
+
+        private class MockAnnotations implements Annotations {
+
+            @Override
+            public String value(String val) {
+                return "PON 1/1";
+            }
+            public Set<String> keys() {
+                return null;
+            }
+        }
+    }
+
+    private class MockSubscriberAndDeviceInformation extends SubscriberAndDeviceInformation {
+
+        MockSubscriberAndDeviceInformation(String id, VlanId ctag,
+                                           VlanId stag, String nasPortId,
+                                           String circuitId, MacAddress hardId,
+                                           Ip4Address ipAddress) {
+            this.setCTag(ctag);
+            this.setHardwareIdentifier(hardId);
+            this.setId(id);
+            this.setIPAddress(ipAddress);
+            this.setSTag(stag);
+            this.setNasPortId(nasPortId);
+            this.setCircuitId(circuitId);
+        }
+    }
+
+    final class MockSubService implements SubscriberAndDeviceInformationService {
+        private final VlanId clientCtag = VlanId.vlanId((short) 999);
+        private final VlanId clientStag = VlanId.vlanId((short) 111);
+        private final String clientNasPortId = "PON 1/1";
+        private final String clientCircuitId = "CIR-PON 1/1";
+
+        MockSubscriberAndDeviceInformation sub =
+                new MockSubscriberAndDeviceInformation(clientNasPortId, clientCtag,
+                        clientStag, clientNasPortId, clientCircuitId, null, null);
+        @Override
+        public SubscriberAndDeviceInformation get(String id) {
+
+                return  sub;
+
+        }
+
+        @Override
+        public void invalidateAll() {}
+        public void invalidateId(String id) {}
+        public SubscriberAndDeviceInformation getfromCache(String id) {
+            return null;
+        }
+    }
+    /**
      * Mocks the DefaultPacketContext.
      */
     final class TestPacketContext extends DefaultPacketContext {