blob: 7cb0e40b55165ff7e44e93df6da150daa8e8ab4e [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.topo;
19
20import com.fasterxml.jackson.databind.node.ObjectNode;
21import org.apache.felix.scr.annotations.Activate;
22import org.apache.felix.scr.annotations.Component;
23import org.apache.felix.scr.annotations.Deactivate;
24import org.apache.felix.scr.annotations.Reference;
25import org.apache.felix.scr.annotations.ReferenceCardinality;
26import org.apache.felix.scr.annotations.Service;
27import org.onosproject.cluster.ClusterEvent;
28import org.onosproject.cluster.ClusterService;
29import org.onosproject.cluster.ControllerNode;
30import org.onosproject.event.AbstractListenerRegistry;
31import org.onosproject.event.EventDeliveryService;
32import org.onosproject.mastership.MastershipService;
33import org.onosproject.net.Device;
34import org.onosproject.net.Host;
35import org.onosproject.net.Link;
36import org.onosproject.net.device.DeviceEvent;
37import org.onosproject.net.device.DeviceService;
Simon Huntc54cd1b2015-05-11 13:43:44 -070038import org.onosproject.net.flow.FlowRuleService;
Simon Huntd7f7bcc2015-05-08 14:13:17 -070039import org.onosproject.net.host.HostEvent;
40import org.onosproject.net.host.HostService;
Simon Huntc54cd1b2015-05-11 13:43:44 -070041import org.onosproject.net.intent.IntentService;
Simon Huntd7f7bcc2015-05-08 14:13:17 -070042import org.onosproject.net.link.LinkEvent;
43import org.onosproject.net.link.LinkService;
Simon Huntc54cd1b2015-05-11 13:43:44 -070044import org.onosproject.net.topology.Topology;
45import org.onosproject.net.topology.TopologyService;
Simon Huntd7f7bcc2015-05-08 14:13:17 -070046import org.slf4j.Logger;
47import org.slf4j.LoggerFactory;
48
49import java.util.ArrayList;
50import java.util.Collections;
51import java.util.Comparator;
52import java.util.List;
53
54import static org.onosproject.cluster.ClusterEvent.Type.INSTANCE_ADDED;
55import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_ADDED;
56import static org.onosproject.net.host.HostEvent.Type.HOST_ADDED;
57import static org.onosproject.net.link.LinkEvent.Type.LINK_ADDED;
Simon Huntc54cd1b2015-05-11 13:43:44 -070058import static org.onosproject.ui.impl.topo.TopoUiEvent.Type.SUMMARY_UPDATE;
Simon Huntd7f7bcc2015-05-08 14:13:17 -070059
60
61/**
62 * Maintains a UI-centric model of the topology, as inferred from interactions
63 * with the different (device, host, link, ...) services. Will serve up this
64 * model to anyone who cares to {@link TopoUiListener listen}.
65 */
66@Component(immediate = true)
67@Service
68public class TopoUiModelManager implements TopoUiModelService {
69
70 private final Logger log = LoggerFactory.getLogger(getClass());
71
72 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
73 protected ClusterService clusterService;
74
75 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
76 protected DeviceService deviceService;
77
78 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
79 protected LinkService linkService;
80
81 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
82 protected HostService hostService;
83
84 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
85 protected MastershipService mastershipService;
86
Simon Huntc54cd1b2015-05-11 13:43:44 -070087 @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;
Simon Huntd7f7bcc2015-05-08 14:13:17 -070095
96
97 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
98 protected EventDeliveryService eventDispatcher;
99
100
101 private AbstractListenerRegistry<TopoUiEvent, TopoUiListener>
102 listenerRegistry = new AbstractListenerRegistry<>();
103
104
105 private final TopoMessageFactory messageFactory = new TopoMessageFactory();
106 private final MetaDb metaDb = new MetaDb();
107
108
109 @Activate
110 public void activate() {
111 eventDispatcher.addSink(TopoUiEvent.class, listenerRegistry);
112 messageFactory.injectServices(
113 metaDb,
114 clusterService,
115 deviceService,
116 linkService,
117 hostService,
118 mastershipService
Simon Huntc54cd1b2015-05-11 13:43:44 -0700119 // TODO: others??
Simon Huntd7f7bcc2015-05-08 14:13:17 -0700120 );
121 log.info("Started");
122 }
123
124 @Deactivate
125 public void deactivate() {
126 eventDispatcher.removeSink(TopoUiEvent.class);
127 log.info("Stopped");
128 }
129
Simon Huntc54cd1b2015-05-11 13:43:44 -0700130
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
Simon Huntd7f7bcc2015-05-08 14:13:17 -0700141 @Override
142 public void addListener(TopoUiListener listener) {
143 listenerRegistry.addListener(listener);
144 }
145
146 @Override
147 public void removeListener(TopoUiListener listener) {
148 listenerRegistry.removeListener(listener);
149 }
150
151 @Override
152 public List<ObjectNode> getInitialState() {
153 List<ObjectNode> results = new ArrayList<>();
154 addInstances(results);
155 addDevices(results);
156 addLinks(results);
157 addHosts(results);
158 return results;
159 }
160
Simon Huntc54cd1b2015-05-11 13:43:44 -0700161 @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
Simon Huntd7f7bcc2015-05-08 14:13:17 -0700215 // =====================================================================
216
217 private static final Comparator<? super ControllerNode> NODE_COMPARATOR =
218 (o1, o2) -> o1.id().toString().compareTo(o2.id().toString());
219
220 // =====================================================================
221
222 private void addInstances(List<ObjectNode> results) {
223 List<ControllerNode> nodes = new ArrayList<>(clusterService.getNodes());
224 Collections.sort(nodes, NODE_COMPARATOR);
225 for (ControllerNode node : nodes) {
226 ClusterEvent ev = new ClusterEvent(INSTANCE_ADDED, node);
227 results.add(messageFactory.instanceMessage(ev));
228 }
229 }
230
231 private void addDevices(List<ObjectNode> results) {
232 // Send optical first, others later -- for layered rendering
233 List<DeviceEvent> deferred = new ArrayList<>();
234
235 for (Device device : deviceService.getDevices()) {
236 DeviceEvent ev = new DeviceEvent(DEVICE_ADDED, device);
237 if (device.type() == Device.Type.ROADM) {
238 results.add(messageFactory.deviceMessage(ev));
239 } else {
240 deferred.add(ev);
241 }
242 }
243
244 for (DeviceEvent ev : deferred) {
245 results.add(messageFactory.deviceMessage(ev));
246 }
247 }
248
249 private void addLinks(List<ObjectNode> results) {
250 // Send optical first, others later -- for layered rendering
251 List<LinkEvent> deferred = new ArrayList<>();
252
253 for (Link link : linkService.getLinks()) {
254 LinkEvent ev = new LinkEvent(LINK_ADDED, link);
255 if (link.type() == Link.Type.OPTICAL) {
256 results.add(messageFactory.linkMessage(ev));
257 } else {
258 deferred.add(ev);
259 }
260 }
261
262 for (LinkEvent ev : deferred) {
263 results.add(messageFactory.linkMessage(ev));
264 }
265 }
266
267 private void addHosts(List<ObjectNode> results) {
268 for (Host host : hostService.getHosts()) {
269 HostEvent ev = new HostEvent(HOST_ADDED, host);
270 results.add(messageFactory.hostMessage(ev));
271 }
272 }
273
274 // =====================================================================
275
276 private void post(TopoUiEvent event) {
277 if (event != null) {
278 eventDispatcher.post(event);
279 }
280 }
281
282 // NOTE: session-independent state only
283 // private inner classes to listen to device/host/link events
284 // TODO..
285}