Updated and refactored the JSON serialization of Topology-related
and "Low Intent" objects:

* Added JSON serialization for topology-related FooEvent objects
  For now, their format matches exactly the corresponding Topology Foo object:
  - DeviceEvent: matches Device
  - SwitchEvent: matches Switch
  - PortEvent: matches Port
  - LinkEvent: matches Link

* Refactored the JSON serialization of existing objects so it
  is more consistent:

============================================
  - Topology Device serialization: "port" is renamed to "portNumber"

  OLD:
{
    "mac": "00:01:02:03:04:05"
    "attachmentPoints": [
        {
            "dpid": "11:22:33:44:55:66:77:88",
            "port": 1
        },
        ...
    ]
}

  NEW:
{
    "mac": "00:01:02:03:04:05"
    "attachmentPoints": [
        {
            "dpid": "11:22:33:44:55:66:77:88",
            "portNumber": 1
        },
        ...
    ]
}
============================================
   - Low Level Intent serialization (LinkEvent used by "path"):
     portNumber is an integer instead of a string

OLD:
[
        ...
        "path": [
            {
                "src": {
                    "portNumber": "2",
                    "dpid": "00:00:00:00:00:00:02:02"
                },
                "dst": {
                    "portNumber": "2",
                    "dpid": "00:00:00:00:00:00:02:01"
                }
            },

NEW:
[
        ...
        "path": [
            {
                "src": {
                    "portNumber": 2,
                    "dpid": "00:00:00:00:00:00:02:02"
                },
                "dst": {
                    "portNumber": 2,
                    "dpid": "00:00:00:00:00:00:02:01"
                }
            },
============================================
   - Topology Link serialization: Format changed to match LinkEvent (and SwitchPort):

OLD:
{
    ...
    "links": [
        {
            "dst-switch": "00:00:00:00:00:00:01:03",
            "src-switch": "00:00:00:00:00:00:01:06",
            "src-port": 3,
            "dst-port": 4
        },

NEW:
{
    ...
    "links": [
        {
            "src": {
                "portNumber": 3,
                "dpid": "00:00:00:00:00:00:01:06"
            },
            "dst": {
                "portNumber": 4,
                "dpid": "00:00:00:00:00:00:01:03"
            }
        },

============================================
    - Topology Port serialization: Renamed "number" to "portNumber"

OLD:
{
    "switches": [
        {
            "state": "ACTIVE",
            "ports": [
                {
                    "state": "ACTIVE",
                    "desc": null,
                    "number": 1,
                    "dpid": "00:00:00:00:00:00:04:0e"
                },

NEW:
{
    "switches": [
        {
            "state": "ACTIVE",
            "ports": [
                {
                    "state": "ACTIVE",
                    "desc": null,
                    "portNumber": 1,
                    "dpid": "00:00:00:00:00:00:04:0e"
                },

============================================
      - SwitchPort serialization (used in number of places referred above):
        portNumber is an integer instead of a string
OLD:
                {
                    "portNumber": "2",
                    "dpid": "00:00:00:00:00:00:02:02"
                }

NEW:
                {
                    "portNumber": 2,
                    "dpid": "00:00:00:00:00:00:02:02"
                }

======================

* Added JSON serialization for TopologyEvents. The format is:

{
    "addedSwitches": [
        {
            "state": "ACTIVE",
            "ports": [
            ],
            "dpid": "00:00:00:00:00:00:02:07"
        },
        ...
    ],
    "removedSwitches": [
        {
            "state": "ACTIVE",
            "ports": [
            ],
            "dpid": "00:00:00:00:00:00:02:08"
        },
        ...
    ],
    "addedPorts": [
        {
            "state": "ACTIVE",
            "desc": null,
            "portNumber": 1,
            "dpid": "00:00:00:00:00:00:02:07"
        },
        ...
    ],
    "removedPorts": [
        {
            "state": "ACTIVE",
            "desc": null,
            "portNumber": 1,
            "dpid": "00:00:00:00:00:00:02:08"
        },
        ...
    ],
    "addedLinks": [
        {
            "src": {
                "portNumber": 10,
                "dpid": "00:00:00:00:00:00:04:01"
            },
            "dst": {
                "portNumber": 2,
                "dpid": "00:00:00:00:00:00:04:0a"
            }
        },
        ...
    ],
    "removedLinks": [
        {
            "src": {
                "portNumber": 5,
                "dpid": "00:00:00:00:00:00:05:01"
            },
            "dst": {
                "portNumber": 6,
                "dpid": "00:00:00:00:00:00:05:0a"
            }
        },
        ...
    ],
    "addedHosts": [
        {
            "mac": "00:01:02:03:04:05"
            "attachmentPoints": [
                {
                    "dpid": "11:22:33:44:55:66:77:88",
                    "port": 1
                },
                ...
            ]
        },
        ...
    ],
    "removedHosts": [
        {
            "mac": "00:01:02:03:08:08"
            "attachmentPoints": [
                {
                    "dpid": "11:22:33:44:55:11:11:11",
                    "port": 1
                },
                ...
            ]
        },
        ...
    ]
}

Change-Id: Ib72be653bc03444b888c0417b3f026966a7df3f3
diff --git a/src/main/java/net/onrc/onos/core/topology/web/serializers/DeviceEventSerializer.java b/src/main/java/net/onrc/onos/core/topology/web/serializers/DeviceEventSerializer.java
new file mode 100644
index 0000000..94ccce2
--- /dev/null
+++ b/src/main/java/net/onrc/onos/core/topology/web/serializers/DeviceEventSerializer.java
@@ -0,0 +1,38 @@
+package net.onrc.onos.core.topology.web.serializers;
+
+import java.io.IOException;
+
+import net.onrc.onos.core.topology.DeviceEvent;
+import net.onrc.onos.core.util.SwitchPort;
+
+import org.codehaus.jackson.JsonGenerator;
+import org.codehaus.jackson.map.SerializerProvider;
+import org.codehaus.jackson.map.ser.std.SerializerBase;
+
+public class DeviceEventSerializer extends SerializerBase<DeviceEvent> {
+
+    public DeviceEventSerializer() {
+        super(DeviceEvent.class);
+    }
+
+    @Override
+    public void serialize(DeviceEvent deviceEvent, JsonGenerator jsonGenerator,
+        SerializerProvider serializerProvider) throws IOException {
+
+        //
+        // TODO: For now, the JSON format of the serialized output should
+        // be same as the JSON format of the corresponding class Device.
+        // In the future, we will use a single serializer.
+        //
+
+        jsonGenerator.writeStartObject();
+        jsonGenerator.writeStringField("mac", deviceEvent.getMac().toString());
+        jsonGenerator.writeFieldName("attachmentPoints");
+        jsonGenerator.writeStartArray();
+        for (SwitchPort switchPort : deviceEvent.getAttachmentPoints()) {
+            jsonGenerator.writeObject(switchPort);
+        }
+        jsonGenerator.writeEndArray();
+        jsonGenerator.writeEndObject();
+    }
+}
diff --git a/src/main/java/net/onrc/onos/core/topology/web/serializers/DeviceSerializer.java b/src/main/java/net/onrc/onos/core/topology/web/serializers/DeviceSerializer.java
index 5319adf..1f8676a 100644
--- a/src/main/java/net/onrc/onos/core/topology/web/serializers/DeviceSerializer.java
+++ b/src/main/java/net/onrc/onos/core/topology/web/serializers/DeviceSerializer.java
@@ -18,16 +18,19 @@
     @Override
     public void serialize(Device dev, JsonGenerator jsonGenerator,
         SerializerProvider serializerProvider) throws IOException {
+
+        //
+        // TODO: For now, the JSON format of the serialized output should
+        // be same as the JSON format of the corresponding class DeviceEvent.
+        // In the future, we will use a single serializer.
+        //
+
         jsonGenerator.writeStartObject();
         jsonGenerator.writeStringField("mac", dev.getMacAddress().toString());
         jsonGenerator.writeFieldName("attachmentPoints");
         jsonGenerator.writeStartArray();
         for (Port port : dev.getAttachmentPoints()) {
-            jsonGenerator.writeStartObject();
-            jsonGenerator.writeStringField("dpid", port.getDpid().toString());
-            // XXX Should port number be treated as unsigned?
-            jsonGenerator.writeNumberField("port", port.getNumber().value());
-            jsonGenerator.writeEndObject();
+            jsonGenerator.writeObject(port.asSwitchPort());
         }
         jsonGenerator.writeEndArray();
         jsonGenerator.writeEndObject();
diff --git a/src/main/java/net/onrc/onos/core/topology/web/serializers/LinkEventSerializer.java b/src/main/java/net/onrc/onos/core/topology/web/serializers/LinkEventSerializer.java
index 2621167..0678d49 100644
--- a/src/main/java/net/onrc/onos/core/topology/web/serializers/LinkEventSerializer.java
+++ b/src/main/java/net/onrc/onos/core/topology/web/serializers/LinkEventSerializer.java
@@ -33,11 +33,15 @@
                           final SerializerProvider serializerProvider)
             throws IOException {
 
-        jsonGenerator.writeStartObject();
+        //
+        // TODO: For now, the JSON format of the serialized output should
+        // be same as the JSON format of the corresponding class Link.
+        // In the future, we will use a single serializer.
+        //
 
+        jsonGenerator.writeStartObject();
         jsonGenerator.writeObjectField("src", linkEvent.getSrc());
         jsonGenerator.writeObjectField("dst", linkEvent.getDst());
-
         jsonGenerator.writeEndObject();
     }
 }
diff --git a/src/main/java/net/onrc/onos/core/topology/web/serializers/LinkSerializer.java b/src/main/java/net/onrc/onos/core/topology/web/serializers/LinkSerializer.java
index 1cecca5..bec4760 100644
--- a/src/main/java/net/onrc/onos/core/topology/web/serializers/LinkSerializer.java
+++ b/src/main/java/net/onrc/onos/core/topology/web/serializers/LinkSerializer.java
@@ -18,17 +18,15 @@
     public void serialize(Link link, JsonGenerator jsonGenerator,
                           SerializerProvider serializerProvider)
             throws IOException {
+
+        //
+        // TODO: For now, the JSON format of the serialized output should
+        // be same as the JSON format of the corresponding class LinkEvent.
+        // In the future, we will use a single serializer.
+        //
         jsonGenerator.writeStartObject();
-        jsonGenerator.writeStringField("src-switch",
-                link.getSrcSwitch().getDpid().toString());
-        // XXX port number as unsigned?
-        jsonGenerator.writeNumberField("src-port",
-                link.getSrcPort().getNumber().value());
-        jsonGenerator.writeStringField("dst-switch",
-                link.getDstSwitch().getDpid().toString());
-        jsonGenerator.writeNumberField("dst-port",
-                link.getDstPort().getNumber().value());
+        jsonGenerator.writeObjectField("src", link.getSrcPort().asSwitchPort());
+        jsonGenerator.writeObjectField("dst", link.getDstPort().asSwitchPort());
         jsonGenerator.writeEndObject();
     }
-
 }
diff --git a/src/main/java/net/onrc/onos/core/topology/web/serializers/PortEventSerializer.java b/src/main/java/net/onrc/onos/core/topology/web/serializers/PortEventSerializer.java
new file mode 100644
index 0000000..84f23ac
--- /dev/null
+++ b/src/main/java/net/onrc/onos/core/topology/web/serializers/PortEventSerializer.java
@@ -0,0 +1,41 @@
+package net.onrc.onos.core.topology.web.serializers;
+
+import java.io.IOException;
+
+import net.onrc.onos.core.topology.PortEvent;
+
+import org.codehaus.jackson.JsonGenerator;
+import org.codehaus.jackson.map.SerializerProvider;
+import org.codehaus.jackson.map.ser.std.SerializerBase;
+
+public class PortEventSerializer extends SerializerBase<PortEvent> {
+
+    public PortEventSerializer() {
+        super(PortEvent.class);
+    }
+
+    @Override
+    public void serialize(PortEvent portEvent, JsonGenerator jsonGenerator,
+                          SerializerProvider serializerProvider)
+            throws IOException {
+        //
+        // TODO: For now, the JSON format of the serialized output should
+        // be same as the JSON format of the corresponding class Port.
+        // In the future, we will use a single serializer.
+        //
+
+        jsonGenerator.writeStartObject();
+        jsonGenerator.writeStringField("state", "ACTIVE");
+        jsonGenerator.writeStringField("dpid", portEvent.getDpid().toString());
+        //
+        // FIXME: The solution below to preresent the "short" port number
+        // as an unsigned value is a hack. The fix should be elsewhere
+        // (e.g., in class PortNumber itself).
+        //
+        jsonGenerator.writeNumberField("portNumber",
+                                       (0xffff & portEvent.getPortNumber().value()));
+        jsonGenerator.writeStringField("desc",
+                                       null /* port.getDescription() */);
+        jsonGenerator.writeEndObject();
+    }
+}
diff --git a/src/main/java/net/onrc/onos/core/topology/web/serializers/PortSerializer.java b/src/main/java/net/onrc/onos/core/topology/web/serializers/PortSerializer.java
index 52fbe44..a0d7385 100644
--- a/src/main/java/net/onrc/onos/core/topology/web/serializers/PortSerializer.java
+++ b/src/main/java/net/onrc/onos/core/topology/web/serializers/PortSerializer.java
@@ -18,12 +18,23 @@
     public void serialize(Port port, JsonGenerator jsonGenerator,
                           SerializerProvider serializerProvider)
             throws IOException {
+        //
+        // TODO: For now, the JSON format of the serialized output should
+        // be same as the JSON format of the corresponding class PortEvent.
+        // In the future, we will use a single serializer.
+        //
+
         jsonGenerator.writeStartObject();
         jsonGenerator.writeStringField("state", "ACTIVE");
         jsonGenerator.writeStringField("dpid", port.getDpid().toString());
-        jsonGenerator.writeNumberField("number", port.getNumber().value());
+        //
+        // FIXME: The solution below to preresent the "short" port number
+        // as an unsigned value is a hack. The fix should be elsewhere
+        // (e.g., in class PortNumber itself).
+        //
+        jsonGenerator.writeNumberField("portNumber",
+                                       (0xffff & port.getNumber().value()));
         jsonGenerator.writeStringField("desc", port.getDescription());
         jsonGenerator.writeEndObject();
     }
-
 }
diff --git a/src/main/java/net/onrc/onos/core/topology/web/serializers/SwitchEventSerializer.java b/src/main/java/net/onrc/onos/core/topology/web/serializers/SwitchEventSerializer.java
new file mode 100644
index 0000000..09358c4
--- /dev/null
+++ b/src/main/java/net/onrc/onos/core/topology/web/serializers/SwitchEventSerializer.java
@@ -0,0 +1,43 @@
+package net.onrc.onos.core.topology.web.serializers;
+
+import java.io.IOException;
+
+import net.onrc.onos.core.topology.SwitchEvent;
+
+import org.codehaus.jackson.JsonGenerator;
+import org.codehaus.jackson.map.SerializerProvider;
+import org.codehaus.jackson.map.ser.std.SerializerBase;
+
+public class SwitchEventSerializer extends SerializerBase<SwitchEvent> {
+
+    public SwitchEventSerializer() {
+        super(SwitchEvent.class);
+    }
+
+    @Override
+    public void serialize(SwitchEvent switchEvent, JsonGenerator jsonGenerator,
+                          SerializerProvider serializerProvider) throws IOException {
+        //
+        // TODO: For now, the JSON format of the serialized output should
+        // be same as the JSON format of the corresponding class Switch.
+        // In the future, we will use a single serializer.
+        //
+
+        jsonGenerator.writeStartObject();
+        jsonGenerator.writeStringField("dpid",
+                                       switchEvent.getDpid().toString());
+        jsonGenerator.writeStringField("state", "ACTIVE");
+        //
+        // TODO: For now, we write empty "ports" array for consistency
+        // with the corresponding Switch JSON serializer.
+        //
+        jsonGenerator.writeArrayFieldStart("ports");
+        /*
+        for (Port port : sw.getPorts()) {
+            jsonGenerator.writeObject(port);
+        }
+        */
+        jsonGenerator.writeEndArray();
+        jsonGenerator.writeEndObject();
+    }
+}
diff --git a/src/main/java/net/onrc/onos/core/topology/web/serializers/SwitchSerializer.java b/src/main/java/net/onrc/onos/core/topology/web/serializers/SwitchSerializer.java
index 01bd22f..3b74c53 100644
--- a/src/main/java/net/onrc/onos/core/topology/web/serializers/SwitchSerializer.java
+++ b/src/main/java/net/onrc/onos/core/topology/web/serializers/SwitchSerializer.java
@@ -18,6 +18,11 @@
     @Override
     public void serialize(Switch sw, JsonGenerator jsonGenerator,
                           SerializerProvider serializerProvider) throws IOException {
+        //
+        // TODO: For now, the JSON format of the serialized output should
+        // be same as the JSON format of the corresponding class SwitchEvent.
+        // In the future, we will use a single serializer.
+        //
 
         jsonGenerator.writeStartObject();
         jsonGenerator.writeStringField("dpid", sw.getDpid().toString());
@@ -29,5 +34,4 @@
         jsonGenerator.writeEndArray();
         jsonGenerator.writeEndObject();
     }
-
 }
diff --git a/src/main/java/net/onrc/onos/core/topology/web/serializers/TopologyEventsSerializer.java b/src/main/java/net/onrc/onos/core/topology/web/serializers/TopologyEventsSerializer.java
new file mode 100644
index 0000000..e5f81c0
--- /dev/null
+++ b/src/main/java/net/onrc/onos/core/topology/web/serializers/TopologyEventsSerializer.java
@@ -0,0 +1,105 @@
+package net.onrc.onos.core.topology.web.serializers;
+
+import net.onrc.onos.core.topology.DeviceEvent;
+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 org.codehaus.jackson.JsonGenerator;
+import org.codehaus.jackson.map.SerializerProvider;
+import org.codehaus.jackson.map.ser.std.SerializerBase;
+
+import java.io.IOException;
+
+/**
+ * JSON serializer for TopologyEvents objects.  Used by WebSocket
+ * implementation of the topology APIs.
+ */
+public class TopologyEventsSerializer extends SerializerBase<TopologyEvents> {
+
+    /**
+     * Default constructor. Performs basic initialization of the JSON
+     * serializer.
+     */
+    public TopologyEventsSerializer() {
+        super(TopologyEvents.class);
+    }
+
+    /**
+     * Serialize a TopologyEvents object in JSON.  The resulting JSON contains
+     * the added and removed topology objects: switches, links and ports.
+     *
+     * @param topologyEvents the TopologyEvents that is being converted to JSON
+     * @param jsonGenerator generator to place the serialized JSON into
+     * @param serializerProvider unused but required for method override
+     * @throws IOException if the JSON serialization process fails
+     */
+    @Override
+    public void serialize(TopologyEvents topologyEvents,
+                          JsonGenerator jsonGenerator,
+                          SerializerProvider serializerProvider)
+            throws IOException {
+
+        // Start the object
+        jsonGenerator.writeStartObject();
+
+        // Output the added switches array
+        jsonGenerator.writeArrayFieldStart("addedSwitches");
+        for (final SwitchEvent switchEvent : topologyEvents.getAddedSwitchEvents()) {
+            jsonGenerator.writeObject(switchEvent);
+        }
+        jsonGenerator.writeEndArray();
+
+        // Output the removed switches array
+        jsonGenerator.writeArrayFieldStart("removedSwitches");
+        for (final SwitchEvent switchEvent : topologyEvents.getRemovedSwitchEvents()) {
+            jsonGenerator.writeObject(switchEvent);
+        }
+        jsonGenerator.writeEndArray();
+
+        // Output the added ports array
+        jsonGenerator.writeArrayFieldStart("addedPorts");
+        for (final PortEvent portEvent : topologyEvents.getAddedPortEvents()) {
+            jsonGenerator.writeObject(portEvent);
+        }
+        jsonGenerator.writeEndArray();
+
+        // Output the removed ports array
+        jsonGenerator.writeArrayFieldStart("removedPorts");
+        for (final PortEvent portEvent : topologyEvents.getRemovedPortEvents()) {
+            jsonGenerator.writeObject(portEvent);
+        }
+        jsonGenerator.writeEndArray();
+
+        // Output the added links array
+        jsonGenerator.writeArrayFieldStart("addedLinks");
+        for (final LinkEvent linkEvent : topologyEvents.getAddedLinkEvents()) {
+            jsonGenerator.writeObject(linkEvent);
+        }
+        jsonGenerator.writeEndArray();
+
+        // Output the removed links array
+        jsonGenerator.writeArrayFieldStart("removedLinks");
+        for (final LinkEvent linkEvent : topologyEvents.getRemovedLinkEvents()) {
+            jsonGenerator.writeObject(linkEvent);
+        }
+        jsonGenerator.writeEndArray();
+
+        // Output the added hosts array
+        jsonGenerator.writeArrayFieldStart("addedHosts");
+        for (final DeviceEvent hostEvent : topologyEvents.getAddedHostEvents()) {
+            jsonGenerator.writeObject(hostEvent);
+        }
+        jsonGenerator.writeEndArray();
+
+        // Output the removed hosts array
+        jsonGenerator.writeArrayFieldStart("removedHosts");
+        for (final DeviceEvent hostEvent : topologyEvents.getRemovedHostEvents()) {
+            jsonGenerator.writeObject(hostEvent);
+        }
+        jsonGenerator.writeEndArray();
+
+        // All done
+        jsonGenerator.writeEndObject();
+    }
+}