GUI -- Further work on refactoring Topology View server side code.
- includes some cleanup of UiMessageHandler and subclasses thereof.

Change-Id: Ie48d830447a4abe1b3accda41a934530a4d55d0e
diff --git a/core/api/src/main/java/org/onosproject/ui/RequestHandler.java b/core/api/src/main/java/org/onosproject/ui/RequestHandler.java
index efc9e93..1678923 100644
--- a/core/api/src/main/java/org/onosproject/ui/RequestHandler.java
+++ b/core/api/src/main/java/org/onosproject/ui/RequestHandler.java
@@ -83,6 +83,7 @@
      * @param sid       message sequence identifier
      * @param payload   message payload
      */
+    // TODO: remove sid from signature
     protected void sendMessage(String eventType, long sid, ObjectNode payload) {
         parent.connection().sendMessage(eventType, sid, payload);
     }
@@ -107,6 +108,7 @@
      * @param sid       sequence identifier
      * @param payload   message payload
      */
+    // TODO: remove sid from signature
     protected void chain(String eventType, long sid, ObjectNode payload) {
         parent.exec(eventType, sid, payload);
     }
@@ -114,11 +116,25 @@
     // ===================================================================
 
 
-    // FIXME : Javadocs
+    /**
+     * Returns the specified node property as a string.
+     *
+     * @param node message event
+     * @param key property name
+     * @return property as a string
+     */
     protected String string(ObjectNode node, String key) {
         return JsonUtils.string(node, key);
     }
 
+    /**
+     * Returns the specified node property as a string, with a default fallback.
+     *
+     * @param node         object node
+     * @param key          property name
+     * @param defValue     fallback value if property is absent
+     * @return property as a string
+     */
     protected String string(ObjectNode node, String key, String defValue) {
         return JsonUtils.string(node, key, defValue);
     }
diff --git a/core/api/src/main/java/org/onosproject/ui/UiConnection.java b/core/api/src/main/java/org/onosproject/ui/UiConnection.java
index 123acb9..ead7b0d 100644
--- a/core/api/src/main/java/org/onosproject/ui/UiConnection.java
+++ b/core/api/src/main/java/org/onosproject/ui/UiConnection.java
@@ -36,6 +36,7 @@
      * @param sid     message sequence number
      * @param payload message payload
      */
+    // TODO: remove sid parameter
     void sendMessage(String type, long sid, ObjectNode payload);
 
 }
\ No newline at end of file
diff --git a/core/api/src/main/java/org/onosproject/ui/UiMessageHandler.java b/core/api/src/main/java/org/onosproject/ui/UiMessageHandler.java
index e2f5f10..b3782a2 100644
--- a/core/api/src/main/java/org/onosproject/ui/UiMessageHandler.java
+++ b/core/api/src/main/java/org/onosproject/ui/UiMessageHandler.java
@@ -16,6 +16,7 @@
 package org.onosproject.ui;
 
 import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ArrayNode;
 import com.fasterxml.jackson.databind.node.ObjectNode;
 import org.onlab.osgi.ServiceDirectory;
 import org.slf4j.Logger;
@@ -31,41 +32,47 @@
 import static com.google.common.base.Preconditions.checkNotNull;
 
 /**
- * Abstraction of an entity capable of processing a JSON message from the user
+ * Abstraction of an entity capable of processing JSON messages from the user
  * interface client.
  * <p>
- * The message is a JSON object with the following structure:
+ * The message structure is:
  * </p>
  * <pre>
  * {
  *     "type": "<em>event-type</em>",
- *     "sid": "<em>sequence-number</em>",
  *     "payload": {
  *         <em>arbitrary JSON object structure</em>
  *     }
  * }
  * </pre>
+ * On {@link #init initialization} the handler will create and cache
+ * {@link RequestHandler} instances, each of which are bound to a particular
+ * <em>event-type</em>. On {@link #process arrival} of a new message,
+ * the <em>event-type</em> is determined, and the message dispatched to the
+ * corresponding <em>RequestHandler</em>'s
+ * {@link RequestHandler#process process} method.
  */
 public abstract class UiMessageHandler {
 
     private final Logger log = LoggerFactory.getLogger(getClass());
     private final Map<String, RequestHandler> handlerMap = new HashMap<>();
+    private final ObjectMapper mapper = new ObjectMapper();
 
     private UiConnection connection;
     private ServiceDirectory directory;
 
-    /**
-     * Mapper for creating ObjectNodes and ArrayNodes etc.
-     */
-    protected final ObjectMapper mapper = new ObjectMapper();
 
     /**
-     * Subclasses must return the collection of handlers for the
-     * message types they handle.
+     * Subclasses must create and return the collection of request handlers
+     * for the message types they handle.
+     * <p>
+     * Note that request handlers should be stateless. When we are
+     * {@link #destroy destroyed}, we will simply drop our references to them
+     * and allow them to be garbage collected.
      *
      * @return the message handler instances
      */
-    protected abstract Collection<RequestHandler> getHandlers();
+    protected abstract Collection<RequestHandler> createRequestHandlers();
 
     /**
      * Returns the set of message types which this handler is capable of
@@ -84,10 +91,9 @@
      */
     public void process(ObjectNode message) {
         String type = JsonUtils.eventType(message);
-        // TODO: remove sid
-        long sid = JsonUtils.sid(message);
         ObjectNode payload = JsonUtils.payload(message);
-        exec(type, sid, payload);
+        // TODO: remove sid
+        exec(type, 0, payload);
     }
 
     /**
@@ -99,21 +105,10 @@
      */
     // TODO: remove sid from signature
     void exec(String eventType, long sid, ObjectNode payload) {
-        RequestHandler handler = handlerMap.get(eventType);
-        if (handler != null) {
+        RequestHandler requestHandler = handlerMap.get(eventType);
+        if (requestHandler != null) {
             log.debug("process {} event...", eventType);
-            handler.process(sid, payload);
-        }
-    }
-
-    private void bindHandlers() {
-        Collection<RequestHandler> handlers = getHandlers();
-        checkNotNull(handlers, "Handlers cannot be null");
-        checkArgument(!handlers.isEmpty(), "Handlers cannot be empty");
-
-        for (RequestHandler h : handlers) {
-            h.setParent(this);
-            handlerMap.put(h.eventType(), h);
+            requestHandler.process(sid, payload);
         }
     }
 
@@ -127,7 +122,15 @@
     public void init(UiConnection connection, ServiceDirectory directory) {
         this.connection = connection;
         this.directory = directory;
-        bindHandlers();
+
+        Collection<RequestHandler> handlers = createRequestHandlers();
+        checkNotNull(handlers, "Handlers cannot be null");
+        checkArgument(!handlers.isEmpty(), "Handlers cannot be empty");
+
+        for (RequestHandler h : handlers) {
+            h.setParent(this);
+            handlerMap.put(h.eventType(), h);
+        }
     }
 
     /**
@@ -136,6 +139,7 @@
     public void destroy() {
         this.connection = null;
         this.directory = null;
+        handlerMap.clear();
     }
 
     /**
@@ -168,4 +172,21 @@
         return directory.get(serviceClass);
     }
 
+    /**
+     * Returns a freshly minted object node.
+     *
+     * @return new object node
+     */
+    protected ObjectNode objectNode() {
+        return mapper.createObjectNode();
+    }
+
+    /**
+     * Returns a freshly minted array node.
+     *
+     * @return new array node
+     */
+    protected ArrayNode arrayNode() {
+        return mapper.createArrayNode();
+    }
 }