GUI -- Beginnings of structure for topology Overlay API.
- Re-implemented RequestSummary / ShowSummary in Alt implementation. Change-Id: Idb86c7bf3ede8f8815abcb488bbf9b0a7041ef79
Showing
12 changed files
with
577 additions
and
13 deletions
... | @@ -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 | +} |
-
Please register or login to post a comment