Carry previous host subject in HostEvent

This is an enhanced version of gerrit 6085 that provides not only the old location
but also the entire old host subject.
The main purpose is allowing apps to be aware of the change of IP address as well

Change-Id: I448d73b0d1e705996259cb0ec777f959f485d9c2
diff --git a/core/api/src/main/java/org/onosproject/net/DefaultHost.java b/core/api/src/main/java/org/onosproject/net/DefaultHost.java
index 2877701..557fa5c 100644
--- a/core/api/src/main/java/org/onosproject/net/DefaultHost.java
+++ b/core/api/src/main/java/org/onosproject/net/DefaultHost.java
@@ -98,7 +98,8 @@
             return Objects.equals(this.id, other.id) &&
                     Objects.equals(this.mac, other.mac) &&
                     Objects.equals(this.vlan, other.vlan) &&
-                    Objects.equals(this.location, other.location);
+                    Objects.equals(this.location, other.location) &&
+                    Objects.equals(this.ipAddresses(), other.ipAddresses());
         }
         return false;
     }
diff --git a/core/api/src/main/java/org/onosproject/net/host/HostEvent.java b/core/api/src/main/java/org/onosproject/net/host/HostEvent.java
index 58ac0bb..92824cf 100644
--- a/core/api/src/main/java/org/onosproject/net/host/HostEvent.java
+++ b/core/api/src/main/java/org/onosproject/net/host/HostEvent.java
@@ -18,7 +18,6 @@
 import org.joda.time.LocalDateTime;
 import org.onosproject.event.AbstractEvent;
 import org.onosproject.net.Host;
-import org.onosproject.net.HostLocation;
 
 import static com.google.common.base.MoreObjects.toStringHelper;
 
@@ -52,7 +51,7 @@
         HOST_MOVED
     }
 
-    private HostLocation prevLocation;
+    private Host prevSubject;
 
     /**
      * Creates an event of a given type and for the specified host and the
@@ -77,25 +76,29 @@
     }
 
     /**
-     * Creates an event with HOST_MOVED type along with the previous location
-     * of the host.
+     * Creates an event with previous subject.
      *
+     * The previous subject is ignored if the type is not moved or updated
+     *
+     * @param type host event type
      * @param host event host subject
-     * @param prevLocation previous location of the host
+     * @param prevSubject previous host subject
      */
-    public HostEvent(Host host, HostLocation prevLocation) {
-        super(Type.HOST_MOVED, host);
-        this.prevLocation = prevLocation;
+    public HostEvent(Type type, Host host, Host prevSubject) {
+        super(type, host);
+        if (type == Type.HOST_MOVED || type == Type.HOST_UPDATED) {
+            this.prevSubject = prevSubject;
+        }
     }
 
     /**
-     * Gets the previous location information in this host event.
+     * Gets the previous subject in this host event.
      *
-     * @return the previous location, or null if previous location is not
+     * @return the previous subject, or null if previous subject is not
      *         specified.
      */
-    public HostLocation prevLocation() {
-        return this.prevLocation;
+    public Host prevSubject() {
+        return this.prevSubject;
     }
 
     @Override
@@ -104,7 +107,7 @@
                 .add("time", new LocalDateTime(time()))
                 .add("type", type())
                 .add("subject", subject())
-                .add("prevLocation", prevLocation())
+                .add("prevSubject", prevSubject())
                 .toString();
     }
 }
diff --git a/core/store/dist/src/main/java/org/onosproject/store/host/impl/ECHostStore.java b/core/store/dist/src/main/java/org/onosproject/store/host/impl/ECHostStore.java
index 391a88f..2012457 100644
--- a/core/store/dist/src/main/java/org/onosproject/store/host/impl/ECHostStore.java
+++ b/core/store/dist/src/main/java/org/onosproject/store/host/impl/ECHostStore.java
@@ -19,6 +19,7 @@
 import static com.google.common.base.Preconditions.checkState;
 import static org.onosproject.net.DefaultAnnotations.merge;
 import static org.onosproject.net.host.HostEvent.Type.HOST_ADDED;
