* Added a new class TopologyEvents that encapsulated the collections
  of all possible topology-related events.
* Updated the ITopologyListener API to use the new class TopologyEvents
* Updated the code that is affected by the ITopologyListener API change.

Change-Id: Ib836141d6a21e5317d645619eb685ff0b13788a2
diff --git a/src/main/java/net/onrc/onos/core/intent/runtime/PathCalcRuntimeModule.java b/src/main/java/net/onrc/onos/core/intent/runtime/PathCalcRuntimeModule.java
index 94f3b28..27de191 100644
--- a/src/main/java/net/onrc/onos/core/intent/runtime/PathCalcRuntimeModule.java
+++ b/src/main/java/net/onrc/onos/core/intent/runtime/PathCalcRuntimeModule.java
@@ -38,12 +38,12 @@
 import net.onrc.onos.core.intent.ShortestPathIntent;
 import net.onrc.onos.core.intent.runtime.web.IntentWebRoutable;
 import net.onrc.onos.core.registry.IControllerRegistryService;
-import net.onrc.onos.core.topology.DeviceEvent;
 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.PortEvent;
 import net.onrc.onos.core.topology.SwitchEvent;
+import net.onrc.onos.core.topology.TopologyEvents;
 import net.onrc.onos.core.util.Dpid;
 
 import org.slf4j.Logger;
@@ -642,27 +642,16 @@
     // ================================================================================
     // ITopologyListener implementations
     // ================================================================================
-
-    // CHECKSTYLE:OFF suppress warning about too many parameters
     /**
      * {@inheritDoc}
      */
     @Override
