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();
+ }
}