+import static org.onosproject.net.host.HostEvent.Type.HOST_MOVED;
 import static org.onosproject.net.host.HostEvent.Type.HOST_REMOVED;
 import static org.onosproject.net.host.HostEvent.Type.HOST_UPDATED;
 import static org.onosproject.store.service.EventuallyConsistentMapEvent.Type.PUT;
@@ -88,7 +89,7 @@
 
     private EventuallyConsistentMap<HostId, DefaultHost> hosts;
 
-    private final ConcurrentHashMap<HostId, HostLocation> locations =
+    private final ConcurrentHashMap<HostId, DefaultHost> prevHosts =
             new ConcurrentHashMap<>();
 
     private EventuallyConsistentMapListener<HostId, DefaultHost> hostLocationTracker =
@@ -114,7 +115,7 @@
     public void deactivate() {
         hosts.removeListener(hostLocationTracker);
         hosts.destroy();
-        locations.clear();
+        prevHosts.clear();
 
         log.info("Stopped");
     }
@@ -253,16 +254,16 @@
         public void event(EventuallyConsistentMapEvent<HostId, DefaultHost> event) {
             DefaultHost host = checkNotNull(event.value());
             if (event.type() == PUT) {
-                HostLocation prevLocation = locations.put(host.id(), host.location());
-                if (prevLocation == null) {
+                Host prevHost = prevHosts.put(host.id(), host);
+                if (prevHost == null) {
                     notifyDelegate(new HostEvent(HOST_ADDED, host));
-                } else if (!Objects.equals(prevLocation, host.location())) {
-                    notifyDelegate(new HostEvent(host, prevLocation));
-                } else {
-                    notifyDelegate(new HostEvent(HOST_UPDATED, host));
+                } else if (!Objects.equals(prevHost.location(), host.location())) {
+                    notifyDelegate(new HostEvent(HOST_MOVED, host, prevHost));
+                } else if (!Objects.equals(prevHost, host)) {
+                    notifyDelegate(new HostEvent(HOST_UPDATED, host, prevHost));
                 }
             } else if (event.type() == REMOVE) {
-                if (locations.remove(host.id()) != null) {
+                if (prevHosts.remove(host.id()) != null) {
                     notifyDelegate(new HostEvent(HOST_REMOVED, host));
                 }
             }
diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/TopologyViewMessageHandlerBase.java b/web/gui/src/main/java/org/onosproject/ui/impl/TopologyViewMessageHandlerBase.java
index 8da8101..f35b6c0 100644
--- a/web/gui/src/main/java/org/onosproject/ui/impl/TopologyViewMessageHandlerBase.java
+++ b/web/gui/src/main/java/org/onosproject/ui/impl/TopologyViewMessageHandlerBase.java
@@ -291,8 +291,8 @@
     // Produces a host event message to the client.
     protected ObjectNode hostMessage(HostEvent event) {
         Host host = event.subject();
+        Host prevHost = event.prevSubject();
         String hostType = host.annotations().value(AnnotationKeys.TYPE);
-        HostLocation prevLoc = event.prevLocation();
 
         ObjectNode payload = objectNode()
                 .put("id", host.id().toString())
@@ -300,8 +300,8 @@
                 .put("ingress", compactLinkString(edgeLink(host, true)))
                 .put("egress", compactLinkString(edgeLink(host, false)));
         payload.set("cp", hostConnect(host.location()));
-        if (prevLoc != null) {
-            payload.set("prevCp", hostConnect(event.prevLocation()));
+        if (prevHost != null && prevHost.location() != null) {
+            payload.set("prevCp", hostConnect(prevHost.location()));
         }
         payload.set("labels", labels(ip(host.ipAddresses()),
                                      host.mac().toString()));