Simon Hunt

GUI -- Beginnings of structure for topology Overlay API.

- Re-implemented RequestSummary / ShowSummary in Alt implementation.

Change-Id: Idb86c7bf3ede8f8815abcb488bbf9b0a7041ef79
...@@ -56,6 +56,7 @@ public abstract class RequestHandler { ...@@ -56,6 +56,7 @@ public abstract class RequestHandler {
56 * @param sid message sequence identifier 56 * @param sid message sequence identifier
57 * @param payload request message payload 57 * @param payload request message payload
58 */ 58 */
59 + // TODO: remove sid from signature
59 public abstract void process(long sid, ObjectNode payload); 60 public abstract void process(long sid, ObjectNode payload);
60 61
61 62
......
...@@ -18,6 +18,8 @@ package org.onosproject.ui; ...@@ -18,6 +18,8 @@ package org.onosproject.ui;
18 import com.fasterxml.jackson.databind.ObjectMapper; 18 import com.fasterxml.jackson.databind.ObjectMapper;
19 import com.fasterxml.jackson.databind.node.ObjectNode; 19 import com.fasterxml.jackson.databind.node.ObjectNode;
20 import org.onlab.osgi.ServiceDirectory; 20 import org.onlab.osgi.ServiceDirectory;
21 +import org.slf4j.Logger;
22 +import org.slf4j.LoggerFactory;
21 23
22 import java.util.Collection; 24 import java.util.Collection;
23 import java.util.Collections; 25 import java.util.Collections;
...@@ -46,6 +48,7 @@ import static com.google.common.base.Preconditions.checkNotNull; ...@@ -46,6 +48,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
46 */ 48 */
47 public abstract class UiMessageHandler { 49 public abstract class UiMessageHandler {
48 50
51 + private final Logger log = LoggerFactory.getLogger(getClass());
49 private final Map<String, RequestHandler> handlerMap = new HashMap<>(); 52 private final Map<String, RequestHandler> handlerMap = new HashMap<>();
50 53
51 private UiConnection connection; 54 private UiConnection connection;
...@@ -56,7 +59,6 @@ public abstract class UiMessageHandler { ...@@ -56,7 +59,6 @@ public abstract class UiMessageHandler {
56 */ 59 */
57 protected final ObjectMapper mapper = new ObjectMapper(); 60 protected final ObjectMapper mapper = new ObjectMapper();
58 61
59 -
60 /** 62 /**
61 * Subclasses must return the collection of handlers for the 63 * Subclasses must return the collection of handlers for the
62 * message types they handle. 64 * message types they handle.
...@@ -82,6 +84,7 @@ public abstract class UiMessageHandler { ...@@ -82,6 +84,7 @@ public abstract class UiMessageHandler {
82 */ 84 */
83 public void process(ObjectNode message) { 85 public void process(ObjectNode message) {
84 String type = JsonUtils.eventType(message); 86 String type = JsonUtils.eventType(message);
87 + // TODO: remove sid
85 long sid = JsonUtils.sid(message); 88 long sid = JsonUtils.sid(message);
86 ObjectNode payload = JsonUtils.payload(message); 89 ObjectNode payload = JsonUtils.payload(message);
87 exec(type, sid, payload); 90 exec(type, sid, payload);
...@@ -94,9 +97,11 @@ public abstract class UiMessageHandler { ...@@ -94,9 +97,11 @@ public abstract class UiMessageHandler {
94 * @param sid sequence identifier 97 * @param sid sequence identifier
95 * @param payload message payload 98 * @param payload message payload
96 */ 99 */
100 + // TODO: remove sid from signature
97 void exec(String eventType, long sid, ObjectNode payload) { 101 void exec(String eventType, long sid, ObjectNode payload) {
98 RequestHandler handler = handlerMap.get(eventType); 102 RequestHandler handler = handlerMap.get(eventType);
99 if (handler != null) { 103 if (handler != null) {
104 + log.debug("process {} event...", eventType);
100 handler.process(sid, payload); 105 handler.process(sid, payload);
101 } 106 }
102 } 107 }
......
...@@ -19,29 +19,40 @@ package org.onosproject.ui.impl; ...@@ -19,29 +19,40 @@ package org.onosproject.ui.impl;
19 19
20 import com.fasterxml.jackson.databind.node.ObjectNode; 20 import com.fasterxml.jackson.databind.node.ObjectNode;
21 import com.google.common.collect.ImmutableSet; 21 import com.google.common.collect.ImmutableSet;
22 +import com.google.common.collect.Maps;
22 import org.onlab.osgi.ServiceDirectory; 23 import org.onlab.osgi.ServiceDirectory;
23 import org.onosproject.core.CoreService; 24 import org.onosproject.core.CoreService;
25 +import org.onosproject.ui.JsonUtils;
24 import org.onosproject.ui.RequestHandler; 26 import org.onosproject.ui.RequestHandler;
25 import org.onosproject.ui.UiConnection; 27 import org.onosproject.ui.UiConnection;
26 import org.onosproject.ui.UiMessageHandler; 28 import org.onosproject.ui.UiMessageHandler;
29 +import org.onosproject.ui.impl.topo.OverlayService;
30 +import org.onosproject.ui.impl.topo.SummaryData;
27 import org.onosproject.ui.impl.topo.TopoUiEvent; 31 import org.onosproject.ui.impl.topo.TopoUiEvent;
28 import org.onosproject.ui.impl.topo.TopoUiListener; 32 import org.onosproject.ui.impl.topo.TopoUiListener;
29 import org.onosproject.ui.impl.topo.TopoUiModelService; 33 import org.onosproject.ui.impl.topo.TopoUiModelService;
34 +import org.onosproject.ui.impl.topo.overlay.AbstractSummaryGenerator;
35 +import org.onosproject.ui.impl.topo.overlay.SummaryGenerator;
30 import org.slf4j.Logger; 36 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory; 37 import org.slf4j.LoggerFactory;
32 38
33 import java.util.Collection; 39 import java.util.Collection;
40 +import java.util.HashMap;
41 +import java.util.Map;
34 42
35 import static com.google.common.base.Preconditions.checkNotNull; 43 import static com.google.common.base.Preconditions.checkNotNull;
44 +import static org.onosproject.ui.impl.topo.TopoUiEvent.Type.SUMMARY_UPDATE;
36 45
37 /** 46 /**
38 * Facility for handling inbound messages from the topology view, and 47 * Facility for handling inbound messages from the topology view, and
39 * generating outbound messages for the same. 48 * generating outbound messages for the same.
40 */ 49 */
41 -public class AltTopoViewMessageHandler extends UiMessageHandler { 50 +public class AltTopoViewMessageHandler extends UiMessageHandler
51 + implements OverlayService {
42 52
43 private static final String TOPO_START = "topoStart"; 53 private static final String TOPO_START = "topoStart";
44 private static final String TOPO_STOP = "topoStop"; 54 private static final String TOPO_STOP = "topoStop";
55 + private static final String REQ_SUMMARY = "requestSummary";
45 56
46 private final Logger log = LoggerFactory.getLogger(getClass()); 57 private final Logger log = LoggerFactory.getLogger(getClass());
47 58
...@@ -50,6 +61,9 @@ public class AltTopoViewMessageHandler extends UiMessageHandler { ...@@ -50,6 +61,9 @@ public class AltTopoViewMessageHandler extends UiMessageHandler {
50 61
51 private TopoUiListener modelListener; 62 private TopoUiListener modelListener;
52 private String version; 63 private String version;
64 + private SummaryGenerator defaultSummaryGenerator;
65 + private SummaryGenerator currentSummaryGenerator;
66 +
53 67
54 private boolean topoActive = false; 68 private boolean topoActive = false;
55 69
...@@ -58,9 +72,12 @@ public class AltTopoViewMessageHandler extends UiMessageHandler { ...@@ -58,9 +72,12 @@ public class AltTopoViewMessageHandler extends UiMessageHandler {
58 super.init(connection, directory); 72 super.init(connection, directory);
59 this.directory = checkNotNull(directory, "Directory cannot be null"); 73 this.directory = checkNotNull(directory, "Directory cannot be null");
60 modelService = directory.get(TopoUiModelService.class); 74 modelService = directory.get(TopoUiModelService.class);
75 + defaultSummaryGenerator = new DefSummaryGenerator("node", "ONOS Summary");
61 76
77 + bindEventHandlers();
62 modelListener = new ModelListener(); 78 modelListener = new ModelListener();
63 version = getVersion(); 79 version = getVersion();
80 + currentSummaryGenerator = defaultSummaryGenerator;
64 } 81 }
65 82
66 83
...@@ -74,11 +91,33 @@ public class AltTopoViewMessageHandler extends UiMessageHandler { ...@@ -74,11 +91,33 @@ public class AltTopoViewMessageHandler extends UiMessageHandler {
74 protected Collection<RequestHandler> getHandlers() { 91 protected Collection<RequestHandler> getHandlers() {
75 return ImmutableSet.of( 92 return ImmutableSet.of(
76 new TopoStart(), 93 new TopoStart(),
77 - new TopoStop() 94 + new TopoStop(),
95 + new ReqSummary()
96 + // TODO: add more handlers here.....
78 ); 97 );
79 } 98 }
80 99
81 // ===================================================================== 100 // =====================================================================
101 + // Overlay Service
102 + // TODO: figure out how we are going to switch overlays in and out...
103 +
104 + private final Map<String, SummaryGenerator> summGenCache = Maps.newHashMap();
105 +
106 + @Override
107 + public void addSummaryGenerator(String overlayId, SummaryGenerator generator) {
108 + log.info("Adding custom Summary Generator for overlay [{}]", overlayId);
109 + summGenCache.put(overlayId, generator);
110 + }
111 +
112 + @Override
113 + public void removeSummaryGenerator(String overlayId) {
114 + summGenCache.remove(overlayId);
115 + log.info("Custom Summary Generator for overlay [{}] removed", overlayId);
116 + }
117 +
118 +
119 +
120 + // =====================================================================
82 // Request Handlers for (topo view) events from the UI... 121 // Request Handlers for (topo view) events from the UI...
83 122
84 private final class TopoStart extends RequestHandler { 123 private final class TopoStart extends RequestHandler {
...@@ -91,7 +130,6 @@ public class AltTopoViewMessageHandler extends UiMessageHandler { ...@@ -91,7 +130,6 @@ public class AltTopoViewMessageHandler extends UiMessageHandler {
91 topoActive = true; 130 topoActive = true;
92 modelService.addListener(modelListener); 131 modelService.addListener(modelListener);
93 sendMessages(modelService.getInitialState()); 132 sendMessages(modelService.getInitialState());
94 - log.debug(TOPO_START);
95 } 133 }
96 } 134 }
97 135
...@@ -104,7 +142,43 @@ public class AltTopoViewMessageHandler extends UiMessageHandler { ...@@ -104,7 +142,43 @@ public class AltTopoViewMessageHandler extends UiMessageHandler {
104 public void process(long sid, ObjectNode payload) { 142 public void process(long sid, ObjectNode payload) {
105 topoActive = false; 143 topoActive = false;
106 modelService.removeListener(modelListener); 144 modelService.removeListener(modelListener);
107 - log.debug(TOPO_STOP); 145 + }
146 + }
147 +
148 + private final class ReqSummary extends RequestHandler {
149 + private ReqSummary() {
150 + super(REQ_SUMMARY);
151 + }
152 +
153 + @Override
154 + public void process(long sid, ObjectNode payload) {
155 + modelService.startSummaryMonitoring();
156 + // NOTE: showSummary messages forwarded through the model listener
157 + }
158 + }
159 +
160 + // =====================================================================
161 +
162 + private final class DefSummaryGenerator extends AbstractSummaryGenerator {
163 + public DefSummaryGenerator(String iconId, String title) {
164 + super(iconId, title);
165 + }
166 +
167 + @Override
168 + public ObjectNode generateSummary() {
169 + SummaryData data = modelService.getSummaryData();
170 + iconId("node");
171 + title("ONOS Summary");
172 + clearProps();
173 + prop("Devices", format(data.deviceCount()));
174 + prop("Links", format(data.linkCount()));
175 + prop("Hosts", format(data.hostCount()));
176 + prop("Topology SCCs", format(data.clusterCount()));
177 + separator();
178 + prop("Intents", format(data.intentCount()));
179 + prop("Flows", format(data.flowRuleCount()));
180 + prop("Version", version);
181 + return buildObjectNode();
108 } 182 }
109 } 183 }
110 184
...@@ -120,6 +194,15 @@ public class AltTopoViewMessageHandler extends UiMessageHandler { ...@@ -120,6 +194,15 @@ public class AltTopoViewMessageHandler extends UiMessageHandler {
120 } 194 }
121 } 195 }
122 196
197 + private void sendMessages(ObjectNode message) {
198 + if (topoActive) {
199 + UiConnection connection = connection();
200 + if (connection != null) {
201 + connection.sendMessage(message);
202 + }
203 + }
204 + }
205 +
123 // ===================================================================== 206 // =====================================================================
124 // Our listener for model events so we can push changes out to the UI... 207 // Our listener for model events so we can push changes out to the UI...
125 208
...@@ -127,7 +210,46 @@ public class AltTopoViewMessageHandler extends UiMessageHandler { ...@@ -127,7 +210,46 @@ public class AltTopoViewMessageHandler extends UiMessageHandler {
127 @Override 210 @Override
128 public void event(TopoUiEvent event) { 211 public void event(TopoUiEvent event) {
129 log.debug("Handle Event: {}", event); 212 log.debug("Handle Event: {}", event);
130 - // TODO: handle event 213 + ModelEventHandler handler = eventHandlerBinding.get(event.type());
214 +
215 + // any handlers not bound explicitly are assumed to be pass-thru...
216 + if (handler == null) {
217 + handler = passThruHandler;
218 + }
219 + handler.handleEvent(event);
220 + }
131 } 221 }
222 +
223 +
224 + // =====================================================================
225 + // Model Event Handler definitions and bindings...
226 +
227 + private interface ModelEventHandler {
228 + void handleEvent(TopoUiEvent event);
229 + }
230 +
231 + private ModelEventHandler passThruHandler = event -> {
232 + // simply forward the event message as is
233 + ObjectNode message = event.subject();
234 + if (message != null) {
235 + sendMessages(event.subject());
132 } 236 }
237 + };
238 +
239 + private ModelEventHandler summaryHandler = event -> {
240 + // use the currently selected summary generator to create the body..
241 + ObjectNode payload = currentSummaryGenerator.generateSummary();
242 + sendMessages(JsonUtils.envelope("showSummary", payload));
243 + };
244 +
245 +
246 + // TopoUiEvent type binding of handlers
247 + private final Map<TopoUiEvent.Type, ModelEventHandler>
248 + eventHandlerBinding = new HashMap<>();
249 +
250 + private void bindEventHandlers() {
251 + eventHandlerBinding.put(SUMMARY_UPDATE, summaryHandler);
252 + // NOTE: no need to bind pass-thru handlers
253 + }
254 +
133 } 255 }
......
...@@ -194,6 +194,7 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase { ...@@ -194,6 +194,7 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase {
194 194
195 // ================================================================== 195 // ==================================================================
196 196
197 + @Deprecated
197 private final class TopoStart extends RequestHandler { 198 private final class TopoStart extends RequestHandler {
198 private TopoStart() { 199 private TopoStart() {
199 super(TOPO_START); 200 super(TOPO_START);
...@@ -209,6 +210,7 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase { ...@@ -209,6 +210,7 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase {
209 } 210 }
210 } 211 }
211 212
213 + @Deprecated
212 private final class TopoStop extends RequestHandler { 214 private final class TopoStop extends RequestHandler {
213 private TopoStop() { 215 private TopoStop() {
214 super(TOPO_STOP); 216 super(TOPO_STOP);
...@@ -221,6 +223,7 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase { ...@@ -221,6 +223,7 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase {
221 } 223 }
222 } 224 }
223 225
226 + @Deprecated
224 private final class ReqSummary extends RequestHandler { 227 private final class ReqSummary extends RequestHandler {
225 private ReqSummary() { 228 private ReqSummary() {
226 super(REQ_SUMMARY); 229 super(REQ_SUMMARY);
......
...@@ -29,6 +29,8 @@ import org.onosproject.ui.UiExtensionService; ...@@ -29,6 +29,8 @@ import org.onosproject.ui.UiExtensionService;
29 import org.onosproject.ui.UiMessageHandlerFactory; 29 import org.onosproject.ui.UiMessageHandlerFactory;
30 import org.onosproject.ui.UiView; 30 import org.onosproject.ui.UiView;
31 import org.onosproject.ui.UiViewHidden; 31 import org.onosproject.ui.UiViewHidden;
32 +import org.onosproject.ui.impl.topo.OverlayService;
33 +import org.onosproject.ui.impl.topo.overlay.SummaryGenerator;
32 import org.slf4j.Logger; 34 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory; 35 import org.slf4j.LoggerFactory;
34 36
...@@ -46,7 +48,8 @@ import static org.onosproject.ui.UiView.Category.PLATFORM; ...@@ -46,7 +48,8 @@ import static org.onosproject.ui.UiView.Category.PLATFORM;
46 */ 48 */
47 @Component(immediate = true) 49 @Component(immediate = true)
48 @Service 50 @Service
49 -public class UiExtensionManager implements UiExtensionService, SpriteService { 51 +public class UiExtensionManager
52 + implements UiExtensionService, SpriteService, OverlayService {
50 53
51 private final Logger log = LoggerFactory.getLogger(getClass()); 54 private final Logger log = LoggerFactory.getLogger(getClass());
52 55
...@@ -59,9 +62,13 @@ public class UiExtensionManager implements UiExtensionService, SpriteService { ...@@ -59,9 +62,13 @@ public class UiExtensionManager implements UiExtensionService, SpriteService {
59 // Core views & core extension 62 // Core views & core extension
60 private final UiExtension core = createCoreExtension(); 63 private final UiExtension core = createCoreExtension();
61 64
65 + // Topology Message Handler
66 + private final AltTopoViewMessageHandler topoHandler =
67 + new AltTopoViewMessageHandler();
68 +
62 69
63 // Creates core UI extension 70 // Creates core UI extension
64 - private static UiExtension createCoreExtension() { 71 + private UiExtension createCoreExtension() {
65 List<UiView> coreViews = of( 72 List<UiView> coreViews = of(
66 new UiView(PLATFORM, "app", "Applications", "nav_apps"), 73 new UiView(PLATFORM, "app", "Applications", "nav_apps"),
67 new UiView(PLATFORM, "cluster", "Cluster Nodes", "nav_cluster"), 74 new UiView(PLATFORM, "cluster", "Cluster Nodes", "nav_cluster"),
...@@ -78,7 +85,7 @@ public class UiExtensionManager implements UiExtensionService, SpriteService { ...@@ -78,7 +85,7 @@ public class UiExtensionManager implements UiExtensionService, SpriteService {
78 UiMessageHandlerFactory messageHandlerFactory = 85 UiMessageHandlerFactory messageHandlerFactory =
79 () -> ImmutableList.of( 86 () -> ImmutableList.of(
80 new TopologyViewMessageHandler(), 87 new TopologyViewMessageHandler(),
81 -// new AltTopoViewMessageHandler(), 88 +// topoHandler,
82 new DeviceViewMessageHandler(), 89 new DeviceViewMessageHandler(),
83 new LinkViewMessageHandler(), 90 new LinkViewMessageHandler(),
84 new HostViewMessageHandler(), 91 new HostViewMessageHandler(),
...@@ -119,7 +126,8 @@ public class UiExtensionManager implements UiExtensionService, SpriteService { ...@@ -119,7 +126,8 @@ public class UiExtensionManager implements UiExtensionService, SpriteService {
119 @Override 126 @Override
120 public synchronized void unregister(UiExtension extension) { 127 public synchronized void unregister(UiExtension extension) {
121 extensions.remove(extension); 128 extensions.remove(extension);
122 - extension.views().stream().map(UiView::id).collect(toSet()).forEach(views::remove); 129 + extension.views().stream()
130 + .map(UiView::id).collect(toSet()).forEach(views::remove);
123 } 131 }
124 132
125 @Override 133 @Override
...@@ -132,9 +140,10 @@ public class UiExtensionManager implements UiExtensionService, SpriteService { ...@@ -132,9 +140,10 @@ public class UiExtensionManager implements UiExtensionService, SpriteService {
132 return views.get(viewId); 140 return views.get(viewId);
133 } 141 }
134 142
135 - 143 + // =====================================================================
136 // Provisional tracking of sprite definitions 144 // Provisional tracking of sprite definitions
137 - private Map<String, JsonNode> sprites = Maps.newHashMap(); 145 +
146 + private final Map<String, JsonNode> sprites = Maps.newHashMap();
138 147
139 @Override 148 @Override
140 public Set<String> getNames() { 149 public Set<String> getNames() {
...@@ -152,4 +161,18 @@ public class UiExtensionManager implements UiExtensionService, SpriteService { ...@@ -152,4 +161,18 @@ public class UiExtensionManager implements UiExtensionService, SpriteService {
152 return sprites.get(name); 161 return sprites.get(name);
153 } 162 }
154 163
164 +
165 + // =====================================================================
166 + // Topology Overlay API -- pass through to topology message handler
167 +
168 + // NOTE: while WIP, comment out calls to topoHandler (for checked in code)
169 + @Override
170 + public void addSummaryGenerator(String overlayId, SummaryGenerator generator) {
171 + topoHandler.addSummaryGenerator(overlayId, generator);
172 + }
173 +
174 + @Override
175 + public void removeSummaryGenerator(String overlayId) {
176 + topoHandler.removeSummaryGenerator(overlayId);
177 + }
155 } 178 }
......
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + *
16 + */
17 +
18 +package org.onosproject.ui.impl.topo;
19 +
20 +import org.onosproject.ui.impl.topo.overlay.SummaryGenerator;
21 +
22 +/**
23 + * Provides the API for external agents to inject topology overlay behavior.
24 + */
25 +public interface OverlayService {
26 +
27 + /**
28 + * Registers a custom summary generator for the specified overlay.
29 + *
30 + * @param overlayId overlay identifier
31 + * @param generator generator to register
32 + */
33 + void addSummaryGenerator(String overlayId, SummaryGenerator generator);
34 +
35 + /**
36 + * Unregisters the generator associated with the specified overlay.
37 + *
38 + * @param overlayId overlay identifier
39 + */
40 + void removeSummaryGenerator(String overlayId);
41 +}
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + *
16 + */
17 +
18 +package org.onosproject.ui.impl.topo;
19 +
20 +/**
21 + * Provides basic summary data for the topology.
22 + */
23 +public interface SummaryData {
24 +
25 + /**
26 + * Returns the number of devices.
27 + *
28 + * @return number of devices
29 + */
30 + int deviceCount();
31 +
32 + /**
33 + * Returns the number of links.
34 + *
35 + * @return number of links
36 + */
37 + int linkCount();
38 +
39 + /**
40 + * Returns the number of hosts.
41 + *
42 + * @return number of hosts
43 + */
44 + int hostCount();
45 +
46 + /**
47 + * Returns the number of clusters (topology SCCs).
48 + *
49 + * @return number of clusters
50 + */
51 + int clusterCount();
52 +
53 + /**
54 + * Returns the number of intents in the system.
55 + *
56 + * @return number of intents
57 + */
58 + long intentCount();
59 +
60 + /**
61 + * Returns the number of flow rules in the system.
62 + *
63 + * @return number of flow rules
64 + */
65 + int flowRuleCount();
66 +
67 +}
...@@ -29,6 +29,10 @@ public class TopoUiEvent extends AbstractEvent<TopoUiEvent.Type, ObjectNode> { ...@@ -29,6 +29,10 @@ public class TopoUiEvent extends AbstractEvent<TopoUiEvent.Type, ObjectNode> {
29 * Type of Topology UI Model events. 29 * Type of Topology UI Model events.
30 */ 30 */
31 public enum Type { 31 public enum Type {
32 + // notification events
33 + SUMMARY_UPDATE,
34 +
35 + // unsolicited topology events
32 INSTANCE_ADDED, 36 INSTANCE_ADDED,
33 INSTANCE_REMOVED, 37 INSTANCE_REMOVED,
34 DEVICE_ADDED, 38 DEVICE_ADDED,
......
...@@ -35,10 +35,14 @@ import org.onosproject.net.Host; ...@@ -35,10 +35,14 @@ import org.onosproject.net.Host;
35 import org.onosproject.net.Link; 35 import org.onosproject.net.Link;
36 import org.onosproject.net.device.DeviceEvent; 36 import org.onosproject.net.device.DeviceEvent;
37 import org.onosproject.net.device.DeviceService; 37 import org.onosproject.net.device.DeviceService;
38 +import org.onosproject.net.flow.FlowRuleService;
38 import org.onosproject.net.host.HostEvent; 39 import org.onosproject.net.host.HostEvent;
39 import org.onosproject.net.host.HostService; 40 import org.onosproject.net.host.HostService;
41 +import org.onosproject.net.intent.IntentService;
40 import org.onosproject.net.link.LinkEvent; 42 import org.onosproject.net.link.LinkEvent;
41 import org.onosproject.net.link.LinkService; 43 import org.onosproject.net.link.LinkService;
44 +import org.onosproject.net.topology.Topology;
45 +import org.onosproject.net.topology.TopologyService;
42 import org.slf4j.Logger; 46 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory; 47 import org.slf4j.LoggerFactory;
44 48
...@@ -51,6 +55,7 @@ import static org.onosproject.cluster.ClusterEvent.Type.INSTANCE_ADDED; ...@@ -51,6 +55,7 @@ import static org.onosproject.cluster.ClusterEvent.Type.INSTANCE_ADDED;
51 import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_ADDED; 55 import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_ADDED;
52 import static org.onosproject.net.host.HostEvent.Type.HOST_ADDED; 56 import static org.onosproject.net.host.HostEvent.Type.HOST_ADDED;
53 import static org.onosproject.net.link.LinkEvent.Type.LINK_ADDED; 57 import static org.onosproject.net.link.LinkEvent.Type.LINK_ADDED;
58 +import static org.onosproject.ui.impl.topo.TopoUiEvent.Type.SUMMARY_UPDATE;
54 59
55 60
56 /** 61 /**
...@@ -79,6 +84,14 @@ public class TopoUiModelManager implements TopoUiModelService { ...@@ -79,6 +84,14 @@ public class TopoUiModelManager implements TopoUiModelService {
79 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 84 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
80 protected MastershipService mastershipService; 85 protected MastershipService mastershipService;
81 86
87 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
88 + protected IntentService intentService;
89 +
90 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
91 + protected FlowRuleService flowRuleService;
92 +
93 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
94 + protected TopologyService topologyService;
82 95
83 96
84 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 97 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
...@@ -103,6 +116,7 @@ public class TopoUiModelManager implements TopoUiModelService { ...@@ -103,6 +116,7 @@ public class TopoUiModelManager implements TopoUiModelService {
103 linkService, 116 linkService,
104 hostService, 117 hostService,
105 mastershipService 118 mastershipService
119 + // TODO: others??
106 ); 120 );
107 log.info("Started"); 121 log.info("Started");
108 } 122 }
...@@ -113,6 +127,17 @@ public class TopoUiModelManager implements TopoUiModelService { ...@@ -113,6 +127,17 @@ public class TopoUiModelManager implements TopoUiModelService {
113 log.info("Stopped"); 127 log.info("Stopped");
114 } 128 }
115 129
130 +
131 + // TODO: figure out how to cull zombie listeners
132 + // The problem is when one refreshes the GUI (topology view)
133 + // a new instance of AltTopoViewMessageHandler is created and added
134 + // as a listener, but we never got a TopoStop event, which is what
135 + // causes the listener (for an AltTopoViewMessageHandler instance) to
136 + // be removed.
137 + // ==== Somehow need to tie this in to the GUI-disconnected event.
138 +
139 +
140 +
116 @Override 141 @Override
117 public void addListener(TopoUiListener listener) { 142 public void addListener(TopoUiListener listener) {
118 listenerRegistry.addListener(listener); 143 listenerRegistry.addListener(listener);
...@@ -133,6 +158,60 @@ public class TopoUiModelManager implements TopoUiModelService { ...@@ -133,6 +158,60 @@ public class TopoUiModelManager implements TopoUiModelService {
133 return results; 158 return results;
134 } 159 }
135 160
161 + @Override
162 + public void startSummaryMonitoring() {
163 + // TODO: set up periodic monitoring task
164 + // send a summary now, and periodically...
165 + post(new TopoUiEvent(SUMMARY_UPDATE, null));
166 + }
167 +
168 + @Override
169 + public void stopSummaryMonitoring() {
170 + // TODO: cancel monitoring task
171 +
172 + }
173 +
174 + @Override
175 + public SummaryData getSummaryData() {
176 + return new SummaryDataImpl();
177 + }
178 +
179 + // =====================================================================
180 +
181 + private final class SummaryDataImpl implements SummaryData {
182 + private final Topology topology = topologyService.currentTopology();
183 +
184 + @Override
185 + public int deviceCount() {
186 + return topology.deviceCount();
187 + }
188 +
189 + @Override
190 + public int linkCount() {
191 + return topology.linkCount();
192 + }
193 +
194 + @Override
195 + public int hostCount() {
196 + return hostService.getHostCount();
197 + }
198 +
199 + @Override
200 + public int clusterCount() {
201 + return topology.clusterCount();
202 + }
203 +
204 + @Override
205 + public long intentCount() {
206 + return intentService.getIntentCount();
207 + }
208 +
209 + @Override
210 + public int flowRuleCount() {
211 + return flowRuleService.getFlowRuleCount();
212 + }
213 + }
214 +
136 // ===================================================================== 215 // =====================================================================
137 216
138 private static final Comparator<? super ControllerNode> NODE_COMPARATOR = 217 private static final Comparator<? super ControllerNode> NODE_COMPARATOR =
......
...@@ -47,8 +47,27 @@ public interface TopoUiModelService { ...@@ -47,8 +47,27 @@ public interface TopoUiModelService {
47 * These will be in the form of "addInstance", "addDevice", "addLink", 47 * These will be in the form of "addInstance", "addDevice", "addLink",
48 * and "addHost" events, as appropriate. 48 * and "addHost" events, as appropriate.
49 * 49 *
50 - * @return initial state events 50 + * @return initial state messages
51 */ 51 */
52 List<ObjectNode> getInitialState(); 52 List<ObjectNode> getInitialState();
53 53
54 + /**
55 + * Starts the summary monitoring process.
56 + * <p>
57 + * Sends a "showSummary" message now, and schedules a task to send
58 + * updates whenever the data changes.
59 + */
60 + void startSummaryMonitoring();
61 +
62 + /**
63 + * Cancels the task that sends summary updates.
64 + */
65 + void stopSummaryMonitoring();
66 +
67 + /**
68 + * Returns base data about the topology.
69 + *
70 + * @return summary data
71 + */
72 + SummaryData getSummaryData();
54 } 73 }
......
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + *
16 + */
17 +
18 +package org.onosproject.ui.impl.topo.overlay;
19 +
20 +import com.fasterxml.jackson.databind.ObjectMapper;
21 +import com.fasterxml.jackson.databind.node.ArrayNode;
22 +import com.fasterxml.jackson.databind.node.ObjectNode;
23 +
24 +import java.text.DecimalFormat;
25 +import java.util.ArrayList;
26 +import java.util.List;
27 +
28 +/**
29 + * Base implementation of a {@link SummaryGenerator}. Provides convenience
30 + * methods for compiling a list of properties to be displayed in the summary
31 + * panel on the UI.
32 + */
33 +public abstract class AbstractSummaryGenerator implements SummaryGenerator {
34 + private static final String NUMBER_FORMAT = "#,###";
35 + private static final DecimalFormat DF = new DecimalFormat(NUMBER_FORMAT);
36 + private static final ObjectMapper MAPPER = new ObjectMapper();
37 +
38 + private final List<Prop> props = new ArrayList<>();
39 + private String iconId;
40 + private String title;
41 +
42 + /**
43 + * Constructs a summary generator without specifying the icon ID or title.
44 + * It is expected that the title (and optionally the icon ID) will be set
45 + * later via {@link #title(String)} (and {@link #iconId(String)}), before
46 + * {@link #buildObjectNode()} is invoked to generate the message payload.
47 + */
48 + public AbstractSummaryGenerator() {
49 + }
50 +
51 + /**
52 + * Constructs a summary generator that uses the specified iconId ID and
53 + * title in its generated output.
54 + *
55 + * @param iconId iconId ID
56 + * @param title title
57 + */
58 + public AbstractSummaryGenerator(String iconId, String title) {
59 + this.iconId = iconId;
60 + this.title = title;
61 + }
62 +
63 + /**
64 + * Subclasses need to provide an implementation.
65 + *
66 + * @return the summary payload
67 + */
68 + @Override
69 + public abstract ObjectNode generateSummary();
70 +
71 + /**
72 + * Formats the given number into a string, using comma separator.
73 + *
74 + * @param number the number
75 + * @return formatted as a string
76 + */
77 + protected String format(Number number) {
78 + return DF.format(number);
79 + }
80 +
81 + /**
82 + * Sets the iconId ID to use.
83 + *
84 + * @param iconId iconId ID
85 + */
86 + protected void iconId(String iconId) {
87 + this.iconId = iconId;
88 + }
89 +
90 + /**
91 + * Sets the summary panel title.
92 + *
93 + * @param title the title
94 + */
95 + protected void title(String title) {
96 + this.title = title;
97 + }
98 +
99 + /**
100 + * Clears out the cache of properties.
101 + */
102 + protected void clearProps() {
103 + props.clear();
104 + }
105 +
106 + /**
107 + * Adds a property to the summary. Note that the value is converted to
108 + * a string by invoking the <code>toString()</code> method on it.
109 + *
110 + * @param label the label
111 + * @param value the value
112 + */
113 + protected void prop(String label, Object value) {
114 + props.add(new Prop(label, value));
115 + }
116 +
117 + /**
118 + * Adds a separator to the summary; when rendered on the client, a visible
119 + * break between properties.
120 + */
121 + protected void separator() {
122 + props.add(new Prop("-", ""));
123 + }
124 +
125 + /**
126 + * Builds an object node from the current state of the summary generator.
127 + *
128 + * @return summary payload as JSON object node
129 + */
130 + protected ObjectNode buildObjectNode() {
131 + ObjectNode result = MAPPER.createObjectNode();
132 + // NOTE: "id" and "type" are currently used for title and iconID
133 + // so that this structure can be "re-used" with detail panel payloads
134 + result.put("id", title).put("type", iconId);
135 +
136 + ObjectNode pnode = MAPPER.createObjectNode();
137 + ArrayNode porder = MAPPER.createArrayNode();
138 +
139 + for (Prop p : props) {
140 + porder.add(p.label);
141 + pnode.put(p.label, p.value);
142 + }
143 + result.set("propOrder", porder);
144 + result.set("props", pnode);
145 +
146 + return result;
147 + }
148 +
149 + // ===================================================================
150 +
151 + /**
152 + * Abstraction of a property, that is, a label-value pair.
153 + */
154 + private static class Prop {
155 + private final String label;
156 + private final String value;
157 +
158 + public Prop(String label, Object value) {
159 + this.label = label;
160 + this.value = value.toString();
161 + }
162 + }
163 +}
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + *
16 + */
17 +
18 +package org.onosproject.ui.impl.topo.overlay;
19 +
20 +import com.fasterxml.jackson.databind.node.ObjectNode;
21 +
22 +/**
23 + * May be called upon to generate the summary messages for the topology view
24 + * in the GUI.
25 + * <p>
26 + * It is assumed that if a custom summary generator is installed on the server
27 + * (as part of a topology overlay), a peer custom summary message handler will
28 + * be installed on the client side to handle the messages thus generated.
29 + */
30 +public interface SummaryGenerator {
31 + /**
32 + * Generates the payload for the "showSummary" message.
33 + *
34 + * @return the message payload
35 + */
36 + ObjectNode generateSummary();
37 +}