Deleted device manager's inside global cache and changed to use the topo cache.
The reason is it caused some unmatched condition with the topo cache when link and port status was changed.
The DeviceEvent timing is changed.
The old one sends it when it is appeared, or attachment point or IP is changed, but now it sends every packet-in to update last-time-seen.

Note:
Looks like there is some vulnerability for changing the mastership of switches.
During mastership changes, the intent reroute is occured, and for a short period of time links or ports haven't found,
so the intent cann't calcurate its path.

Change-Id: I311fa5ad368ca833915999ad112274f1a7979387
diff --git a/src/main/java/net/onrc/onos/apps/forwarding/Forwarding.java b/src/main/java/net/onrc/onos/apps/forwarding/Forwarding.java
index d955828..03c9740 100644
--- a/src/main/java/net/onrc/onos/apps/forwarding/Forwarding.java
+++ b/src/main/java/net/onrc/onos/apps/forwarding/Forwarding.java
@@ -560,6 +560,8 @@
                     break;
                 case STATE_CHANGED:
                     IntentState state = pathIntent.getState();
+                    log.debug("This is STATE_CHANGED. intent id {} is now state {}",
+                            pathIntent.getId() , state);
                     switch (state) {
                         case INST_REQ:
                             break;
diff --git a/src/main/java/net/onrc/onos/core/devicemanager/OnosDevice.java b/src/main/java/net/onrc/onos/core/devicemanager/OnosDevice.java
index d0a5ee4..1a2bdeb 100644
--- a/src/main/java/net/onrc/onos/core/devicemanager/OnosDevice.java
+++ b/src/main/java/net/onrc/onos/core/devicemanager/OnosDevice.java
@@ -19,9 +19,12 @@
 
 import java.io.Serializable;
 import java.util.Date;
+import java.util.Objects;
 
 import net.floodlightcontroller.util.MACAddress;
 
+
+
 /**
  * An entity on the network is a visible trace of a device that corresponds
  * to a packet received from a particular interface on the edge of a network,
@@ -53,13 +56,13 @@
      * The DPID of the switch for the ingress point for this entity,
      * or null if not present.
      */
-    private long switchDPID;
+    private Long switchDPID;
 
     /**
      * The port number of the switch for the ingress point for this entity,
      * or null if not present.
      */
-    private short switchPort;
+    private Long switchPort;
 
     /**
      * The last time we observed this entity on the network.
@@ -75,16 +78,16 @@
     }
 
     /**
-     * Create a new entity.
+     * Create a new device and its information.
      *
-     * @param macAddress
-     * @param vlan
-     * @param switchDPID
-     * @param switchPort
-     * @param lastSeenTimestamp
+     * @param macAddress mac address of this device
+     * @param vlan vlan ID of this device
+     * @param switchDPID switch DPID where the device is attached
+     * @param switchPort port number where the device is attached
+     * @param lastSeenTimestamp last packet-in time of this device
      */
     public OnosDevice(MACAddress macAddress, Short vlan, Long switchDPID,
-            short switchPort, Date lastSeenTimestamp) {
+            Long switchPort, Date lastSeenTimestamp) {
         this.macAddress = macAddress;
         this.vlan = vlan;
         this.switchDPID = switchDPID;
@@ -112,18 +115,10 @@
         return switchDPID;
     }
 
-    public void setSwitchDPID(long dpid) {
-        this.switchDPID = dpid;
-    }
-
-    public short getSwitchPort() {
+    public Long getSwitchPort() {
         return switchPort;
     }
 
-    public void setSwitchPort(short port) {
-        this.switchPort = port;
-    }
-
     public Date getLastSeenTimestamp() {
         if (this.lastSeenTimestamp == null) {
             return null;
@@ -137,14 +132,11 @@
 
     @Override
     public int hashCode() {
-        if (hashCode != 0) {
-            return hashCode;
-        }
         final int prime = 31;
         hashCode = 1;
         hashCode = prime * hashCode + (int) (macAddress.toLong() ^ (macAddress.toLong() >>> 32));
-        hashCode = prime * hashCode + (int) switchDPID;
-        hashCode = prime * hashCode + (int) switchPort;
+        hashCode = prime * hashCode + ((switchDPID == null) ? 0 : switchDPID.hashCode());
+        hashCode = prime * hashCode + ((switchPort == null) ? 0 : switchPort.hashCode());
         hashCode = prime * hashCode + ((vlan == null) ? 0 : vlan.hashCode());
         return hashCode;
     }
@@ -164,24 +156,16 @@
         if (hashCode() != other.hashCode()) {
             return false;
         }
-        if (macAddress == null) {
-            if (other.macAddress != null) {
-                return false;
-            }
-        } else if (!macAddress.equals(other.macAddress)) {
+        if (!Objects.equals(macAddress, other.macAddress)) {
             return false;
         }
-        if (switchDPID != other.switchDPID) {
+        if (!Objects.equals(switchDPID, other.switchDPID)) {
             return false;
         }
-        if (switchPort != other.switchPort) {
+        if (!Objects.equals(switchPort, other.switchPort)) {
             return false;
         }
-        if (vlan == null) {
-            if (other.vlan != null) {
-                return false;
-            }
-        } else if (!vlan.equals(other.vlan)) {
+        if (!Objects.equals(vlan, other.vlan)) {
             return false;
         }
         return true;
diff --git a/src/main/java/net/onrc/onos/core/devicemanager/OnosDeviceManager.java b/src/main/java/net/onrc/onos/core/devicemanager/OnosDeviceManager.java
index 23944a0..0c7a75e 100644
--- a/src/main/java/net/onrc/onos/core/devicemanager/OnosDeviceManager.java
+++ b/src/main/java/net/onrc/onos/core/devicemanager/OnosDeviceManager.java
@@ -8,7 +8,6 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.Executors;
 import java.util.concurrent.ScheduledExecutorService;
@@ -24,11 +23,10 @@
 import net.floodlightcontroller.core.module.IFloodlightModule;
 import net.floodlightcontroller.core.module.IFloodlightService;
 import net.floodlightcontroller.util.MACAddress;
-import net.onrc.onos.core.datagrid.IDatagridService;
-import net.onrc.onos.core.datagrid.IEventChannel;
-import net.onrc.onos.core.datagrid.IEventChannelListener;
 import net.onrc.onos.core.packet.Ethernet;
+import net.onrc.onos.core.topology.Device;
 import net.onrc.onos.core.topology.ITopologyService;
+import net.onrc.onos.core.topology.Port;
 import net.onrc.onos.core.topology.Topology;
 
 import org.openflow.protocol.OFMessage;
@@ -39,8 +37,7 @@
 
 public class OnosDeviceManager implements IFloodlightModule,
         IOFMessageListener,
-        IOnosDeviceService,
-        IEventChannelListener<Long, OnosDevice> {
+        IOnosDeviceService {
 
     private static final Logger log = LoggerFactory.getLogger(OnosDeviceManager.class);
     private static final long DEVICE_CLEANING_INITIAL_DELAY = 30;
@@ -52,16 +49,6 @@
     private static final ScheduledExecutorService EXECUTOR_SERVICE =
             Executors.newSingleThreadScheduledExecutor();
 
-    // TODO This infrastructure maintains a global device cache in the
-    // OnosDeviceManager module on each instance (in mapDevice). We want to
-    // remove this eventually - the global cache should be maintained by the
-    // topology layer (which it currently is as well).
-    private IDatagridService datagrid;
-    private IEventChannel<Long, OnosDevice> eventChannel;
-    private static final String DEVICE_CHANNEL_NAME = "onos.device";
-    private final Map<Long, OnosDevice> mapDevice =
-            new ConcurrentHashMap<Long, OnosDevice>();
-
     private ITopologyService topologyService;
     private Topology topology;
 
@@ -129,6 +116,10 @@
     // The above "receive" method couldn't be tested
     // because of IFloodlightProviderService static final field.
     protected Command processPacketIn(IOFSwitch sw, OFPacketIn pi, Ethernet eth) {
+        if (log.isTraceEnabled()) {
+            log.trace("Receive PACKET_IN swId {}, portId {}", sw.getId(), pi.getInPort());
+        }
+
         long dpid = sw.getId();
         short portId = pi.getInPort();
         Long mac = eth.getSourceMAC().toLong();
@@ -140,31 +131,21 @@
             return Command.STOP;
         }
 
-        // We check if it is the same device in datagrid to suppress the device update
-        OnosDevice exDev = mapDevice.get(mac);
-        if (exDev != null && exDev.equals(srcDevice)) {
-            // There is the same existing device. Update only ActiveSince time.
-            // TODO This doesn't update the timestamp in the Topology module,
-            // only in the local cache in this local driver module.
-            exDev.setLastSeenTimestamp(new Date());
-            if (log.isTraceEnabled()) {
-                log.trace("In the local cache, there is the same device."
-                        + " Only update last seen time: {}", exDev);
-            }
-            return Command.CONTINUE;
-        }
-
         // If the switch port we try to attach a new device already has a link,
         // then don't add the device
         // TODO We probably don't need to check this here, it should be done in
         // the Topology module.
-        if (topology.getOutgoingLink(dpid, (long) portId) != null) {
-            if (log.isTraceEnabled()) {
-                log.trace("Stop adding OnosDevice {} as " +
-                        "there is a link on the port: dpid {} port {}",
-                        srcDevice.getMacAddress(), dpid, portId);
+        topology.acquireReadLock();
+        try {
+            if (topology.getOutgoingLink(dpid, (long) portId) != null ||
+                    topology.getIncomingLink(dpid, (long) portId) != null) {
+                log.debug("Stop adding OnosDevice {} as " +
+                    "there is a link on the port: dpid {} port {}",
+                    srcDevice.getMacAddress(), dpid, portId);
+                return Command.CONTINUE;
             }
-            return Command.CONTINUE;
+        } finally {
+            topology.releaseReadLock();
         }
 
         addOnosDevice(mac, srcDevice);
@@ -187,28 +168,30 @@
         @Override
         public void run() {
             log.debug("called CleanDevice");
+            topology.acquireReadLock();
             try {
-                Set<OnosDevice> deleteSet = new HashSet<OnosDevice>();
-                for (OnosDevice dev : mapDevice.values()) {
-                    long now = new Date().getTime();
-                    if ((now - dev.getLastSeenTimestamp().getTime()
-                            > agingMillisecConfig)) {
+                Set<Device> deleteSet = new HashSet<Device>();
+                for (Device dev : topology.getDevices()) {
+                    long now = System.currentTimeMillis();
+                    if ((now - dev.getLastSeenTime() > agingMillisecConfig)) {
                         if (log.isTraceEnabled()) {
-                            log.debug("Removing device info from the datagrid: {}, diff {}",
-                                    dev, now - dev.getLastSeenTimestamp().getTime());
+                            log.trace("Removing device info: mac {}, now {}, lastSeenTime {}, diff {}",
+                                    dev.getMacAddress(), now, dev.getLastSeenTime(), now - dev.getLastSeenTime());
                         }
                         deleteSet.add(dev);
                     }
                 }
 
-                for (OnosDevice dev : deleteSet) {
-                    deleteOnosDevice(dev);
+                for (Device dev : deleteSet) {
+                    deleteOnosDeviceByMac(dev.getMacAddress());
                 }
             } catch (Exception e) {
                 // Any exception thrown by the task will prevent the Executor
                 // from running the next iteration, so we need to catch and log
                 // all exceptions here.
                 log.error("Exception in device cleanup thread:", e);
+            } finally {
+                topology.releaseReadLock();
             }
         }
     }
@@ -223,7 +206,7 @@
      */
     protected OnosDevice getSourceDeviceFromPacket(Ethernet eth,
             long swdpid,
-            short port) {
+            long port) {
         MACAddress sourceMac = eth.getSourceMAC();
 
         // Ignore broadcast/multicast source
@@ -261,7 +244,6 @@
                 new ArrayList<Class<? extends IFloodlightService>>();
         dependencies.add(IFloodlightProviderService.class);
         dependencies.add(ITopologyService.class);
-        dependencies.add(IDatagridService.class);
         return dependencies;
     }
 
@@ -270,7 +252,6 @@
             throws FloodlightModuleException {
         floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
         deviceListeners = new CopyOnWriteArrayList<IOnosDeviceListener>();
-        datagrid = context.getServiceImpl(IDatagridService.class);
         topologyService = context.getServiceImpl(ITopologyService.class);
         topology = topologyService.getTopology();
 
@@ -280,56 +261,48 @@
     @Override
     public void startUp(FloodlightModuleContext context) {
         floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this);
-        eventChannel = datagrid.addListener(DEVICE_CHANNEL_NAME, this,
-                Long.class,
-                OnosDevice.class);
         EXECUTOR_SERVICE.scheduleAtFixedRate(new CleanDevice(),
                 DEVICE_CLEANING_INITIAL_DELAY, cleanupSecondConfig, TimeUnit.SECONDS);
     }
 
     @Override
     public void deleteOnosDevice(OnosDevice dev) {
-        Long mac = dev.getMacAddress().toLong();
-        eventChannel.removeEntry(mac);
         floodlightProvider.publishUpdate(
                 new OnosDeviceUpdate(dev, OnosDeviceUpdateType.DELETE));
     }
 
     @Override
     public void deleteOnosDeviceByMac(MACAddress mac) {
-        OnosDevice deleteDevice = mapDevice.get(mac.toLong());
-        deleteOnosDevice(deleteDevice);
+        OnosDevice deleteDevice = null;
+        topology.acquireReadLock();
+        try {
+            Device dev = topology.getDeviceByMac(mac);
+
+            for (Port switchPort : dev.getAttachmentPoints()) {
+                // We don't handle vlan now and multiple attachment points.
+                deleteDevice = new OnosDevice(dev.getMacAddress(),
+                        null,
+                        switchPort.getDpid(),
+                        switchPort.getNumber(),
+                        new Date(dev.getLastSeenTime()));
+                break;
+            }
+        } finally {
+            topology.releaseReadLock();
+        }
+
+        if (deleteDevice != null) {
+            deleteOnosDevice(deleteDevice);
+        }
     }
 
     @Override
     public void addOnosDevice(Long mac, OnosDevice dev) {
-        eventChannel.addEntry(mac, dev);
         floodlightProvider.publishUpdate(
                 new OnosDeviceUpdate(dev, OnosDeviceUpdateType.ADD));
     }
 
     @Override
-    public void entryAdded(OnosDevice dev) {
-        Long mac = dev.getMacAddress().toLong();
-        mapDevice.put(mac, dev);
-        log.debug("Device added into local Cache: device mac {}", mac);
-    }
-
-    @Override
-    public void entryRemoved(OnosDevice dev) {
-        Long mac = dev.getMacAddress().toLong();
-        mapDevice.remove(mac);
-        log.debug("Device removed into local Cache: device mac {}", mac);
-    }
-
-    @Override
-    public void entryUpdated(OnosDevice dev) {
-        Long mac = dev.getMacAddress().toLong();
-        mapDevice.put(mac, dev);
-        log.debug("Device updated into local Cache: device mac {}", mac);
-    }
-
-    @Override
     public void addOnosDeviceListener(IOnosDeviceListener listener) {
         deviceListeners.add(listener);
     }
diff --git a/src/main/java/net/onrc/onos/core/intent/runtime/PlanInstallModule.java b/src/main/java/net/onrc/onos/core/intent/runtime/PlanInstallModule.java
index b74514c..025b6d7 100644
--- a/src/main/java/net/onrc/onos/core/intent/runtime/PlanInstallModule.java
+++ b/src/main/java/net/onrc/onos/core/intent/runtime/PlanInstallModule.java
@@ -340,7 +340,8 @@
                 states.domainSwitchDpids.addAll(domainSwitchDpids);
             }
             parentIntentMap.remove(intentParentId);
-            log.debug("addEntry to intentStateChannel intentId {}, states {}", flowRemovedMsg.getCookie(), states);
+            log.debug("addEntry to intentStateChannel intentId {}, states {}",
+                    pathIntentId, newState);
 
             intentStateChannel.addTransientEntry(flowRemovedMsg.getCookie(), states);
         }
diff --git a/src/main/java/net/onrc/onos/core/topology/DeviceImpl.java b/src/main/java/net/onrc/onos/core/topology/DeviceImpl.java
index fc1628e..0ba23dd 100644
--- a/src/main/java/net/onrc/onos/core/topology/DeviceImpl.java
+++ b/src/main/java/net/onrc/onos/core/topology/DeviceImpl.java
@@ -47,19 +47,19 @@
     /**
      * Only {@link TopologyManager} should use this method.
      *
-     * @param p
+     * @param port the port that the device is attached to
      */
-    void addAttachmentPoint(Port p) {
-        this.attachmentPoints.remove(p);
-        this.attachmentPoints.addFirst(p);
+    void addAttachmentPoint(Port port) {
+        this.attachmentPoints.remove(port);
+        this.attachmentPoints.addFirst(port);
     }
 
     /**
      * Only {@link TopologyManager} should use this method.
      *
-     * @param p
+     * @param port the port that the device is attached to
      */
-    boolean removeAttachmentPoint(Port p) {
-        return this.attachmentPoints.remove(p);
+    boolean removeAttachmentPoint(Port port) {
+        return this.attachmentPoints.remove(port);
     }
 }
diff --git a/src/main/java/net/onrc/onos/core/topology/TopologyManager.java b/src/main/java/net/onrc/onos/core/topology/TopologyManager.java
index 8e0a4e6..343102b 100644
--- a/src/main/java/net/onrc/onos/core/topology/TopologyManager.java
+++ b/src/main/java/net/onrc/onos/core/topology/TopologyManager.java
@@ -1085,6 +1085,8 @@
             attachmentFound = true;
         }
 
+        deviceImpl.setLastSeenTime(deviceEvent.getLastSeenTime());
+
         // Update the device in the topology
         if (attachmentFound) {
             log.debug("Storing the device info into the Topology: mac {}", deviceEvent.getMac());
diff --git a/src/main/java/net/onrc/onos/core/topology/TopologyPublisher.java b/src/main/java/net/onrc/onos/core/topology/TopologyPublisher.java
index 36399bc..eb76c1e 100644
--- a/src/main/java/net/onrc/onos/core/topology/TopologyPublisher.java
+++ b/src/main/java/net/onrc/onos/core/topology/TopologyPublisher.java
@@ -307,8 +307,7 @@
     public void onosDeviceAdded(OnosDevice device) {
         log.debug("Called onosDeviceAdded mac {}", device.getMacAddress());
 
-        SwitchPort sp = new SwitchPort(device.getSwitchDPID(),
-                (long) device.getSwitchPort());
+        SwitchPort sp = new SwitchPort(device.getSwitchDPID(), device.getSwitchPort());
         List<SwitchPort> spLists = new ArrayList<SwitchPort>();
         spLists.add(sp);
         DeviceEvent event = new DeviceEvent(device.getMacAddress());
diff --git a/src/test/java/net/onrc/onos/core/devicemanager/OnosDeviceManagerTest.java b/src/test/java/net/onrc/onos/core/devicemanager/OnosDeviceManagerTest.java
index 0b9defb..22900cc 100644
--- a/src/test/java/net/onrc/onos/core/devicemanager/OnosDeviceManagerTest.java
+++ b/src/test/java/net/onrc/onos/core/devicemanager/OnosDeviceManagerTest.java
@@ -7,7 +7,6 @@
 import static org.easymock.EasyMock.expect;
 import static org.easymock.EasyMock.expectLastCall;
 import static org.easymock.EasyMock.replay;
-import static org.easymock.EasyMock.verify;
 
 import java.util.Date;
 
@@ -16,12 +15,12 @@
 import net.floodlightcontroller.core.IOFSwitch;
 import net.floodlightcontroller.core.IUpdate;
 import net.floodlightcontroller.core.module.FloodlightModuleContext;
+import net.floodlightcontroller.core.module.FloodlightModuleException;
 import net.floodlightcontroller.test.FloodlightTestCase;
 import net.floodlightcontroller.util.MACAddress;
 import net.onrc.onos.core.datagrid.IDatagridService;
 import net.onrc.onos.core.datagrid.IEventChannel;
 import net.onrc.onos.core.datagrid.IEventChannelListener;
-import net.onrc.onos.core.intent.MockTopology;
 import net.onrc.onos.core.packet.ARP;
 import net.onrc.onos.core.packet.DHCP;
 import net.onrc.onos.core.packet.Data;
@@ -32,6 +31,7 @@
 import net.onrc.onos.core.registry.IControllerRegistryService;
 import net.onrc.onos.core.topology.ITopologyListener;
 import net.onrc.onos.core.topology.ITopologyService;
+import net.onrc.onos.core.topology.MockTopology;
 
 import org.easymock.EasyMock;
 import org.junit.After;
@@ -51,9 +51,9 @@
     private IPacket pkt0, pkt1, pkt2, pkt3, pkt4;
     private IOFSwitch sw1;
     private long sw1Dpid;
-    private short sw1DevPort;
+    private long sw1DevPort, sw1DevPort2;
     private OnosDeviceManager odm;
-    private OFPacketIn pktIn;
+    private OFPacketIn pktIn, pktIn2;
     private FloodlightModuleContext modContext;
     private ITopologyService networkGraphService;
     private IEventChannel<Long, OnosDevice> eventChannel;
@@ -69,7 +69,7 @@
         IDatagridService datagridService;
         IControllerRegistryService controllerRegistryService;
 
-        topology.createSampleTopology1();
+        topology.createSampleTopology2();
         modContext = new FloodlightModuleContext();
 
         floodLightProvider = createMock(IFloodlightProviderService.class);
@@ -104,6 +104,7 @@
         replay(sw1);
 
         sw1DevPort = 100;
+        sw1DevPort2 = 12L;
 
         odm = new OnosDeviceManager();
         /*
@@ -201,13 +202,11 @@
                 .setTargetProtocolAddress(IPv4.toIPv4AddressBytes("192.168.1.2")));
 
 
-        this.pktIn = new OFPacketIn()
-        .setInPort(sw1DevPort);
+        this.pktIn = new OFPacketIn().setInPort((short) sw1DevPort);
+
+        this.pktIn2 = new OFPacketIn().setInPort((short) sw1DevPort2);
 
         lastSeenTimestamp = new Date(1);
-
-        odm.init(modContext);
-        odm.startUp(modContext);
     }
 
     @Override
@@ -264,30 +263,46 @@
 
     /**
      * This test will invoke addOnosDevice to add a new device through Packet pkt1.
+     * @throws FloodlightModuleException
      */
     @Test
-    public void testProcessPacketInAddNewDevice() {
-        Ethernet eth = (Ethernet) pkt1;
-        Long longmac = eth.getSourceMAC().toLong();
-        OnosDevice srcDevice = odm.getSourceDeviceFromPacket(eth, sw1Dpid, sw1DevPort);
-
-        floodLightProvider.addOFMessageListener(EasyMock.eq(OFType.PACKET_IN), EasyMock.isA(OnosDeviceManager.class));
-        EasyMock.expectLastCall();
-        eventChannel.addEntry(longmac, srcDevice);
+    public void testProcessPacketInAddNewDevice() throws FloodlightModuleException {
+        floodLightProvider.addOFMessageListener(EasyMock.eq(OFType.PACKET_IN),
+                EasyMock.isA(OnosDeviceManager.class));
         EasyMock.expectLastCall();
         floodLightProvider.publishUpdate(EasyMock.isA(IUpdate.class));
         EasyMock.expectLastCall();
-        replay(floodLightProvider, eventChannel);
+        replay(floodLightProvider);
 
+        odm.init(modContext);
+        odm.startUp(modContext);
         Command cmd = odm.processPacketIn(sw1, pktIn, (Ethernet) pkt1);
         assertEquals(Command.CONTINUE, cmd);
 
-        verify(eventChannel);
+        EasyMock.verify(floodLightProvider);
     }
 
     /**
-     * This test will test return Command.STOP path in processPacketIn method
-     * by injecting a broadcast packet.
+     * Test ProcessPacket function.
+     * @throws FloodlightModuleException
+     */
+    @Test
+    public void testProcessPacketInHasLink() throws FloodlightModuleException {
+        floodLightProvider.addOFMessageListener(EasyMock.eq(OFType.PACKET_IN),
+                EasyMock.isA(OnosDeviceManager.class));
+        EasyMock.expectLastCall();
+        replay(floodLightProvider);
+
+        odm.init(modContext);
+        odm.startUp(modContext);
+        Command cmd = odm.processPacketIn(sw1, pktIn2, (Ethernet) pkt1);
+        assertEquals(Command.CONTINUE, cmd);
+
+        EasyMock.verify(floodLightProvider);
+    }
+
+    /**
+     * Test return Command.STOP path in processPacketIn method by injecting a broadcast packet.
      */
     @Test
     public void testProcessPacketInStop() {
@@ -296,99 +311,69 @@
     }
 
     /**
-     * This tests same packet received case.
-     */
-    @Test
-    public void testProcessPacketInSamePacket() {
-        Ethernet eth = (Ethernet) pkt2;
-        OnosDevice srcDevice = odm.getSourceDeviceFromPacket(eth, sw1Dpid, sw1DevPort);
-        odm.entryAdded(srcDevice);
-        srcDevice.setLastSeenTimestamp(lastSeenTimestamp);
-
-        Command cmd = odm.processPacketIn(sw1, pktIn, (Ethernet) pkt2);
-        assertEquals(Command.CONTINUE, cmd);
-        assertTrue(lastSeenTimestamp.before(srcDevice.getLastSeenTimestamp()));
-    }
-
-    /**
-     * This tests the packet with the same MAC but the second one without IP address.
-     */
-    @Test
-    public void testProcessPacketInNoIpAddress() {
-        Ethernet eth = (Ethernet) pkt3;
-        OnosDevice srcDevice = odm.getSourceDeviceFromPacket(eth, sw1Dpid, sw1DevPort);
-        odm.entryAdded(srcDevice);
-        srcDevice.setLastSeenTimestamp(lastSeenTimestamp);
-
-        Command cmd = odm.processPacketIn(sw1, pktIn, (Ethernet) pkt2);
-        assertEquals(Command.CONTINUE, cmd);
-        assertTrue(lastSeenTimestamp.before(srcDevice.getLastSeenTimestamp()));
-    }
-
-    /**
      * Test add a device from the information from packet.
+     * @throws FloodlightModuleException
      */
     @Test
-    public void testAddOnosDevice() {
+    public void testAddOnosDevice() throws FloodlightModuleException {
         Ethernet eth = (Ethernet) pkt1;
         Long longmac = eth.getSourceMAC().toLong();
         OnosDevice srcDevice = odm.getSourceDeviceFromPacket(eth, sw1Dpid, sw1DevPort);
 
         floodLightProvider.addOFMessageListener(EasyMock.eq(OFType.PACKET_IN), EasyMock.isA(OnosDeviceManager.class));
         EasyMock.expectLastCall();
-        eventChannel.addEntry(longmac, srcDevice);
-        EasyMock.expectLastCall();
         floodLightProvider.publishUpdate(EasyMock.isA(IUpdate.class));
         EasyMock.expectLastCall();
-        replay(floodLightProvider, eventChannel);
+        replay(floodLightProvider);
 
+        odm.init(modContext);
+        odm.startUp(modContext);
         odm.addOnosDevice(longmac, srcDevice);
 
-        verify(eventChannel);
+        EasyMock.verify(floodLightProvider);
     }
 
     /**
      * Test delete a device.
+     * @throws FloodlightModuleException
      */
     @Test
-    public void testDeleteOnosDevice() {
+    public void testDeleteOnosDevice() throws FloodlightModuleException {
         Ethernet eth = (Ethernet) pkt1;
-        Long longmac = eth.getSourceMAC().toLong();
         OnosDevice srcDevice = odm.getSourceDeviceFromPacket(eth, sw1Dpid, sw1DevPort);
 
         floodLightProvider.addOFMessageListener(EasyMock.eq(OFType.PACKET_IN), EasyMock.isA(OnosDeviceManager.class));
         EasyMock.expectLastCall();
-        eventChannel.removeEntry(longmac);
-        EasyMock.expectLastCall();
         floodLightProvider.publishUpdate(EasyMock.isA(IUpdate.class));
         EasyMock.expectLastCall();
-        replay(floodLightProvider, eventChannel);
+        replay(floodLightProvider);
 
+        odm.init(modContext);
+        odm.startUp(modContext);
         odm.deleteOnosDevice(srcDevice);
 
-        verify(eventChannel);
+        EasyMock.verify(floodLightProvider);
     }
 
     /**
      * Test delete a device by using its source mac address.
+     * @throws FloodlightModuleException
      */
     @Test
-    public void testDeleteOnosDeviceByMac() {
+    public void testDeleteOnosDeviceByMac() throws FloodlightModuleException {
         Ethernet eth = (Ethernet) pkt1;
         MACAddress mac = eth.getSourceMAC();
-        Long longmac = mac.toLong();
-        OnosDevice srcDevice = odm.getSourceDeviceFromPacket(eth, sw1Dpid, sw1DevPort);
 
         floodLightProvider.addOFMessageListener(EasyMock.eq(OFType.PACKET_IN), EasyMock.isA(OnosDeviceManager.class));
         EasyMock.expectLastCall();
-        eventChannel.removeEntry(longmac);
-        EasyMock.expectLastCall();
         floodLightProvider.publishUpdate(EasyMock.isA(IUpdate.class));
         EasyMock.expectLastCall();
-        replay(floodLightProvider, eventChannel);
+        replay(floodLightProvider);
 
-        odm.entryAdded(srcDevice);
+        odm.init(modContext);
+        odm.startUp(modContext);
         odm.deleteOnosDeviceByMac(mac);
-        verify(eventChannel);
+
+        EasyMock.verify(floodLightProvider);
     }
 }
diff --git a/src/test/java/net/onrc/onos/core/devicemanager/OnosDeviceTest.java b/src/test/java/net/onrc/onos/core/devicemanager/OnosDeviceTest.java
new file mode 100644
index 0000000..6c79bf0
--- /dev/null
+++ b/src/test/java/net/onrc/onos/core/devicemanager/OnosDeviceTest.java
@@ -0,0 +1,65 @@
+package net.onrc.onos.core.devicemanager;
+
+import static org.junit.Assert.assertTrue;
+
+import java.util.Date;
+
+import net.floodlightcontroller.util.MACAddress;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+/*
+ * This is the test for OnosDevice.class.
+ */
+public class OnosDeviceTest {
+
+    MACAddress mac1;
+    MACAddress mac2;
+    Long dpid1;
+    Long dpid2;
+    Long portNum1;
+    Long portNum2;
+    Date date1;
+    Date date2;
+
+    @Before
+    public void setUp() throws Exception {
+        mac1 = MACAddress.valueOf("00:00:00:00:00:01");
+        mac2 = MACAddress.valueOf("00:00:00:00:00:01");
+        dpid1 = 1L;
+        dpid2 = 1L;
+        portNum1 = 1L;
+        portNum2 = 1L;
+        date1 = new Date(1L);
+        date2 = new Date(2L);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+    }
+
+    /*
+     * Test for making sure hashCode function works properly.
+     */
+    @Test
+    public void testHashCode() {
+        OnosDevice dev1 = new OnosDevice(mac1, null, dpid1, portNum1, date1);
+        OnosDevice dev2 = new OnosDevice(mac2, null, dpid2, portNum2, date2);
+
+        assertTrue(dev1.hashCode() == dev2.hashCode());
+    }
+
+    /*
+     * Test for making sure equals function works properly.
+     */
+    @Test
+    public void testEqualsObject() {
+        OnosDevice dev1 = new OnosDevice(mac1, null, dpid1, portNum1, date1);
+        OnosDevice dev2 = new OnosDevice(mac2, null, dpid2, portNum2, date2);
+
+        assertTrue(dev1.equals(dev2));
+    }
+
+}
diff --git a/src/test/java/net/onrc/onos/core/intent/ConstrainedBFSTreeTest.java b/src/test/java/net/onrc/onos/core/intent/ConstrainedBFSTreeTest.java
index 4a58b90..9a3aaa2 100644
--- a/src/test/java/net/onrc/onos/core/intent/ConstrainedBFSTreeTest.java
+++ b/src/test/java/net/onrc/onos/core/intent/ConstrainedBFSTreeTest.java
@@ -5,6 +5,7 @@
 import static org.junit.Assert.assertNull;
 import net.onrc.onos.core.intent.IntentOperation.Operator;
 import net.onrc.onos.core.topology.LinkEvent;
+import net.onrc.onos.core.topology.MockTopology;
 
 import org.junit.After;
 import org.junit.Before;
diff --git a/src/test/java/net/onrc/onos/core/intent/MockTopology.java b/src/test/java/net/onrc/onos/core/intent/MockTopology.java
deleted file mode 100644
index ddbdbe7..0000000
--- a/src/test/java/net/onrc/onos/core/intent/MockTopology.java
+++ /dev/null
@@ -1,86 +0,0 @@
-package net.onrc.onos.core.intent;
-
-import net.onrc.onos.core.topology.Link;
-import net.onrc.onos.core.topology.LinkImpl;
-import net.onrc.onos.core.topology.Switch;
-import net.onrc.onos.core.topology.SwitchImpl;
-import net.onrc.onos.core.topology.TopologyImpl;
-
-/**
- * A mock class of Topology.
- * This class should be used only by test codes.
- */
-public class MockTopology extends TopologyImpl {
-    // TODO this class doesn't seem like it should extend TopologyImpl. It
-    // isn't a Topology, it's more of a TopologyBuilder - methods to
-    // create an populate a fake topology that's not based on discovery
-    // data from the driver modules.
-    // We may well need a MockTopology, but that's not what this class is
-    // doing.
-
-    public static final Long LOCAL_PORT = 0xFFFEL;
-    public SwitchImpl sw1, sw2, sw3, sw4;
-
-    public Switch addSwitch(Long switchId) {
-        SwitchImpl sw = new SwitchImpl(this, switchId);
-        this.putSwitch(sw);
-        return sw;
-    }
-
-    public Link[] addBidirectionalLinks(Long srcDpid, Long srcPortNo, Long dstDpid, Long dstPortNo) {
-        Link[] links = new Link[2];
-        links[0] = new LinkImpl(this, getPort(srcDpid, srcPortNo), getPort(dstDpid, dstPortNo));
-        links[1] = new LinkImpl(this, getPort(dstDpid, dstPortNo), getPort(srcDpid, srcPortNo));
-
-        putLink(links[0]);
-        putLink(links[1]);
-
-        return links;
-    }
-
-    /**
-     * create sample topology of 4 switches and 5 bidirectional links.
-     * <pre>
-     * [1] --- [2]
-     *  |    /  |
-     *  |  /    |
-     * [4] --- [3]
-     * </pre>
-     */
-    public void createSampleTopology1() {
-        sw1 = (SwitchImpl) addSwitch(1L);
-        sw1.addPort(LOCAL_PORT);
-        sw2 = (SwitchImpl) addSwitch(2L);
-        sw2.addPort(LOCAL_PORT);
-        sw3 = (SwitchImpl) addSwitch(3L);
-        sw3.addPort(LOCAL_PORT);
-        sw4 = (SwitchImpl) addSwitch(4L);
-        sw4.addPort(LOCAL_PORT);
-
-        sw1.addPort(12L); // sw1 -> sw2
-        sw1.addPort(14L); // sw1 -> sw4
-        sw2.addPort(21L); // sw2 -> sw1
-        sw2.addPort(23L); // sw2 -> sw3
-        sw2.addPort(24L); // sw2 -> sw4
-        sw3.addPort(32L); // sw3 -> sw2
-        sw3.addPort(34L); // sw3 -> sw4
-        sw4.addPort(41L); // sw4 -> sw1
-        sw4.addPort(42L); // sw4 -> sw2
-        sw4.addPort(43L); // sw4 -> sw3
-
-        addBidirectionalLinks(1L, 12L, 2L, 21L);
-        addBidirectionalLinks(2L, 23L, 3L, 32L);
-        addBidirectionalLinks(3L, 34L, 4L, 43L);
-        addBidirectionalLinks(4L, 41L, 1L, 14L);
-        addBidirectionalLinks(2L, 24L, 4L, 42L);
-
-        // set capacity of all links to 1000Mbps
-        for (Link link : getLinks()) {
-            ((LinkImpl) link).setCapacity(1000.0);
-        }
-    }
-
-    public void removeLink(Long srcDpid, Long srcPortNo, Long dstDpid, Long dstPortNo) {
-        removeLink(getLink(srcDpid, srcPortNo, dstDpid, dstPortNo));
-    }
-}
diff --git a/src/test/java/net/onrc/onos/core/intent/runtime/IntentTestMocks.java b/src/test/java/net/onrc/onos/core/intent/runtime/IntentTestMocks.java
index 1a2e1c5..a6dde8b 100644
--- a/src/test/java/net/onrc/onos/core/intent/runtime/IntentTestMocks.java
+++ b/src/test/java/net/onrc/onos/core/intent/runtime/IntentTestMocks.java
@@ -1,19 +1,5 @@
 package net.onrc.onos.core.intent.runtime;
 
-
-import net.floodlightcontroller.core.module.FloodlightModuleContext;
-import net.floodlightcontroller.restserver.IRestApiService;
-import net.onrc.onos.core.datagrid.IDatagridService;
-import net.onrc.onos.core.datagrid.IEventChannel;
-import net.onrc.onos.core.datagrid.IEventChannelListener;
-import net.onrc.onos.core.intent.IntentOperationList;
-import net.onrc.onos.core.intent.MockTopology;
-import net.onrc.onos.core.intent.runtime.web.IntentWebRoutable;
-import net.onrc.onos.core.registry.IControllerRegistryService;
-import net.onrc.onos.core.topology.ITopologyListener;
-import net.onrc.onos.core.topology.ITopologyService;
-import org.powermock.api.easymock.PowerMock;
-
 import static org.easymock.EasyMock.anyObject;
 import static org.easymock.EasyMock.createMock;
 import static org.easymock.EasyMock.eq;
@@ -21,6 +7,19 @@
 import static org.easymock.EasyMock.expectLastCall;
 import static org.easymock.EasyMock.replay;
 import static org.easymock.EasyMock.verify;
+import net.floodlightcontroller.core.module.FloodlightModuleContext;
+import net.floodlightcontroller.restserver.IRestApiService;
+import net.onrc.onos.core.datagrid.IDatagridService;
+import net.onrc.onos.core.datagrid.IEventChannel;
+import net.onrc.onos.core.datagrid.IEventChannelListener;
+import net.onrc.onos.core.intent.IntentOperationList;
+import net.onrc.onos.core.intent.runtime.web.IntentWebRoutable;
+import net.onrc.onos.core.registry.IControllerRegistryService;
+import net.onrc.onos.core.topology.ITopologyListener;
+import net.onrc.onos.core.topology.ITopologyService;
+import net.onrc.onos.core.topology.MockTopology;
+
+import org.powermock.api.easymock.PowerMock;
 
 /**
  * This class contains all of the mocked code required to run a test that uses
diff --git a/src/test/java/net/onrc/onos/core/intent/runtime/PathCalcRuntimeModuleTest.java b/src/test/java/net/onrc/onos/core/intent/runtime/PathCalcRuntimeModuleTest.java
index 9623436..5d4adb8 100644
--- a/src/test/java/net/onrc/onos/core/intent/runtime/PathCalcRuntimeModuleTest.java
+++ b/src/test/java/net/onrc/onos/core/intent/runtime/PathCalcRuntimeModuleTest.java
@@ -17,10 +17,10 @@
 import net.onrc.onos.core.intent.IntentMap;
 import net.onrc.onos.core.intent.IntentOperation.Operator;
 import net.onrc.onos.core.intent.IntentOperationList;
-import net.onrc.onos.core.intent.MockTopology;
 import net.onrc.onos.core.intent.ShortestPathIntent;
 import net.onrc.onos.core.topology.DeviceEvent;
 import net.onrc.onos.core.topology.LinkEvent;
+import net.onrc.onos.core.topology.MockTopology;
 import net.onrc.onos.core.topology.PortEvent;
 import net.onrc.onos.core.topology.SwitchEvent;
 
diff --git a/src/test/java/net/onrc/onos/core/intent/runtime/UseCaseTest.java b/src/test/java/net/onrc/onos/core/intent/runtime/UseCaseTest.java
index d911d2f..76af2ec 100644
--- a/src/test/java/net/onrc/onos/core/intent/runtime/UseCaseTest.java
+++ b/src/test/java/net/onrc/onos/core/intent/runtime/UseCaseTest.java
@@ -24,7 +24,6 @@
 import net.onrc.onos.core.intent.Intent.IntentState;
 import net.onrc.onos.core.intent.IntentOperation.Operator;
 import net.onrc.onos.core.intent.IntentOperationList;
-import net.onrc.onos.core.intent.MockTopology;
 import net.onrc.onos.core.intent.PathIntent;
 import net.onrc.onos.core.intent.PathIntentMap;
 import net.onrc.onos.core.intent.ShortestPathIntent;
@@ -34,6 +33,7 @@
 import net.onrc.onos.core.topology.ITopologyListener;
 import net.onrc.onos.core.topology.ITopologyService;
 import net.onrc.onos.core.topology.LinkEvent;
+import net.onrc.onos.core.topology.MockTopology;
 import net.onrc.onos.core.topology.PortEvent;
 import net.onrc.onos.core.topology.SwitchEvent;
 import net.onrc.onos.core.topology.Topology;
diff --git a/src/test/java/net/onrc/onos/core/topology/MockTopology.java b/src/test/java/net/onrc/onos/core/topology/MockTopology.java
new file mode 100644
index 0000000..888779a
--- /dev/null
+++ b/src/test/java/net/onrc/onos/core/topology/MockTopology.java
@@ -0,0 +1,140 @@
+package net.onrc.onos.core.topology;
+
+import net.floodlightcontroller.util.MACAddress;
+
+/**
+ * A mock class of Topology.
+ * This class should be used only by test codes.
+ */
+public class MockTopology extends TopologyImpl {
+    // TODO this class doesn't seem like it should extend TopologyImpl. It
+    // isn't a Topology, it's more of a TopologyBuilder - methods to
+    // create an populate a fake topology that's not based on discovery
+    // data from the driver modules.
+    // We may well need a MockTopology, but that's not what this class is
+    // doing.
+
+    public static final Long LOCAL_PORT = 0xFFFEL;
+    public SwitchImpl sw1, sw2, sw3, sw4;
+
+    public Switch addSwitch(Long switchId) {
+        SwitchImpl sw = new SwitchImpl(this, switchId);
+        this.putSwitch(sw);
+        return sw;
+    }
+
+    public Link[] addBidirectionalLinks(Long srcDpid, Long srcPortNo, Long dstDpid, Long dstPortNo) {
+        Link[] links = new Link[2];
+        links[0] = new LinkImpl(this, getPort(srcDpid, srcPortNo), getPort(dstDpid, dstPortNo));
+        links[1] = new LinkImpl(this, getPort(dstDpid, dstPortNo), getPort(srcDpid, srcPortNo));
+
+        putLink(links[0]);
+        putLink(links[1]);
+
+        return links;
+    }
+
+    /**
+     * create sample topology of 4 switches and 5 bidirectional links.
+     * <pre>
+     * [1] --- [2]
+     *  |    /  |
+     *  |  /    |
+     * [4] --- [3]
+     * </pre>
+     */
+    public void createSampleTopology1() {
+        sw1 = (SwitchImpl) addSwitch(1L);
+        sw1.addPort(LOCAL_PORT);
+        sw2 = (SwitchImpl) addSwitch(2L);
+        sw2.addPort(LOCAL_PORT);
+        sw3 = (SwitchImpl) addSwitch(3L);
+        sw3.addPort(LOCAL_PORT);
+        sw4 = (SwitchImpl) addSwitch(4L);
+        sw4.addPort(LOCAL_PORT);
+
+        sw1.addPort(12L); // sw1 -> sw2
+        sw1.addPort(14L); // sw1 -> sw4
+        sw2.addPort(21L); // sw2 -> sw1
+        sw2.addPort(23L); // sw2 -> sw3
+        sw2.addPort(24L); // sw2 -> sw4
+        sw3.addPort(32L); // sw3 -> sw2
+        sw3.addPort(34L); // sw3 -> sw4
+        sw4.addPort(41L); // sw4 -> sw1
+        sw4.addPort(42L); // sw4 -> sw2
+        sw4.addPort(43L); // sw4 -> sw3
+
+        addBidirectionalLinks(1L, 12L, 2L, 21L);
+        addBidirectionalLinks(2L, 23L, 3L, 32L);
+        addBidirectionalLinks(3L, 34L, 4L, 43L);
+        addBidirectionalLinks(4L, 41L, 1L, 14L);
+        addBidirectionalLinks(2L, 24L, 4L, 42L);
+
+        // set capacity of all links to 1000Mbps
+        for (Link link : getLinks()) {
+            ((LinkImpl) link).setCapacity(1000.0);
+        }
+    }
+
+    /**
+     * create sample topology of 4 switches and 5 bidirectional links.
+     * <pre>
+     *
+     *
+     * [H1]-[1] --- [2]
+     *       |    /  |
+     *       |  /    |
+     *      [4] --- [3]-[H3]
+     * </pre>
+     */
+    public void createSampleTopology2() {
+        sw1 = (SwitchImpl) addSwitch(1L);
+        sw1.addPort(LOCAL_PORT);
+        sw2 = (SwitchImpl) addSwitch(2L);
+        sw2.addPort(LOCAL_PORT);
+        sw3 = (SwitchImpl) addSwitch(3L);
+        sw3.addPort(LOCAL_PORT);
+        sw4 = (SwitchImpl) addSwitch(4L);
+        sw4.addPort(LOCAL_PORT);
+
+        Port port12 = sw1.addPort(12L); // sw1 -> sw2
+        Port port14 = sw1.addPort(14L); // sw1 -> sw4
+        Port port15 = sw1.addPort(15L); // sw1 -> h1
+        Port port21 = sw2.addPort(21L); // sw2 -> sw1
+        Port port23 = sw2.addPort(23L); // sw2 -> sw3
+        Port port24 = sw2.addPort(24L); // sw2 -> sw4
+        Port port32 = sw3.addPort(32L); // sw3 -> sw2
+        Port port34 = sw3.addPort(34L); // sw3 -> sw4
+        Port port35 = sw3.addPort(35L); // sw3 -> h3
+        Port port41 = sw4.addPort(41L); // sw4 -> sw1
+        Port port42 = sw4.addPort(42L); // sw4 -> sw2
+        Port port43 = sw4.addPort(43L); // sw4 -> sw3
+
+        MACAddress mac1 = MACAddress.valueOf("00:44:33:22:11:00");
+        DeviceImpl dev1 = new DeviceImpl(this, mac1);
+        dev1.addAttachmentPoint(port15);
+        dev1.setLastSeenTime(1L);
+        this.putDevice(dev1);
+
+        MACAddress mac3 = MACAddress.valueOf("00:11:22:33:44:55");
+        DeviceImpl dev3 = new DeviceImpl(this, mac3);
+        dev3.addAttachmentPoint(port35);
+        dev3.setLastSeenTime(1L);
+        this.putDevice(dev3);
+
+        addBidirectionalLinks(1L, 12L, 2L, 21L);
+        addBidirectionalLinks(2L, 23L, 3L, 32L);
+        addBidirectionalLinks(3L, 34L, 4L, 43L);
+        addBidirectionalLinks(4L, 41L, 1L, 14L);
+        addBidirectionalLinks(2L, 24L, 4L, 42L);
+
+        // set capacity of all links to 1000Mbps
+        for (Link link : getLinks()) {
+            ((LinkImpl) link).setCapacity(1000.0);
+        }
+    }
+
+    public void removeLink(Long srcDpid, Long srcPortNo, Long dstDpid, Long dstPortNo) {
+        removeLink(getLink(srcDpid, srcPortNo, dstDpid, dstPortNo));
+    }
+}