Simon Hunt

GUI -- Further work on refactoring Topology View server side code.

- includes some cleanup of UiMessageHandler and subclasses thereof.

Change-Id: Ie48d830447a4abe1b3accda41a934530a4d55d0e
...@@ -108,7 +108,7 @@ public class IntentPerfUi { ...@@ -108,7 +108,7 @@ public class IntentPerfUi {
108 private boolean streamingEnabled = false; 108 private boolean streamingEnabled = false;
109 109
110 @Override 110 @Override
111 - protected Collection<RequestHandler> getHandlers() { 111 + protected Collection<RequestHandler> createRequestHandlers() {
112 return ImmutableSet.of( 112 return ImmutableSet.of(
113 new IntentPerfStart(), 113 new IntentPerfStart(),
114 new IntentPerfStop() 114 new IntentPerfStop()
...@@ -135,8 +135,8 @@ public class IntentPerfUi { ...@@ -135,8 +135,8 @@ public class IntentPerfUi {
135 135
136 136
137 private ObjectNode sampleNode(Sample sample) { 137 private ObjectNode sampleNode(Sample sample) {
138 - ObjectNode sampleNode = mapper.createObjectNode(); 138 + ObjectNode sampleNode = objectNode();
139 - ArrayNode an = mapper.createArrayNode(); 139 + ArrayNode an = arrayNode();
140 sampleNode.put("time", sample.time); 140 sampleNode.put("time", sample.time);
141 sampleNode.set("data", an); 141 sampleNode.set("data", an);
142 142
......
...@@ -83,6 +83,7 @@ public abstract class RequestHandler { ...@@ -83,6 +83,7 @@ public abstract class RequestHandler {
83 * @param sid message sequence identifier 83 * @param sid message sequence identifier
84 * @param payload message payload 84 * @param payload message payload
85 */ 85 */
86 + // TODO: remove sid from signature
86 protected void sendMessage(String eventType, long sid, ObjectNode payload) { 87 protected void sendMessage(String eventType, long sid, ObjectNode payload) {
87 parent.connection().sendMessage(eventType, sid, payload); 88 parent.connection().sendMessage(eventType, sid, payload);
88 } 89 }
...@@ -107,6 +108,7 @@ public abstract class RequestHandler { ...@@ -107,6 +108,7 @@ public abstract class RequestHandler {
107 * @param sid sequence identifier 108 * @param sid sequence identifier
108 * @param payload message payload 109 * @param payload message payload
109 */ 110 */
111 + // TODO: remove sid from signature
110 protected void chain(String eventType, long sid, ObjectNode payload) { 112 protected void chain(String eventType, long sid, ObjectNode payload) {
111 parent.exec(eventType, sid, payload); 113 parent.exec(eventType, sid, payload);
112 } 114 }
...@@ -114,11 +116,25 @@ public abstract class RequestHandler { ...@@ -114,11 +116,25 @@ public abstract class RequestHandler {
114 // =================================================================== 116 // ===================================================================
115 117
116 118
117 - // FIXME : Javadocs 119 + /**
120 + * Returns the specified node property as a string.
121 + *
122 + * @param node message event
123 + * @param key property name
124 + * @return property as a string
125 + */
118 protected String string(ObjectNode node, String key) { 126 protected String string(ObjectNode node, String key) {
119 return JsonUtils.string(node, key); 127 return JsonUtils.string(node, key);
120 } 128 }
121 129
130 + /**
131 + * Returns the specified node property as a string, with a default fallback.
132 + *
133 + * @param node object node
134 + * @param key property name
135 + * @param defValue fallback value if property is absent
136 + * @return property as a string
137 + */
122 protected String string(ObjectNode node, String key, String defValue) { 138 protected String string(ObjectNode node, String key, String defValue) {
123 return JsonUtils.string(node, key, defValue); 139 return JsonUtils.string(node, key, defValue);
124 } 140 }
......
...@@ -36,6 +36,7 @@ public interface UiConnection { ...@@ -36,6 +36,7 @@ public interface UiConnection {
36 * @param sid message sequence number 36 * @param sid message sequence number
37 * @param payload message payload 37 * @param payload message payload
38 */ 38 */
39 + // TODO: remove sid parameter
39 void sendMessage(String type, long sid, ObjectNode payload); 40 void sendMessage(String type, long sid, ObjectNode payload);
40 41
41 } 42 }
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
16 package org.onosproject.ui; 16 package org.onosproject.ui;
17 17
18 import com.fasterxml.jackson.databind.ObjectMapper; 18 import com.fasterxml.jackson.databind.ObjectMapper;
19 +import com.fasterxml.jackson.databind.node.ArrayNode;
19 import com.fasterxml.jackson.databind.node.ObjectNode; 20 import com.fasterxml.jackson.databind.node.ObjectNode;
20 import org.onlab.osgi.ServiceDirectory; 21 import org.onlab.osgi.ServiceDirectory;
21 import org.slf4j.Logger; 22 import org.slf4j.Logger;
...@@ -31,41 +32,47 @@ import static com.google.common.base.Preconditions.checkArgument; ...@@ -31,41 +32,47 @@ import static com.google.common.base.Preconditions.checkArgument;
31 import static com.google.common.base.Preconditions.checkNotNull; 32 import static com.google.common.base.Preconditions.checkNotNull;
32 33
33 /** 34 /**
34 - * Abstraction of an entity capable of processing a JSON message from the user 35 + * Abstraction of an entity capable of processing JSON messages from the user
35 * interface client. 36 * interface client.
36 * <p> 37 * <p>
37 - * The message is a JSON object with the following structure: 38 + * The message structure is:
38 * </p> 39 * </p>
39 * <pre> 40 * <pre>
40 * { 41 * {
41 * "type": "<em>event-type</em>", 42 * "type": "<em>event-type</em>",
42 - * "sid": "<em>sequence-number</em>",
43 * "payload": { 43 * "payload": {
44 * <em>arbitrary JSON object structure</em> 44 * <em>arbitrary JSON object structure</em>
45 * } 45 * }
46 * } 46 * }
47 * </pre> 47 * </pre>
48 + * On {@link #init initialization} the handler will create and cache
49 + * {@link RequestHandler} instances, each of which are bound to a particular
50 + * <em>event-type</em>. On {@link #process arrival} of a new message,
51 + * the <em>event-type</em> is determined, and the message dispatched to the
52 + * corresponding <em>RequestHandler</em>'s
53 + * {@link RequestHandler#process process} method.
48 */ 54 */
49 public abstract class UiMessageHandler { 55 public abstract class UiMessageHandler {
50 56
51 private final Logger log = LoggerFactory.getLogger(getClass()); 57 private final Logger log = LoggerFactory.getLogger(getClass());
52 private final Map<String, RequestHandler> handlerMap = new HashMap<>(); 58 private final Map<String, RequestHandler> handlerMap = new HashMap<>();
59 + private final ObjectMapper mapper = new ObjectMapper();
53 60
54 private UiConnection connection; 61 private UiConnection connection;
55 private ServiceDirectory directory; 62 private ServiceDirectory directory;
56 63
57 - /**
58 - * Mapper for creating ObjectNodes and ArrayNodes etc.
59 - */
60 - protected final ObjectMapper mapper = new ObjectMapper();
61 64
62 /** 65 /**
63 - * Subclasses must return the collection of handlers for the 66 + * Subclasses must create and return the collection of request handlers
64 - * message types they handle. 67 + * for the message types they handle.
68 + * <p>
69 + * Note that request handlers should be stateless. When we are
70 + * {@link #destroy destroyed}, we will simply drop our references to them
71 + * and allow them to be garbage collected.
65 * 72 *
66 * @return the message handler instances 73 * @return the message handler instances
67 */ 74 */
68 - protected abstract Collection<RequestHandler> getHandlers(); 75 + protected abstract Collection<RequestHandler> createRequestHandlers();
69 76
70 /** 77 /**
71 * Returns the set of message types which this handler is capable of 78 * Returns the set of message types which this handler is capable of
...@@ -84,10 +91,9 @@ public abstract class UiMessageHandler { ...@@ -84,10 +91,9 @@ public abstract class UiMessageHandler {
84 */ 91 */
85 public void process(ObjectNode message) { 92 public void process(ObjectNode message) {
86 String type = JsonUtils.eventType(message); 93 String type = JsonUtils.eventType(message);
87 - // TODO: remove sid
88 - long sid = JsonUtils.sid(message);
89 ObjectNode payload = JsonUtils.payload(message); 94 ObjectNode payload = JsonUtils.payload(message);
90 - exec(type, sid, payload); 95 + // TODO: remove sid
96 + exec(type, 0, payload);
91 } 97 }
92 98
93 /** 99 /**
...@@ -99,21 +105,10 @@ public abstract class UiMessageHandler { ...@@ -99,21 +105,10 @@ public abstract class UiMessageHandler {
99 */ 105 */
100 // TODO: remove sid from signature 106 // TODO: remove sid from signature
101 void exec(String eventType, long sid, ObjectNode payload) { 107 void exec(String eventType, long sid, ObjectNode payload) {
102 - RequestHandler handler = handlerMap.get(eventType); 108 + RequestHandler requestHandler = handlerMap.get(eventType);
103 - if (handler != null) { 109 + if (requestHandler != null) {
104 log.debug("process {} event...", eventType); 110 log.debug("process {} event...", eventType);
105 - handler.process(sid, payload); 111 + requestHandler.process(sid, payload);
106 - }
107 - }
108 -
109 - private void bindHandlers() {
110 - Collection<RequestHandler> handlers = getHandlers();
111 - checkNotNull(handlers, "Handlers cannot be null");
112 - checkArgument(!handlers.isEmpty(), "Handlers cannot be empty");
113 -
114 - for (RequestHandler h : handlers) {
115 - h.setParent(this);
116 - handlerMap.put(h.eventType(), h);
117 } 112 }
118 } 113 }
119 114
...@@ -127,7 +122,15 @@ public abstract class UiMessageHandler { ...@@ -127,7 +122,15 @@ public abstract class UiMessageHandler {
127 public void init(UiConnection connection, ServiceDirectory directory) { 122 public void init(UiConnection connection, ServiceDirectory directory) {
128 this.connection = connection; 123 this.connection = connection;
129 this.directory = directory; 124 this.directory = directory;
130 - bindHandlers(); 125 +
126 + Collection<RequestHandler> handlers = createRequestHandlers();
127 + checkNotNull(handlers, "Handlers cannot be null");
128 + checkArgument(!handlers.isEmpty(), "Handlers cannot be empty");
129 +
130 + for (RequestHandler h : handlers) {
131 + h.setParent(this);
132 + handlerMap.put(h.eventType(), h);
133 + }
131 } 134 }
132 135
133 /** 136 /**
...@@ -136,6 +139,7 @@ public abstract class UiMessageHandler { ...@@ -136,6 +139,7 @@ public abstract class UiMessageHandler {
136 public void destroy() { 139 public void destroy() {
137 this.connection = null; 140 this.connection = null;
138 this.directory = null; 141 this.directory = null;
142 + handlerMap.clear();
139 } 143 }
140 144
141 /** 145 /**
...@@ -168,4 +172,21 @@ public abstract class UiMessageHandler { ...@@ -168,4 +172,21 @@ public abstract class UiMessageHandler {
168 return directory.get(serviceClass); 172 return directory.get(serviceClass);
169 } 173 }
170 174
175 + /**
176 + * Returns a freshly minted object node.
177 + *
178 + * @return new object node
179 + */
180 + protected ObjectNode objectNode() {
181 + return mapper.createObjectNode();
182 + }
183 +
184 + /**
185 + * Returns a freshly minted array node.
186 + *
187 + * @return new array node
188 + */
189 + protected ArrayNode arrayNode() {
190 + return mapper.createArrayNode();
191 + }
171 } 192 }
......
...@@ -53,6 +53,7 @@ public class AltTopoViewMessageHandler extends UiMessageHandler ...@@ -53,6 +53,7 @@ public class AltTopoViewMessageHandler extends UiMessageHandler
53 private static final String TOPO_START = "topoStart"; 53 private static final String TOPO_START = "topoStart";
54 private static final String TOPO_STOP = "topoStop"; 54 private static final String TOPO_STOP = "topoStop";
55 private static final String REQ_SUMMARY = "requestSummary"; 55 private static final String REQ_SUMMARY = "requestSummary";
56 + private static final String CANCEL_SUMMARY = "cancelSummary";
56 57
57 private final Logger log = LoggerFactory.getLogger(getClass()); 58 private final Logger log = LoggerFactory.getLogger(getClass());
58 59
...@@ -80,6 +81,13 @@ public class AltTopoViewMessageHandler extends UiMessageHandler ...@@ -80,6 +81,13 @@ public class AltTopoViewMessageHandler extends UiMessageHandler
80 currentSummaryGenerator = defaultSummaryGenerator; 81 currentSummaryGenerator = defaultSummaryGenerator;
81 } 82 }
82 83
84 + @Override
85 + public void destroy() {
86 +// cancelAllMonitoring();
87 +// stopListeningToModel();
88 + super.destroy();
89 + }
90 +
83 91
84 private String getVersion() { 92 private String getVersion() {
85 String ver = directory.get(CoreService.class).version().toString(); 93 String ver = directory.get(CoreService.class).version().toString();
...@@ -88,11 +96,12 @@ public class AltTopoViewMessageHandler extends UiMessageHandler ...@@ -88,11 +96,12 @@ public class AltTopoViewMessageHandler extends UiMessageHandler
88 96
89 97
90 @Override 98 @Override
91 - protected Collection<RequestHandler> getHandlers() { 99 + protected Collection<RequestHandler> createRequestHandlers() {
92 return ImmutableSet.of( 100 return ImmutableSet.of(
93 new TopoStart(), 101 new TopoStart(),
94 new TopoStop(), 102 new TopoStop(),
95 - new ReqSummary() 103 + new ReqSummary(),
104 + new CancelSummary()
96 // TODO: add more handlers here..... 105 // TODO: add more handlers here.....
97 ); 106 );
98 } 107 }
...@@ -157,6 +166,17 @@ public class AltTopoViewMessageHandler extends UiMessageHandler ...@@ -157,6 +166,17 @@ public class AltTopoViewMessageHandler extends UiMessageHandler
157 } 166 }
158 } 167 }
159 168
169 + private final class CancelSummary extends RequestHandler {
170 + private CancelSummary() {
171 + super(CANCEL_SUMMARY);
172 + }
173 +
174 + @Override
175 + public void process(long sid, ObjectNode payload) {
176 + modelService.stopSummaryMonitoring();
177 + }
178 + }
179 +
160 // ===================================================================== 180 // =====================================================================
161 181
162 private final class DefSummaryGenerator extends AbstractSummaryGenerator { 182 private final class DefSummaryGenerator extends AbstractSummaryGenerator {
......
...@@ -57,7 +57,7 @@ public class ApplicationViewMessageHandler extends UiMessageHandler { ...@@ -57,7 +57,7 @@ public class ApplicationViewMessageHandler extends UiMessageHandler {
57 }; 57 };
58 58
59 @Override 59 @Override
60 - protected Collection<RequestHandler> getHandlers() { 60 + protected Collection<RequestHandler> createRequestHandlers() {
61 return ImmutableSet.of( 61 return ImmutableSet.of(
62 new AppDataRequest(), 62 new AppDataRequest(),
63 new AppMgmtRequest() 63 new AppMgmtRequest()
......
...@@ -54,7 +54,7 @@ public class ClusterViewMessageHandler extends UiMessageHandler { ...@@ -54,7 +54,7 @@ public class ClusterViewMessageHandler extends UiMessageHandler {
54 private static final String ICON_ID_OFFLINE = "inactive"; 54 private static final String ICON_ID_OFFLINE = "inactive";
55 55
56 @Override 56 @Override
57 - protected Collection<RequestHandler> getHandlers() { 57 + protected Collection<RequestHandler> createRequestHandlers() {
58 return ImmutableSet.of(new ClusterDataRequest()); 58 return ImmutableSet.of(new ClusterDataRequest());
59 } 59 }
60 60
......
...@@ -84,7 +84,7 @@ public class DeviceViewMessageHandler extends UiMessageHandler { ...@@ -84,7 +84,7 @@ public class DeviceViewMessageHandler extends UiMessageHandler {
84 private static final String ICON_ID_OFFLINE = "inactive"; 84 private static final String ICON_ID_OFFLINE = "inactive";
85 85
86 @Override 86 @Override
87 - protected Collection<RequestHandler> getHandlers() { 87 + protected Collection<RequestHandler> createRequestHandlers() {
88 return ImmutableSet.of( 88 return ImmutableSet.of(
89 new DataRequestHandler(), 89 new DataRequestHandler(),
90 new DetailRequestHandler() 90 new DetailRequestHandler()
......
...@@ -65,7 +65,7 @@ public class FlowViewMessageHandler extends UiMessageHandler { ...@@ -65,7 +65,7 @@ public class FlowViewMessageHandler extends UiMessageHandler {
65 }; 65 };
66 66
67 @Override 67 @Override
68 - protected Collection<RequestHandler> getHandlers() { 68 + protected Collection<RequestHandler> createRequestHandlers() {
69 return ImmutableSet.of(new FlowDataRequest()); 69 return ImmutableSet.of(new FlowDataRequest());
70 } 70 }
71 71
......
...@@ -56,7 +56,7 @@ public class GroupViewMessageHandler extends UiMessageHandler { ...@@ -56,7 +56,7 @@ public class GroupViewMessageHandler extends UiMessageHandler {
56 }; 56 };
57 57
58 @Override 58 @Override
59 - protected Collection<RequestHandler> getHandlers() { 59 + protected Collection<RequestHandler> createRequestHandlers() {
60 return ImmutableSet.of(new GroupDataRequest()); 60 return ImmutableSet.of(new GroupDataRequest());
61 } 61 }
62 62
......
...@@ -56,7 +56,7 @@ public class HostViewMessageHandler extends UiMessageHandler { ...@@ -56,7 +56,7 @@ public class HostViewMessageHandler extends UiMessageHandler {
56 }; 56 };
57 57
58 @Override 58 @Override
59 - protected Collection<RequestHandler> getHandlers() { 59 + protected Collection<RequestHandler> createRequestHandlers() {
60 return ImmutableSet.of(new HostDataRequest()); 60 return ImmutableSet.of(new HostDataRequest());
61 } 61 }
62 62
......
...@@ -63,7 +63,7 @@ public class IntentViewMessageHandler extends UiMessageHandler { ...@@ -63,7 +63,7 @@ public class IntentViewMessageHandler extends UiMessageHandler {
63 }; 63 };
64 64
65 @Override 65 @Override
66 - protected Collection<RequestHandler> getHandlers() { 66 + protected Collection<RequestHandler> createRequestHandlers() {
67 return ImmutableSet.of(new IntentDataRequest()); 67 return ImmutableSet.of(new IntentDataRequest());
68 } 68 }
69 69
......
...@@ -59,7 +59,7 @@ public class LinkViewMessageHandler extends UiMessageHandler { ...@@ -59,7 +59,7 @@ public class LinkViewMessageHandler extends UiMessageHandler {
59 private static final String ICON_ID_OFFLINE = "inactive"; 59 private static final String ICON_ID_OFFLINE = "inactive";
60 60
61 @Override 61 @Override
62 - protected Collection<RequestHandler> getHandlers() { 62 + protected Collection<RequestHandler> createRequestHandlers() {
63 return ImmutableSet.of(new LinkDataRequest()); 63 return ImmutableSet.of(new LinkDataRequest());
64 } 64 }
65 65
......
...@@ -54,7 +54,7 @@ public class PortViewMessageHandler extends UiMessageHandler { ...@@ -54,7 +54,7 @@ public class PortViewMessageHandler extends UiMessageHandler {
54 }; 54 };
55 55
56 @Override 56 @Override
57 - protected Collection<RequestHandler> getHandlers() { 57 + protected Collection<RequestHandler> createRequestHandlers() {
58 return ImmutableSet.of(new PortDataRequest()); 58 return ImmutableSet.of(new PortDataRequest());
59 } 59 }
60 60
......
...@@ -167,7 +167,7 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase { ...@@ -167,7 +167,7 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase {
167 } 167 }
168 168
169 @Override 169 @Override
170 - protected Collection<RequestHandler> getHandlers() { 170 + protected Collection<RequestHandler> createRequestHandlers() {
171 return ImmutableSet.of( 171 return ImmutableSet.of(
172 new TopoStart(), 172 new TopoStart(),
173 new TopoStop(), 173 new TopoStop(),
...@@ -254,8 +254,8 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase { ...@@ -254,8 +254,8 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase {
254 254
255 @Override 255 @Override
256 public void process(long sid, ObjectNode payload) { 256 public void process(long sid, ObjectNode payload) {
257 - ObjectNode root = mapper.createObjectNode(); 257 + ObjectNode root = objectNode();
258 - ArrayNode names = mapper.createArrayNode(); 258 + ArrayNode names = arrayNode();
259 get(SpriteService.class).getNames().forEach(names::add); 259 get(SpriteService.class).getNames().forEach(names::add);
260 root.set("names", names); 260 root.set("names", names);
261 sendMessage("spriteListResponse", sid, root); 261 sendMessage("spriteListResponse", sid, root);
...@@ -270,7 +270,7 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase { ...@@ -270,7 +270,7 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase {
270 @Override 270 @Override
271 public void process(long sid, ObjectNode payload) { 271 public void process(long sid, ObjectNode payload) {
272 String name = string(payload, "name"); 272 String name = string(payload, "name");
273 - ObjectNode root = mapper.createObjectNode(); 273 + ObjectNode root = objectNode();
274 root.set("data", get(SpriteService.class).get(name)); 274 root.set("data", get(SpriteService.class).get(name));
275 sendMessage("spriteDataResponse", sid, root); 275 sendMessage("spriteDataResponse", sid, root);
276 } 276 }
......
...@@ -171,7 +171,7 @@ public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler { ...@@ -171,7 +171,7 @@ public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler {
171 171
172 // Produces JSON structure from annotations. 172 // Produces JSON structure from annotations.
173 private JsonNode props(Annotations annotations) { 173 private JsonNode props(Annotations annotations) {
174 - ObjectNode props = mapper.createObjectNode(); 174 + ObjectNode props = objectNode();
175 if (annotations != null) { 175 if (annotations != null) {
176 for (String key : annotations.keys()) { 176 for (String key : annotations.keys()) {
177 props.put(key, annotations.value(key)); 177 props.put(key, annotations.value(key));
...@@ -197,7 +197,7 @@ public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler { ...@@ -197,7 +197,7 @@ public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler {
197 197
198 // Produces a log message event bound to the client. 198 // Produces a log message event bound to the client.
199 private ObjectNode message(String severity, long id, String message) { 199 private ObjectNode message(String severity, long id, String message) {
200 - ObjectNode payload = mapper.createObjectNode() 200 + ObjectNode payload = objectNode()
201 .put("severity", severity) 201 .put("severity", severity)
202 .put("message", message); 202 .put("message", message);
203 203
...@@ -266,14 +266,14 @@ public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler { ...@@ -266,14 +266,14 @@ public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler {
266 protected ObjectNode instanceMessage(ClusterEvent event, String messageType) { 266 protected ObjectNode instanceMessage(ClusterEvent event, String messageType) {
267 ControllerNode node = event.subject(); 267 ControllerNode node = event.subject();
268 int switchCount = mastershipService.getDevicesOf(node.id()).size(); 268 int switchCount = mastershipService.getDevicesOf(node.id()).size();
269 - ObjectNode payload = mapper.createObjectNode() 269 + ObjectNode payload = objectNode()
270 .put("id", node.id().toString()) 270 .put("id", node.id().toString())
271 .put("ip", node.ip().toString()) 271 .put("ip", node.ip().toString())
272 .put("online", clusterService.getState(node.id()) == ACTIVE) 272 .put("online", clusterService.getState(node.id()) == ACTIVE)
273 .put("uiAttached", node.equals(clusterService.getLocalNode())) 273 .put("uiAttached", node.equals(clusterService.getLocalNode()))
274 .put("switches", switchCount); 274 .put("switches", switchCount);
275 275
276 - ArrayNode labels = mapper.createArrayNode(); 276 + ArrayNode labels = arrayNode();
277 labels.add(node.id().toString()); 277 labels.add(node.id().toString());
278 labels.add(node.ip().toString()); 278 labels.add(node.ip().toString());
279 279
...@@ -291,7 +291,7 @@ public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler { ...@@ -291,7 +291,7 @@ public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler {
291 // Produces a device event message to the client. 291 // Produces a device event message to the client.
292 protected ObjectNode deviceMessage(DeviceEvent event) { 292 protected ObjectNode deviceMessage(DeviceEvent event) {
293 Device device = event.subject(); 293 Device device = event.subject();
294 - ObjectNode payload = mapper.createObjectNode() 294 + ObjectNode payload = objectNode()
295 .put("id", device.id().toString()) 295 .put("id", device.id().toString())
296 .put("type", device.type().toString().toLowerCase()) 296 .put("type", device.type().toString().toLowerCase())
297 .put("online", deviceService.isAvailable(device.id())) 297 .put("online", deviceService.isAvailable(device.id()))
...@@ -299,7 +299,7 @@ public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler { ...@@ -299,7 +299,7 @@ public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler {
299 299
300 // Generate labels: id, chassis id, no-label, optional-name 300 // Generate labels: id, chassis id, no-label, optional-name
301 String name = device.annotations().value(AnnotationKeys.NAME); 301 String name = device.annotations().value(AnnotationKeys.NAME);
302 - ArrayNode labels = mapper.createArrayNode(); 302 + ArrayNode labels = arrayNode();
303 labels.add(""); 303 labels.add("");
304 labels.add(isNullOrEmpty(name) ? device.id().toString() : name); 304 labels.add(isNullOrEmpty(name) ? device.id().toString() : name);
305 labels.add(device.id().toString()); 305 labels.add(device.id().toString());
...@@ -318,7 +318,7 @@ public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler { ...@@ -318,7 +318,7 @@ public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler {
318 // Produces a link event message to the client. 318 // Produces a link event message to the client.
319 protected ObjectNode linkMessage(LinkEvent event) { 319 protected ObjectNode linkMessage(LinkEvent event) {
320 Link link = event.subject(); 320 Link link = event.subject();
321 - ObjectNode payload = mapper.createObjectNode() 321 + ObjectNode payload = objectNode()
322 .put("id", compactLinkString(link)) 322 .put("id", compactLinkString(link))
323 .put("type", link.type().toString().toLowerCase()) 323 .put("type", link.type().toString().toLowerCase())
324 .put("online", link.state() == Link.State.ACTIVE) 324 .put("online", link.state() == Link.State.ACTIVE)
...@@ -336,13 +336,13 @@ public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler { ...@@ -336,13 +336,13 @@ public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler {
336 protected ObjectNode hostMessage(HostEvent event) { 336 protected ObjectNode hostMessage(HostEvent event) {
337 Host host = event.subject(); 337 Host host = event.subject();
338 String hostType = host.annotations().value(AnnotationKeys.TYPE); 338 String hostType = host.annotations().value(AnnotationKeys.TYPE);
339 - ObjectNode payload = mapper.createObjectNode() 339 + ObjectNode payload = objectNode()
340 .put("id", host.id().toString()) 340 .put("id", host.id().toString())
341 .put("type", isNullOrEmpty(hostType) ? "endstation" : hostType) 341 .put("type", isNullOrEmpty(hostType) ? "endstation" : hostType)
342 .put("ingress", compactLinkString(edgeLink(host, true))) 342 .put("ingress", compactLinkString(edgeLink(host, true)))
343 .put("egress", compactLinkString(edgeLink(host, false))); 343 .put("egress", compactLinkString(edgeLink(host, false)));
344 - payload.set("cp", hostConnect(mapper, host.location())); 344 + payload.set("cp", hostConnect(host.location()));
345 - payload.set("labels", labels(mapper, ip(host.ipAddresses()), 345 + payload.set("labels", labels(ip(host.ipAddresses()),
346 host.mac().toString())); 346 host.mac().toString()));
347 payload.set("props", props(host.annotations())); 347 payload.set("props", props(host.annotations()));
348 addGeoLocation(host, payload); 348 addGeoLocation(host, payload);
...@@ -354,15 +354,15 @@ public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler { ...@@ -354,15 +354,15 @@ public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler {
354 } 354 }
355 355
356 // Encodes the specified host location into a JSON object. 356 // Encodes the specified host location into a JSON object.
357 - private ObjectNode hostConnect(ObjectMapper mapper, HostLocation location) { 357 + private ObjectNode hostConnect(HostLocation location) {
358 - return mapper.createObjectNode() 358 + return objectNode()
359 .put("device", location.deviceId().toString()) 359 .put("device", location.deviceId().toString())
360 .put("port", location.port().toLong()); 360 .put("port", location.port().toLong());
361 } 361 }
362 362
363 // Encodes the specified list of labels a JSON array. 363 // Encodes the specified list of labels a JSON array.
364 - private ArrayNode labels(ObjectMapper mapper, String... labels) { 364 + private ArrayNode labels(String... labels) {
365 - ArrayNode json = mapper.createArrayNode(); 365 + ArrayNode json = arrayNode();
366 for (String label : labels) { 366 for (String label : labels) {
367 json.add(label); 367 json.add(label);
368 } 368 }
...@@ -402,7 +402,7 @@ public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler { ...@@ -402,7 +402,7 @@ public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler {
402 if (slat != null && slng != null && !slat.isEmpty() && !slng.isEmpty()) { 402 if (slat != null && slng != null && !slat.isEmpty() && !slng.isEmpty()) {
403 double lat = Double.parseDouble(slat); 403 double lat = Double.parseDouble(slat);
404 double lng = Double.parseDouble(slng); 404 double lng = Double.parseDouble(slng);
405 - ObjectNode loc = mapper.createObjectNode() 405 + ObjectNode loc = objectNode()
406 .put("type", "latlng").put("lat", lat).put("lng", lng); 406 .put("type", "latlng").put("lat", lat).put("lng", lng);
407 payload.set("location", loc); 407 payload.set("location", loc);
408 } 408 }
...@@ -531,22 +531,22 @@ public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler { ...@@ -531,22 +531,22 @@ public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler {
531 531
532 // Produces JSON message to trigger traffic overview visualization 532 // Produces JSON message to trigger traffic overview visualization
533 protected ObjectNode trafficSummaryMessage() { 533 protected ObjectNode trafficSummaryMessage() {
534 - ObjectNode payload = mapper.createObjectNode(); 534 + ObjectNode payload = objectNode();
535 - ArrayNode paths = mapper.createArrayNode(); 535 + ArrayNode paths = arrayNode();
536 payload.set("paths", paths); 536 payload.set("paths", paths);
537 537
538 - ObjectNode pathNodeN = mapper.createObjectNode(); 538 + ObjectNode pathNodeN = objectNode();
539 - ArrayNode linksNodeN = mapper.createArrayNode(); 539 + ArrayNode linksNodeN = arrayNode();
540 - ArrayNode labelsN = mapper.createArrayNode(); 540 + ArrayNode labelsN = arrayNode();
541 541
542 pathNodeN.put("class", "plain").put("traffic", false); 542 pathNodeN.put("class", "plain").put("traffic", false);
543 pathNodeN.set("links", linksNodeN); 543 pathNodeN.set("links", linksNodeN);
544 pathNodeN.set("labels", labelsN); 544 pathNodeN.set("labels", labelsN);
545 paths.add(pathNodeN); 545 paths.add(pathNodeN);
546 546
547 - ObjectNode pathNodeT = mapper.createObjectNode(); 547 + ObjectNode pathNodeT = objectNode();
548 - ArrayNode linksNodeT = mapper.createArrayNode(); 548 + ArrayNode linksNodeT = arrayNode();
549 - ArrayNode labelsT = mapper.createArrayNode(); 549 + ArrayNode labelsT = arrayNode();
550 550
551 pathNodeT.put("class", "secondary").put("traffic", true); 551 pathNodeT.put("class", "secondary").put("traffic", true);
552 pathNodeT.set("links", linksNodeT); 552 pathNodeT.set("links", linksNodeT);
...@@ -581,8 +581,8 @@ public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler { ...@@ -581,8 +581,8 @@ public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler {
581 581
582 // Produces JSON message to trigger flow overview visualization 582 // Produces JSON message to trigger flow overview visualization
583 protected ObjectNode flowSummaryMessage(Set<Device> devices) { 583 protected ObjectNode flowSummaryMessage(Set<Device> devices) {
584 - ObjectNode payload = mapper.createObjectNode(); 584 + ObjectNode payload = objectNode();
585 - ArrayNode paths = mapper.createArrayNode(); 585 + ArrayNode paths = arrayNode();
586 payload.set("paths", paths); 586 payload.set("paths", paths);
587 587
588 for (Device device : devices) { 588 for (Device device : devices) {
...@@ -595,9 +595,9 @@ public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler { ...@@ -595,9 +595,9 @@ public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler {
595 } 595 }
596 596
597 private void addLinkFlows(Link link, ArrayNode paths, Integer count) { 597 private void addLinkFlows(Link link, ArrayNode paths, Integer count) {
598 - ObjectNode pathNode = mapper.createObjectNode(); 598 + ObjectNode pathNode = objectNode();
599 - ArrayNode linksNode = mapper.createArrayNode(); 599 + ArrayNode linksNode = arrayNode();
600 - ArrayNode labels = mapper.createArrayNode(); 600 + ArrayNode labels = arrayNode();
601 boolean noFlows = count == null || count == 0; 601 boolean noFlows = count == null || count == 0;
602 pathNode.put("class", noFlows ? "secondary" : "primary"); 602 pathNode.put("class", noFlows ? "secondary" : "primary");
603 pathNode.put("traffic", false); 603 pathNode.put("traffic", false);
...@@ -610,8 +610,8 @@ public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler { ...@@ -610,8 +610,8 @@ public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler {
610 610
611 // Produces JSON message to trigger traffic visualization 611 // Produces JSON message to trigger traffic visualization
612 protected ObjectNode trafficMessage(TrafficClass... trafficClasses) { 612 protected ObjectNode trafficMessage(TrafficClass... trafficClasses) {
613 - ObjectNode payload = mapper.createObjectNode(); 613 + ObjectNode payload = objectNode();
614 - ArrayNode paths = mapper.createArrayNode(); 614 + ArrayNode paths = arrayNode();
615 payload.set("paths", paths); 615 payload.set("paths", paths);
616 616
617 // Classify links based on their traffic traffic first... 617 // Classify links based on their traffic traffic first...
...@@ -624,10 +624,10 @@ public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler { ...@@ -624,10 +624,10 @@ public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler {
624 String tc = (biLink.classes() + (hasTraffic ? " animated" : "")).trim(); 624 String tc = (biLink.classes() + (hasTraffic ? " animated" : "")).trim();
625 ObjectNode pathNode = pathNodes.get(tc); 625 ObjectNode pathNode = pathNodes.get(tc);
626 if (pathNode == null) { 626 if (pathNode == null) {
627 - pathNode = mapper.createObjectNode() 627 + pathNode = objectNode()
628 .put("class", tc).put("traffic", hasTraffic); 628 .put("class", tc).put("traffic", hasTraffic);
629 - pathNode.set("links", mapper.createArrayNode()); 629 + pathNode.set("links", arrayNode());
630 - pathNode.set("labels", mapper.createArrayNode()); 630 + pathNode.set("labels", arrayNode());
631 pathNodes.put(tc, pathNode); 631 pathNodes.put(tc, pathNode);
632 paths.add(pathNode); 632 paths.add(pathNode);
633 } 633 }
...@@ -701,11 +701,11 @@ public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler { ...@@ -701,11 +701,11 @@ public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler {
701 // connectivity intent 701 // connectivity intent
702 protected void addPathTraffic(ArrayNode paths, String type, String trafficType, 702 protected void addPathTraffic(ArrayNode paths, String type, String trafficType,
703 Iterable<Link> links) { 703 Iterable<Link> links) {
704 - ObjectNode pathNode = mapper.createObjectNode(); 704 + ObjectNode pathNode = objectNode();
705 - ArrayNode linksNode = mapper.createArrayNode(); 705 + ArrayNode linksNode = arrayNode();
706 706
707 if (links != null) { 707 if (links != null) {
708 - ArrayNode labels = mapper.createArrayNode(); 708 + ArrayNode labels = arrayNode();
709 boolean hasTraffic = false; 709 boolean hasTraffic = false;
710 for (Link link : links) { 710 for (Link link : links) {
711 if (isInfrastructureEgress(link)) { 711 if (isInfrastructureEgress(link)) {
...@@ -767,10 +767,10 @@ public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler { ...@@ -767,10 +767,10 @@ public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler {
767 // Produces JSON property details. 767 // Produces JSON property details.
768 private ObjectNode json(String id, String type, Prop... props) { 768 private ObjectNode json(String id, String type, Prop... props) {
769 ObjectMapper mapper = new ObjectMapper(); 769 ObjectMapper mapper = new ObjectMapper();
770 - ObjectNode result = mapper.createObjectNode() 770 + ObjectNode result = objectNode()
771 .put("id", id).put("type", type); 771 .put("id", id).put("type", type);
772 - ObjectNode pnode = mapper.createObjectNode(); 772 + ObjectNode pnode = objectNode();
773 - ArrayNode porder = mapper.createArrayNode(); 773 + ArrayNode porder = arrayNode();
774 for (Prop p : props) { 774 for (Prop p : props) {
775 porder.add(p.key); 775 porder.add(p.key);
776 pnode.put(p.key, p.value); 776 pnode.put(p.key, p.value);
......
...@@ -41,7 +41,7 @@ public class UiWebSocket ...@@ -41,7 +41,7 @@ public class UiWebSocket
41 41
42 private static final Logger log = LoggerFactory.getLogger(UiWebSocket.class); 42 private static final Logger log = LoggerFactory.getLogger(UiWebSocket.class);
43 43
44 - private static final long MAX_AGE_MS = 15000; 44 + private static final long MAX_AGE_MS = 15_000;
45 45
46 private static final byte PING = 0x9; 46 private static final byte PING = 0x9;
47 private static final byte PONG = 0xA; 47 private static final byte PONG = 0xA;
...@@ -83,8 +83,10 @@ public class UiWebSocket ...@@ -83,8 +83,10 @@ public class UiWebSocket
83 * @return true if idle or closed 83 * @return true if idle or closed
84 */ 84 */
85 synchronized boolean isIdle() { 85 synchronized boolean isIdle() {
86 - boolean idle = (System.currentTimeMillis() - lastActive) > MAX_AGE_MS; 86 + long quietFor = System.currentTimeMillis() - lastActive;
87 + boolean idle = quietFor > MAX_AGE_MS;
87 if (idle || (connection != null && !connection.isOpen())) { 88 if (idle || (connection != null && !connection.isOpen())) {
89 + log.debug("IDLE (or closed) websocket [{} ms]", quietFor);
88 return true; 90 return true;
89 } else if (connection != null) { 91 } else if (connection != null) {
90 try { 92 try {
...@@ -108,7 +110,8 @@ public class UiWebSocket ...@@ -108,7 +110,8 @@ public class UiWebSocket
108 @Override 110 @Override
109 public synchronized void onClose(int closeCode, String message) { 111 public synchronized void onClose(int closeCode, String message) {
110 destroyHandlers(); 112 destroyHandlers();
111 - log.info("GUI client disconnected"); 113 + log.info("GUI client disconnected [close-code={}, message={}]",
114 + closeCode, message);
112 } 115 }
113 116
114 @Override 117 @Override
......
...@@ -50,6 +50,8 @@ import java.util.ArrayList; ...@@ -50,6 +50,8 @@ import java.util.ArrayList;
50 import java.util.Collections; 50 import java.util.Collections;
51 import java.util.Comparator; 51 import java.util.Comparator;
52 import java.util.List; 52 import java.util.List;
53 +import java.util.Timer;
54 +import java.util.TimerTask;
53 55
54 import static org.onosproject.cluster.ClusterEvent.Type.INSTANCE_ADDED; 56 import static org.onosproject.cluster.ClusterEvent.Type.INSTANCE_ADDED;
55 import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_ADDED; 57 import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_ADDED;
...@@ -67,6 +69,9 @@ import static org.onosproject.ui.impl.topo.TopoUiEvent.Type.SUMMARY_UPDATE; ...@@ -67,6 +69,9 @@ import static org.onosproject.ui.impl.topo.TopoUiEvent.Type.SUMMARY_UPDATE;
67 @Service 69 @Service
68 public class TopoUiModelManager implements TopoUiModelService { 70 public class TopoUiModelManager implements TopoUiModelService {
69 71
72 + // TODO: put back to 30,000 ms for production
73 + private static final long SUMMARY_PERIOD = 15_000;
74 +
70 private final Logger log = LoggerFactory.getLogger(getClass()); 75 private final Logger log = LoggerFactory.getLogger(getClass());
71 76
72 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 77 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
...@@ -105,6 +110,11 @@ public class TopoUiModelManager implements TopoUiModelService { ...@@ -105,6 +110,11 @@ public class TopoUiModelManager implements TopoUiModelService {
105 private final TopoMessageFactory messageFactory = new TopoMessageFactory(); 110 private final TopoMessageFactory messageFactory = new TopoMessageFactory();
106 private final MetaDb metaDb = new MetaDb(); 111 private final MetaDb metaDb = new MetaDb();
107 112
113 + private final Timer timer = new Timer("topology-view");
114 +
115 + private TimerTask summaryTask = null;
116 + private boolean summaryRunning = false;
117 +
108 118
109 @Activate 119 @Activate
110 public void activate() { 120 public void activate() {
...@@ -135,7 +145,8 @@ public class TopoUiModelManager implements TopoUiModelService { ...@@ -135,7 +145,8 @@ public class TopoUiModelManager implements TopoUiModelService {
135 // causes the listener (for an AltTopoViewMessageHandler instance) to 145 // causes the listener (for an AltTopoViewMessageHandler instance) to
136 // be removed. 146 // be removed.
137 // ==== Somehow need to tie this in to the GUI-disconnected event. 147 // ==== Somehow need to tie this in to the GUI-disconnected event.
138 - 148 + // This probably requires client-generated heartbeat messages to
149 + // Keep the connection alive.
139 150
140 151
141 @Override 152 @Override
...@@ -159,16 +170,32 @@ public class TopoUiModelManager implements TopoUiModelService { ...@@ -159,16 +170,32 @@ public class TopoUiModelManager implements TopoUiModelService {
159 } 170 }
160 171
161 @Override 172 @Override
162 - public void startSummaryMonitoring() { 173 + public synchronized void startSummaryMonitoring() {
163 - // TODO: set up periodic monitoring task 174 + // first, cancel previous task if not canceled already
164 - // send a summary now, and periodically... 175 + stopSummaryMonitoring();
165 - post(new TopoUiEvent(SUMMARY_UPDATE, null)); 176 +
177 + // create and start a summary task, to execute with no delay, and
178 + // every SUMMARY_PERIOD milliseconds thereafter.
179 + summaryTask = new TimerTask() {
180 + @Override
181 + public void run() {
182 + if (summaryRunning) {
183 + post(new TopoUiEvent(SUMMARY_UPDATE, null));
184 + }
185 + }
186 + };
187 +
188 + timer.schedule(summaryTask, 0, SUMMARY_PERIOD);
189 + summaryRunning = true;
166 } 190 }
167 191
168 @Override 192 @Override
169 - public void stopSummaryMonitoring() { 193 + public synchronized void stopSummaryMonitoring() {
170 - // TODO: cancel monitoring task 194 + if (summaryTask != null) {
171 - 195 + summaryTask.cancel();
196 + summaryTask = null;
197 + }
198 + summaryRunning = false;
172 } 199 }
173 200
174 @Override 201 @Override
......