-    public void topologyEvents(Collection<SwitchEvent> addedSwitchEvents,
-                                   Collection<SwitchEvent> removedSwitchEvents,
-                                   Collection<PortEvent> addedPortEvents,
-                                   Collection<PortEvent> removedPortEvents,
-                                   Collection<LinkEvent> addedLinkEvents,
-                                   Collection<LinkEvent> removedLinkEvents,
-                                   Collection<DeviceEvent> addedDeviceEvents,
-                                   Collection<DeviceEvent> removedDeviceEvents) {
-    // CHECKSTYLE:ON
-
+    public void topologyEvents(TopologyEvents topologyEvents) {
         PerfLogger p = new PerfLogger("networkGraphEvents");
         HashSet<Intent> affectedPaths = new HashSet<>();
 
         boolean rerouteAll = false;
-        for (LinkEvent le : addedLinkEvents) {
+        for (LinkEvent le : topologyEvents.getAddedLinkEvents()) {
             LinkEvent rev = new LinkEvent(le.getDst().getDpid(),
                     le.getDst().getPortNumber(), le.getSrc().getDpid(),
                     le.getSrc().getPortNumber());
@@ -675,7 +664,7 @@
                 log.debug("Adding unmatched LinkEvent: {}", le);
             }
         }
-        for (LinkEvent le : removedLinkEvents) {
+        for (LinkEvent le : topologyEvents.getRemovedLinkEvents()) {
             if (unmatchedLinkEvents.contains(le)) {
                 unmatchedLinkEvents.remove(le);
                 log.debug("Removing LinkEvent: {}", le);
@@ -685,23 +674,26 @@
             log.debug("Unmatched link events: {} events", unmatchedLinkEvents.size());
         }
 
-        if (rerouteAll) { //addedLinkEvents.size() > 0) { // ||
-//                              addedPortEvents.size() > 0 ||
-//                              addedSwitchEvents.size() > 0) {
+        if (rerouteAll) {
+            //
+            // (topologyEvents.getAddedLinkEvents().size() > 0) ||
+            // (topologyEvents.getAddedPortEvents().size() > 0) ||
+            // (topologyEvents.getAddedSwitchEvents.size() > 0)
+            //
             p.log("begin_getAllIntents");
             affectedPaths.addAll(getPathIntents().getAllIntents());
             p.log("end_getAllIntents");
-        } else if (removedSwitchEvents.size() > 0 ||
-                removedLinkEvents.size() > 0 ||
-                removedPortEvents.size() > 0) {
+        } else if (topologyEvents.getRemovedSwitchEvents().size() > 0 ||
+                   topologyEvents.getRemovedLinkEvents().size() > 0 ||
+                   topologyEvents.getRemovedPortEvents().size() > 0) {
             p.log("begin_getIntentsByLink");
-            for (LinkEvent linkEvent : removedLinkEvents) {
+            for (LinkEvent linkEvent : topologyEvents.getRemovedLinkEvents()) {
                 affectedPaths.addAll(pathIntents.getIntentsByLink(linkEvent));
             }
             p.log("end_getIntentsByLink");
 
             p.log("begin_getIntentsByPort");
-            for (PortEvent portEvent : removedPortEvents) {
+            for (PortEvent portEvent : topologyEvents.getRemovedPortEvents()) {
                 affectedPaths.addAll(pathIntents.getIntentsByPort(
                         portEvent.getDpid(),
                         portEvent.getPortNumber()));
@@ -709,7 +701,7 @@
             p.log("end_getIntentsByPort");
 
             p.log("begin_getIntentsByDpid");
-            for (SwitchEvent switchEvent : removedSwitchEvents) {
+            for (SwitchEvent switchEvent : topologyEvents.getRemovedSwitchEvents()) {
                 affectedPaths.addAll(pathIntents.getIntentsByDpid(switchEvent.getDpid()));
             }
             p.log("end_getIntentsByDpid");
diff --git a/src/main/java/net/onrc/onos/core/topology/ITopologyListener.java b/src/main/java/net/onrc/onos/core/topology/ITopologyListener.java
index 889db03..aa02da0 100644
--- a/src/main/java/net/onrc/onos/core/topology/ITopologyListener.java
+++ b/src/main/java/net/onrc/onos/core/topology/ITopologyListener.java
@@ -1,46 +1,15 @@
 package net.onrc.onos.core.topology;
 
-import java.util.Collection;
-
 /**
- * Interface which needs to be implemented to receive Topology events from
+ * Interface that needs to be implemented to receive Topology events from
  * the Topology.
  */
 public interface ITopologyListener {
     /**
-     * Topology events.
-     * <p/>
-     * The recommended ordering rules for applying/processing the events is:
-     * (a) Process "added" events before "removed" events.
-     * (b) The ordering of the "added" events should be:
-     * addedSwitchEvents, addedPortEvents, addedLinkEvents,
-     * addedDeviceEvents
-     * The above ordering guarantees that adding a port for example
-     * will be processed after the corresponding switch itself is added.
-     * (c) The ordering of the "removed" events should be:
-     * removedDeviceEvents, removedLinkEvents, removedPortEvents,
-     * removedSwitchEvents
-     * The above ordering guarantees that removing a port for example
-     * will be processed before the corresponding switch itself is
-     * removed.
+     * Topology events that have been generated.
      *
-     * @param addedSwitchEvents   the Added Switch Events.
-     * @param removedSwitchEvents the Removed Switch Events.
-     * @param addedPortEvents     the Added Port Events.
-     * @param removedPortEvents   the Removed Port Events.
-     * @param addedLinkEvents     the Added Link Events.
-     * @param removedLinkEvents   the Removed Link Events.
-     * @param addedDeviceEvents   the Added Device Events.
-     * @param removedDeviceEvents the Removed Device Events.
+     * @param topologyEvents the generated Topology Events
+     * @see TopologyEvents
      */
-    // CHECKSTYLE:OFF suppress warning about too many parameters
-    public void topologyEvents(Collection<SwitchEvent> addedSwitchEvents,
-                                   Collection<SwitchEvent> removedSwitchEvents,
-                                   Collection<PortEvent> addedPortEvents,
-                                   Collection<PortEvent> removedPortEvents,
-                                   Collection<LinkEvent> addedLinkEvents,
-                                   Collection<LinkEvent> removedLinkEvents,
-                                   Collection<DeviceEvent> addedDeviceEvents,
-                                   Collection<DeviceEvent> removedDeviceEvents);
-    // CHECKSTYLE:ON
+    public void topologyEvents(TopologyEvents topologyEvents);
 }
diff --git a/src/main/java/net/onrc/onos/core/topology/TopologyEvents.java b/src/main/java/net/onrc/onos/core/topology/TopologyEvents.java
new file mode 100644
index 0000000..71b7fb5
--- /dev/null
+++ b/src/main/java/net/onrc/onos/core/topology/TopologyEvents.java
@@ -0,0 +1,162 @@
+package net.onrc.onos.core.topology;
+
+import java.util.Collection;
+import java.util.Collections;
+
+/**
+ * Class for encapsulating multiple topology events.
+ * <p/>
+ * The recommended ordering rules for applying/processing the events are:
+ * <p/>
+ * (a) Process "removed" events before "added" events.
+ * <p/>
+ * (b) The processing order of the "removed" events should be:
+ * removedHostEvents, removedLinkEvents, removedPortEvents,
+ * removedSwitchEvents
+ * <p/>
+ * (c) The processing order of the "added" events should be:
+ * addedSwitchEvents, addedPortEvents, addedLinkEvents,
+ * addedHostEvents
+ * <p/>
+ * The above ordering guarantees that removing a port for example
+ * will be processed before the corresponding switch itself is
+ * removed.
+ * <p/>
+ * The above ordering guarantees that adding a port for example
+ * will be processed after the corresponding switch itself is added.
+ */
+public final class TopologyEvents {
+    private final long timestamp;
+    private final Collection<SwitchEvent> addedSwitchEvents;
+    private final Collection<SwitchEvent> removedSwitchEvents;
+    private final Collection<PortEvent> addedPortEvents;
+    private final Collection<PortEvent> removedPortEvents;
+    private final Collection<LinkEvent> addedLinkEvents;
+    private final Collection<LinkEvent> removedLinkEvents;
+    private final Collection<DeviceEvent> addedHostEvents;
+    private final Collection<DeviceEvent> removedHostEvents;
+
+    /**
+     * Constructor.
+     *
+     * @param timestamp the timestamp for the event.
+     * @param addedSwitchEvents the collection of added Switch Events.
+     * @param removedSwitchEvents the collection of removed Switch Events.
+     * @param addedPortEvents the collection of added Port Events.
+     * @param removedPortEvents the collection of removed Port Events.
+     * @param addedLinkEvents the collection of added Link Events.
+     * @param removedLinkEvents the collection of removed Link Events.
+     * @param addedHostEvents the collection of added Host Events.
+     * @param removedHostEvents the collection of removed Host Events.
+     */
+    // CHECKSTYLE:OFF suppress the warning about too many parameters
+    public TopologyEvents(long timestamp,
+                          Collection<SwitchEvent> addedSwitchEvents,
+                          Collection<SwitchEvent> removedSwitchEvents,
+                          Collection<PortEvent> addedPortEvents,
+                          Collection<PortEvent> removedPortEvents,
+                          Collection<LinkEvent> addedLinkEvents,
+                          Collection<LinkEvent> removedLinkEvents,
+                          Collection<DeviceEvent> addedHostEvents,
+                          Collection<DeviceEvent> removedHostEvents) {
+        // CHECKSTYLE:ON
+        this.timestamp = timestamp;
+        this.addedSwitchEvents =
+            Collections.unmodifiableCollection(addedSwitchEvents);
+        this.removedSwitchEvents =
+            Collections.unmodifiableCollection(removedSwitchEvents);
+        this.addedPortEvents =
+            Collections.unmodifiableCollection(addedPortEvents);
+        this.removedPortEvents =
+            Collections.unmodifiableCollection(removedPortEvents);
+        this.addedLinkEvents =
+            Collections.unmodifiableCollection(addedLinkEvents);
+        this.removedLinkEvents =
+            Collections.unmodifiableCollection(removedLinkEvents);
+        this.addedHostEvents =
+            Collections.unmodifiableCollection(addedHostEvents);
+        this.removedHostEvents =
+            Collections.unmodifiableCollection(removedHostEvents);
+    }
+
+    /**
+     * Gets the timestamp for the events.
+     *
+     * @return the timestamp for the events.
+     */
+    public long getTimestamp() {
+        return timestamp;
+    }
+
+    /**
+     * Gets the collection of added Switch Events.
+     *
+     * @return the collection of added Switch Events.
+     */
+    public Collection<SwitchEvent> getAddedSwitchEvents() {
+        return addedSwitchEvents;
+    }
+
+    /**
+     * Gets the collection of removed Switch Events.
+     *
+     * @return the collection of removed Switch Events.
+     */
+    public Collection<SwitchEvent> getRemovedSwitchEvents() {
+        return removedSwitchEvents;
+    }
+
+    /**
+     * Gets the collection of added Port Events.
+     *
+     * @return the collection of added Port Events.
+     */
+    public Collection<PortEvent> getAddedPortEvents() {
+        return addedPortEvents;
+    }
+
+    /**
+     * Gets the collection of removed Port Events.
+     *
+     * @return the collection of removed Port Events.
+     */
+    public Collection<PortEvent> getRemovedPortEvents() {
+        return removedPortEvents;
+    }
+
+    /**
+     * Gets the collection of added Link Events.
+     *
+     * @return the collection of added Link Events.
+     */
+    public Collection<LinkEvent> getAddedLinkEvents() {
+        return addedLinkEvents;
+    }
+
+    /**
+     * Gets the collection of removed Link Events.
+     *
+     * @return the collection of removed Link Events.
+     */
+    public Collection<LinkEvent> getRemovedLinkEvents() {
+        return removedLinkEvents;
+    }
+
+    /**
+     * Gets the collection of added Host Events.
+     *
+     * @return the collection of added Host Events.
+     */
+    public Collection<DeviceEvent> getAddedHostEvents() {
+        return addedHostEvents;
+    }
+
+    /**
+     * Gets the collection of removed Host Events.
+     *
+     * @return the collection of removed Host Events.
+     */
+    public Collection<DeviceEvent> getRemovedHostEvents() {
+        return removedHostEvents;
+    }
+}
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 3cff46a..3a07693 100644
--- a/src/main/java/net/onrc/onos/core/topology/TopologyManager.java
+++ b/src/main/java/net/onrc/onos/core/topology/TopologyManager.java
@@ -27,10 +27,13 @@
 import net.onrc.onos.core.util.Dpid;
 import net.onrc.onos.core.util.EventEntry;
 import net.onrc.onos.core.util.SwitchPort;
+import net.onrc.onos.core.util.serializers.KryoFactory;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.esotericsoftware.kryo.Kryo;
+
 /**
  * The TopologyManager receives topology updates from the southbound discovery
  * modules and from other ONOS instances. These updates are processed and
@@ -59,6 +62,7 @@
     private final TopologyImpl topology = new TopologyImpl();
     private final IControllerRegistryService registryService;
     private CopyOnWriteArrayList<ITopologyListener> topologyListeners;
+    private Kryo kryo = KryoFactory.newKryoObject();
 
     //
     // Local state for keeping track of reordered events.
@@ -457,16 +461,19 @@
         }
 
         // Deliver the events
+        long timestamp = System.nanoTime();
         for (ITopologyListener listener : this.topologyListeners) {
-            // TODO: Should copy before handing them over to listener?
-            listener.topologyEvents(apiAddedSwitchEvents,
-                    apiRemovedSwitchEvents,
-                    apiAddedPortEvents,
-                    apiRemovedPortEvents,
-                    apiAddedLinkEvents,
-                    apiRemovedLinkEvents,
-                    apiAddedDeviceEvents,
-                    apiRemovedDeviceEvents);
+            TopologyEvents events =
+                new TopologyEvents(timestamp,
+                                   kryo.copy(apiAddedSwitchEvents),
+                                   kryo.copy(apiRemovedSwitchEvents),
+                                   kryo.copy(apiAddedPortEvents),
+                                   kryo.copy(apiRemovedPortEvents),
+                                   kryo.copy(apiAddedLinkEvents),
+                                   kryo.copy(apiRemovedLinkEvents),
+                                   kryo.copy(apiAddedDeviceEvents),
+                                   kryo.copy(apiRemovedDeviceEvents));
+            listener.topologyEvents(events);
         }
 
         //
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 5d4adb8..568b242 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
@@ -23,6 +23,7 @@
 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.TopologyEvents;
 
 import org.hamcrest.Description;
 import org.hamcrest.Factory;
@@ -456,6 +457,7 @@
         final List<DeviceEvent> emptyDeviceEvents = new LinkedList<>();
         final List<LinkEvent> addedLinkEvents = new LinkedList<>();
         final List<LinkEvent> removedLinkEvents = new LinkedList<>();
+        TopologyEvents topologyEvents;
 
         final MockTopology topology = mocks.getTopology();
         topology.removeLink(1L, 12L, 2L, 21L); // This link is used by the intent "1"
@@ -464,10 +466,18 @@
         LinkEvent linkEvent2 = new LinkEvent(2L, 21L, 1L, 12L);
         removedLinkEvents.add(linkEvent1);
         removedLinkEvents.add(linkEvent2);
-        runtime.topologyEvents(emptySwitchEvents, emptySwitchEvents,
-                    emptyPortEvents, emptyPortEvents,
-                    addedLinkEvents, removedLinkEvents,
-                    emptyDeviceEvents, emptyDeviceEvents);
+
+        topologyEvents = new TopologyEvents(0,
+                                            emptySwitchEvents,
+                                            emptySwitchEvents,
+                                            emptyPortEvents,
+                                            emptyPortEvents,
+                                            addedLinkEvents,
+                                            removedLinkEvents,
+                                            emptyDeviceEvents,
+                                            emptyDeviceEvents);
+
+        runtime.topologyEvents(topologyEvents);
 
         //  Check the high level intents.
         final IntentMap highLevelIntentsAfterReroute = runtime.getHighLevelIntents();
@@ -681,6 +691,7 @@
         final List<DeviceEvent> emptyDeviceEvents = new LinkedList<>();
         final List<LinkEvent> addedLinkEvents = new LinkedList<>();
         final List<LinkEvent> removedLinkEvents = new LinkedList<>();
+        TopologyEvents topologyEvents;
 
         final MockTopology topology = mocks.getTopology();
         topology.removeLink(1L, 12L, 2L, 21L); // This link is used by the intent "1"
@@ -689,15 +700,18 @@
         final LinkEvent linkEvent2 = new LinkEvent(2L, 21L, 1L, 12L);
         removedLinkEvents.add(linkEvent1);
         removedLinkEvents.add(linkEvent2);
-        runtime.topologyEvents(
-                emptySwitchEvents,
-                emptySwitchEvents,
-                emptyPortEvents,
-                emptyPortEvents,
-                addedLinkEvents,
-                removedLinkEvents,
-                emptyDeviceEvents,
-                emptyDeviceEvents);
+
+        topologyEvents = new TopologyEvents(0,
+                                            emptySwitchEvents,
+                                            emptySwitchEvents,
+                                            emptyPortEvents,
+                                            emptyPortEvents,
+                                            addedLinkEvents,
+                                            removedLinkEvents,
+                                            emptyDeviceEvents,
+                                            emptyDeviceEvents);
+
+        runtime.topologyEvents(topologyEvents);
 
         //  Check the high level intents.
         final IntentMap highLevelIntentsAfterReroute = runtime.getHighLevelIntents();
@@ -739,15 +753,18 @@
         topology.addBidirectionalLinks(1L, 12L, 2L, 21L); // Restoration of the failure
         addedLinkEvents.add(linkEvent1);
         addedLinkEvents.add(linkEvent2);
-        runtime.topologyEvents(
-                emptySwitchEvents,
-                emptySwitchEvents,
-                emptyPortEvents,
-                emptyPortEvents,
-                addedLinkEvents,
-                removedLinkEvents,
-                emptyDeviceEvents,
-                emptyDeviceEvents);
+
+        topologyEvents = new TopologyEvents(0,
+                                            emptySwitchEvents,
+                                            emptySwitchEvents,
+                                            emptyPortEvents,
+                                            emptyPortEvents,
+                                            addedLinkEvents,
+                                            removedLinkEvents,
+                                            emptyDeviceEvents,
+                                            emptyDeviceEvents);
+
+        runtime.topologyEvents(topologyEvents);
 
         //  Check the high level intents.
         final IntentMap highLevelIntentsAfterInterrupt = runtime.getHighLevelIntents();
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 76af2ec..a5b8816 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
@@ -37,6 +37,7 @@
 import net.onrc.onos.core.topology.PortEvent;
 import net.onrc.onos.core.topology.SwitchEvent;
 import net.onrc.onos.core.topology.Topology;
+import net.onrc.onos.core.topology.TopologyEvents;
 
 import org.junit.After;
 import org.junit.Before;
@@ -231,6 +232,7 @@
         List<LinkEvent> removedLinkEvents = new LinkedList<>();
         List<DeviceEvent> addedDeviceEvents = new LinkedList<>();
         List<DeviceEvent> removedDeviceEvents = new LinkedList<>();
+        TopologyEvents topologyEvents;
 
         // create shortest path intents
         IntentOperationList opList = new IntentOperationList();
@@ -272,15 +274,18 @@
         removedLinkEvents.clear();
         removedLinkEvents.add(linkEvent1);
         removedLinkEvents.add(linkEvent2);
-        runtime1.topologyEvents(
-                addedSwitchEvents,
-                removedSwitchEvents,
-                addedPortEvents,
-                removedPortEvents,
-                addedLinkEvents,
-                removedLinkEvents,
-                addedDeviceEvents,
-                removedDeviceEvents);
+
+        topologyEvents = new TopologyEvents(0,
+                                            addedSwitchEvents,
+                                            removedSwitchEvents,
+                                            addedPortEvents,
+                                            removedPortEvents,
+                                            addedLinkEvents,
+                                            removedLinkEvents,
+                                            addedDeviceEvents,
+                                            removedDeviceEvents);
+
+        runtime1.topologyEvents(topologyEvents);
         System.out.println("*** Link goes down. ***");
 
         // send notification
@@ -303,15 +308,18 @@
         addedLinkEvents.clear();
         addedLinkEvents.add(linkEvent1);
         addedLinkEvents.add(linkEvent2);
-        runtime1.topologyEvents(
-                addedSwitchEvents,
-                removedSwitchEvents,
-                addedPortEvents,
-                removedPortEvents,
-                addedLinkEvents,
-                removedLinkEvents,
-                addedDeviceEvents,
-                removedDeviceEvents);
+
+        topologyEvents = new TopologyEvents(0,
+                                            addedSwitchEvents,
+                                            removedSwitchEvents,
+                                            addedPortEvents,
+                                            removedPortEvents,
+                                            addedLinkEvents,
+                                            removedLinkEvents,
+                                            addedDeviceEvents,
+                                            removedDeviceEvents);
+
+        runtime1.topologyEvents(topologyEvents);
         System.out.println("*** Link goes up. ***");
 
         // send notification