blob: 8a7534fb46fe45ab0f0c054e92846f240c75f839 [file] [log] [blame]
Simon Huntd7f7bcc2015-05-08 14:13:17 -07001/*
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
18package org.onosproject.ui.impl;
19
20import com.fasterxml.jackson.databind.node.ObjectNode;
21import com.google.common.collect.ImmutableSet;
Simon Huntc54cd1b2015-05-11 13:43:44 -070022import com.google.common.collect.Maps;
Simon Huntd7f7bcc2015-05-08 14:13:17 -070023import org.onlab.osgi.ServiceDirectory;
24import org.onosproject.core.CoreService;
Simon Huntc54cd1b2015-05-11 13:43:44 -070025import org.onosproject.ui.JsonUtils;
Simon Huntd7f7bcc2015-05-08 14:13:17 -070026import org.onosproject.ui.RequestHandler;
27import org.onosproject.ui.UiConnection;
28import org.onosproject.ui.UiMessageHandler;
Simon Huntc54cd1b2015-05-11 13:43:44 -070029import org.onosproject.ui.impl.topo.OverlayService;
30import org.onosproject.ui.impl.topo.SummaryData;
Simon Huntd7f7bcc2015-05-08 14:13:17 -070031import org.onosproject.ui.impl.topo.TopoUiEvent;
32import org.onosproject.ui.impl.topo.TopoUiListener;
33import org.onosproject.ui.impl.topo.TopoUiModelService;
Simon Huntc54cd1b2015-05-11 13:43:44 -070034import org.onosproject.ui.impl.topo.overlay.AbstractSummaryGenerator;
35import org.onosproject.ui.impl.topo.overlay.SummaryGenerator;
Simon Huntd7f7bcc2015-05-08 14:13:17 -070036import org.slf4j.Logger;
37import org.slf4j.LoggerFactory;
38
39import java.util.Collection;
Simon Huntc54cd1b2015-05-11 13:43:44 -070040import java.util.HashMap;
41import java.util.Map;
Simon Huntd7f7bcc2015-05-08 14:13:17 -070042
43import static com.google.common.base.Preconditions.checkNotNull;
Simon Huntc54cd1b2015-05-11 13:43:44 -070044import static org.onosproject.ui.impl.topo.TopoUiEvent.Type.SUMMARY_UPDATE;
Simon Huntd7f7bcc2015-05-08 14:13:17 -070045
46/**
47 * Facility for handling inbound messages from the topology view, and
48 * generating outbound messages for the same.
49 */
Simon Huntc54cd1b2015-05-11 13:43:44 -070050public class AltTopoViewMessageHandler extends UiMessageHandler
51 implements OverlayService {
Simon Huntd7f7bcc2015-05-08 14:13:17 -070052
53 private static final String TOPO_START = "topoStart";
54 private static final String TOPO_STOP = "topoStop";
Simon Huntc54cd1b2015-05-11 13:43:44 -070055 private static final String REQ_SUMMARY = "requestSummary";
Simon Huntd7f7bcc2015-05-08 14:13:17 -070056
57 private final Logger log = LoggerFactory.getLogger(getClass());
58
59 protected ServiceDirectory directory;
60 protected TopoUiModelService modelService;
61
62 private TopoUiListener modelListener;
63 private String version;
Simon Huntc54cd1b2015-05-11 13:43:44 -070064 private SummaryGenerator defaultSummaryGenerator;
65 private SummaryGenerator currentSummaryGenerator;
66
Simon Huntd7f7bcc2015-05-08 14:13:17 -070067
68 private boolean topoActive = false;
69
70 @Override
71 public void init(UiConnection connection, ServiceDirectory directory) {
72 super.init(connection, directory);
73 this.directory = checkNotNull(directory, "Directory cannot be null");
74 modelService = directory.get(TopoUiModelService.class);
Simon Huntc54cd1b2015-05-11 13:43:44 -070075 defaultSummaryGenerator = new DefSummaryGenerator("node", "ONOS Summary");
Simon Huntd7f7bcc2015-05-08 14:13:17 -070076
Simon Huntc54cd1b2015-05-11 13:43:44 -070077 bindEventHandlers();
Simon Huntd7f7bcc2015-05-08 14:13:17 -070078 modelListener = new ModelListener();
79 version = getVersion();
Simon Huntc54cd1b2015-05-11 13:43:44 -070080 currentSummaryGenerator = defaultSummaryGenerator;
Simon Huntd7f7bcc2015-05-08 14:13:17 -070081 }
82
83
84 private String getVersion() {
85 String ver = directory.get(CoreService.class).version().toString();
86 return ver.replace(".SNAPSHOT", "*").replaceFirst("~.*$", "");
87 }
88
89
90 @Override
91 protected Collection<RequestHandler> getHandlers() {
92 return ImmutableSet.of(
93 new TopoStart(),
Simon Huntc54cd1b2015-05-11 13:43:44 -070094 new TopoStop(),
95 new ReqSummary()
96 // TODO: add more handlers here.....
Simon Huntd7f7bcc2015-05-08 14:13:17 -070097 );
98 }
99
100 // =====================================================================
Simon Huntc54cd1b2015-05-11 13:43:44 -0700101 // 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 // =====================================================================
Simon Huntd7f7bcc2015-05-08 14:13:17 -0700121 // Request Handlers for (topo view) events from the UI...
122
123 private final class TopoStart extends RequestHandler {
124 private TopoStart() {
125 super(TOPO_START);
126 }
127
128 @Override
129 public void process(long sid, ObjectNode payload) {
130 topoActive = true;
131 modelService.addListener(modelListener);
132 sendMessages(modelService.getInitialState());
Simon Huntd7f7bcc2015-05-08 14:13:17 -0700133 }
134 }
135
136 private final class TopoStop extends RequestHandler {
137 private TopoStop() {
138 super(TOPO_STOP);
139 }
140
141 @Override
142 public void process(long sid, ObjectNode payload) {
143 topoActive = false;
144 modelService.removeListener(modelListener);
Simon Huntc54cd1b2015-05-11 13:43:44 -0700145 }
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();
Simon Huntd7f7bcc2015-05-08 14:13:17 -0700182 }
183 }
184
185 // =====================================================================
186 // Private Helper Methods...
187
188 private void sendMessages(Collection<ObjectNode> messages) {
189 if (topoActive) {
190 UiConnection connection = connection();
191 if (connection != null) {
192 messages.forEach(connection::sendMessage);
193 }
194 }
195 }
196
Simon Huntc54cd1b2015-05-11 13:43:44 -0700197 private void sendMessages(ObjectNode message) {
198 if (topoActive) {
199 UiConnection connection = connection();
200 if (connection != null) {
201 connection.sendMessage(message);
202 }
203 }
204 }
205
Simon Huntd7f7bcc2015-05-08 14:13:17 -0700206 // =====================================================================
207 // Our listener for model events so we can push changes out to the UI...
208
209 private class ModelListener implements TopoUiListener {
210 @Override
211 public void event(TopoUiEvent event) {
212 log.debug("Handle Event: {}", event);
Simon Huntc54cd1b2015-05-11 13:43:44 -0700213 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);
Simon Huntd7f7bcc2015-05-08 14:13:17 -0700220 }
221 }
Simon Huntc54cd1b2015-05-11 13:43:44 -0700222
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());
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
Simon Huntd7f7bcc2015-05-08 14:13:17 -0700255}