blob: 3a3f141f8d5383b53b36083c6b42ce5913254a2e [file] [log] [blame]
Simon Hunted804d52016-03-30 09:51:40 -07001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2016-present Open Networking Laboratory
Simon Hunted804d52016-03-30 09:51:40 -07003 *
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
Simon Huntf679c4e2016-04-01 17:02:24 -070017package org.onosproject.ui.impl.topo;
Simon Hunted804d52016-03-30 09:51:40 -070018
Simon Huntb1ce2602016-07-23 14:04:31 -070019import org.onosproject.net.region.RegionId;
Simon Huntf679c4e2016-04-01 17:02:24 -070020import org.onosproject.ui.UiTopoLayoutService;
21import org.onosproject.ui.impl.UiWebSocket;
Thomas Vachuska8c0b18a2017-04-14 16:27:33 -070022import org.onosproject.ui.model.topo.UiModelEvent;
Simon Huntcda9c032016-04-11 10:32:54 -070023import org.onosproject.ui.impl.topo.model.UiModelListener;
Simon Huntf679c4e2016-04-01 17:02:24 -070024import org.onosproject.ui.impl.topo.model.UiSharedTopologyModel;
Simon Huntd5b96732016-07-08 13:22:27 -070025import org.onosproject.ui.model.topo.UiClusterMember;
Simon Hunt98189192016-07-29 19:02:27 -070026import org.onosproject.ui.model.topo.UiNode;
Simon Huntd5b96732016-07-08 13:22:27 -070027import org.onosproject.ui.model.topo.UiRegion;
Simon Huntc13082f2016-08-03 21:20:23 -070028import org.onosproject.ui.model.topo.UiSynthLink;
Simon Huntf679c4e2016-04-01 17:02:24 -070029import org.onosproject.ui.model.topo.UiTopoLayout;
Simon Hunted804d52016-03-30 09:51:40 -070030import org.slf4j.Logger;
31import org.slf4j.LoggerFactory;
32
Simon Huntf836a872016-08-10 17:37:36 -070033import java.util.ArrayList;
Simon Huntb1ce2602016-07-23 14:04:31 -070034import java.util.HashSet;
Simon Huntd5b96732016-07-08 13:22:27 -070035import java.util.List;
Simon Hunt977aa052016-07-20 17:08:29 -070036import java.util.Set;
Simon Huntd5b96732016-07-08 13:22:27 -070037
Simon Hunted804d52016-03-30 09:51:40 -070038/**
Simon Huntf679c4e2016-04-01 17:02:24 -070039 * Coordinates with the {@link UiTopoLayoutService} to access
40 * {@link UiTopoLayout}s, and with the {@link UiSharedTopologyModel} which
Simon Huntcda9c032016-04-11 10:32:54 -070041 * maintains a local model of the network entities, tailored specifically
42 * for displaying on the UI.
Simon Hunted804d52016-03-30 09:51:40 -070043 * <p>
44 * Note that an instance of this class will be created for each
Simon Huntf679c4e2016-04-01 17:02:24 -070045 * {@link UiWebSocket} connection, and will contain
Simon Hunted804d52016-03-30 09:51:40 -070046 * the state of how the topology is laid out for the logged-in user.
Simon Huntd5b96732016-07-08 13:22:27 -070047 * <p>
48 * The expected pattern is for the {@link Topo2ViewMessageHandler} to obtain
49 * a reference to the session instance (via the {@link UiWebSocket}), and
50 * interact with it when topo-related events come in from the client.
Simon Hunted804d52016-03-30 09:51:40 -070051 */
Simon Huntcda9c032016-04-11 10:32:54 -070052public class UiTopoSession implements UiModelListener {
Simon Hunt977aa052016-07-20 17:08:29 -070053
Simon Hunt537bc762016-12-20 12:15:13 -080054 private static final String TOPO2_UI_MODEL_EVENT = "topo2UiModelEvent";
55
Simon Hunted804d52016-03-30 09:51:40 -070056 private final Logger log = LoggerFactory.getLogger(getClass());
57
Simon Huntf679c4e2016-04-01 17:02:24 -070058 private final UiWebSocket webSocket;
Simon Hunt7092cc42016-04-06 18:40:17 -070059 private final String username;
Simon Hunt537bc762016-12-20 12:15:13 -080060 private final Topo2Jsonifier t2json;
Simon Hunt7092cc42016-04-06 18:40:17 -070061
62 final UiSharedTopologyModel sharedModel;
Simon Hunted804d52016-03-30 09:51:40 -070063
64 private boolean registered = false;
65
Thomas Vachuska92b016b2016-05-20 11:37:57 -070066 private UiTopoLayoutService layoutService;
Simon Hunt7092cc42016-04-06 18:40:17 -070067 private UiTopoLayout currentLayout;
Simon Huntbbd0f462017-01-10 14:50:22 -080068 private boolean messagesEnabled = true;
Simon Huntf679c4e2016-04-01 17:02:24 -070069
Simon Hunted804d52016-03-30 09:51:40 -070070 /**
Simon Hunt537bc762016-12-20 12:15:13 -080071 * Creates a new topology session for the specified web socket connection,
72 * and references to JSONifier, shared model, and layout service.
Simon Hunt7092cc42016-04-06 18:40:17 -070073 *
Thomas Vachuska92b016b2016-05-20 11:37:57 -070074 * @param webSocket web socket
Simon Hunt537bc762016-12-20 12:15:13 -080075 * @param jsonifier JSONifier instance
Thomas Vachuska92b016b2016-05-20 11:37:57 -070076 * @param model share topology model
77 * @param layoutService topology layout service
Simon Hunted804d52016-03-30 09:51:40 -070078 */
Thomas Vachuska92b016b2016-05-20 11:37:57 -070079 public UiTopoSession(UiWebSocket webSocket,
Simon Hunt537bc762016-12-20 12:15:13 -080080 Topo2Jsonifier jsonifier,
Thomas Vachuska92b016b2016-05-20 11:37:57 -070081 UiSharedTopologyModel model,
82 UiTopoLayoutService layoutService) {
Simon Huntf679c4e2016-04-01 17:02:24 -070083 this.webSocket = webSocket;
Simon Hunt7092cc42016-04-06 18:40:17 -070084 this.username = webSocket.userName();
Simon Hunt537bc762016-12-20 12:15:13 -080085 this.t2json = jsonifier;
Simon Huntcda9c032016-04-11 10:32:54 -070086 this.sharedModel = model;
Thomas Vachuska92b016b2016-05-20 11:37:57 -070087 this.layoutService = layoutService;
Simon Hunted804d52016-03-30 09:51:40 -070088 }
89
Simon Hunt977aa052016-07-20 17:08:29 -070090 // constructs a neutered instance, for unit testing
91 UiTopoSession() {
92 webSocket = null;
93 username = null;
Simon Hunt537bc762016-12-20 12:15:13 -080094 t2json = null;
Simon Hunt977aa052016-07-20 17:08:29 -070095 sharedModel = null;
96 }
97
Simon Hunted804d52016-03-30 09:51:40 -070098 /**
Simon Hunt7092cc42016-04-06 18:40:17 -070099 * Initializes the session; registering with the shared model.
Simon Hunted804d52016-03-30 09:51:40 -0700100 */
101 public void init() {
102 if (!registered) {
Simon Hunt7092cc42016-04-06 18:40:17 -0700103 log.debug("{} : Registering with shared model", this);
Simon Hunted804d52016-03-30 09:51:40 -0700104 sharedModel.register(this);
Thomas Vachuska92b016b2016-05-20 11:37:57 -0700105 currentLayout = layoutService.getRootLayout();
Simon Hunted804d52016-03-30 09:51:40 -0700106 registered = true;
107 } else {
108 log.warn("already registered");
109 }
110 }
111
112 /**
Simon Hunt7092cc42016-04-06 18:40:17 -0700113 * Destroys the session; unregistering from the shared model.
Simon Hunted804d52016-03-30 09:51:40 -0700114 */
115 public void destroy() {
Simon Hunt7092cc42016-04-06 18:40:17 -0700116 if (registered) {
117 log.debug("{} : Unregistering from shared model", this);
Simon Hunted804d52016-03-30 09:51:40 -0700118 sharedModel.unregister(this);
Simon Huntf679c4e2016-04-01 17:02:24 -0700119 registered = false;
Simon Hunted804d52016-03-30 09:51:40 -0700120 } else {
121 log.warn("already unregistered");
122 }
123 }
124
125 @Override
126 public String toString() {
Simon Huntf679c4e2016-04-01 17:02:24 -0700127 return String.format("{UiTopoSession for user <%s>}", username);
Simon Hunted804d52016-03-30 09:51:40 -0700128 }
Simon Huntcda9c032016-04-11 10:32:54 -0700129
130 @Override
Thomas Vachuska8c0b18a2017-04-14 16:27:33 -0700131 public boolean isRelevant(UiModelEvent event) {
132 if (!messagesEnabled) {
133 return false;
Simon Huntbbd0f462017-01-10 14:50:22 -0800134 }
Thomas Vachuska8c0b18a2017-04-14 16:27:33 -0700135 UiRegion uiRegion = sharedModel.getRegion(currentLayout.regionId());
136 return uiRegion.isRelevant(event);
137 }
138
139 @Override
140 public void event(UiModelEvent event) {
141 webSocket.sendMessage(TOPO2_UI_MODEL_EVENT, t2json.jsonEvent(event));
Simon Huntcda9c032016-04-11 10:32:54 -0700142 }
Thomas Vachuska92b016b2016-05-20 11:37:57 -0700143
144 /**
145 * Returns the current layout context.
146 *
147 * @return current topology layout
148 */
149 public UiTopoLayout currentLayout() {
150 return currentLayout;
151 }
152
153 /**
Simon Huntf836a872016-08-10 17:37:36 -0700154 * Returns the breadcrumb trail from current layout to root. That is,
155 * element 0 of the list will be the current layout; the last element
156 * of the list will be the root layout. This list is guaranteed to have
157 * size of at least 1.
158 *
159 * @return breadcrumb trail
160 */
161 public List<UiTopoLayout> breadCrumbs() {
162 UiTopoLayout current = currentLayout;
163 List<UiTopoLayout> crumbs = new ArrayList<>();
164 crumbs.add(current);
165 while (!current.isRoot()) {
166 current = layoutService.getLayout(current.parent());
167 crumbs.add(current);
168 }
169 return crumbs;
170 }
171
172 /**
Thomas Vachuska92b016b2016-05-20 11:37:57 -0700173 * Changes the current layout context to the specified layout.
174 *
175 * @param topoLayout new topology layout context
176 */
177 public void setCurrentLayout(UiTopoLayout topoLayout) {
178 currentLayout = topoLayout;
179 }
180
181 /**
182 * Enables or disables the transmission of topology event update messages.
183 *
184 * @param enabled true if messages should be sent
185 */
186 public void enableEvent(boolean enabled) {
187 messagesEnabled = enabled;
188 }
Simon Huntd5b96732016-07-08 13:22:27 -0700189
190 /**
191 * Returns the list of ONOS instances (cluster members).
192 *
193 * @return the list of ONOS instances
194 */
195 public List<UiClusterMember> getAllInstances() {
196 return sharedModel.getClusterMembers();
197 }
198
199 /**
200 * Returns the region for the specified layout.
201 *
202 * @param layout layout filter
203 * @return region that the layout is based upon
204 */
205 public UiRegion getRegion(UiTopoLayout layout) {
Simon Huntb1ce2602016-07-23 14:04:31 -0700206 RegionId rid = layout.regionId();
207 return rid == null ? sharedModel.getNullRegion() : sharedModel.getRegion(rid);
Simon Huntd5b96732016-07-08 13:22:27 -0700208 }
Simon Hunt977aa052016-07-20 17:08:29 -0700209
210 /**
Simon Hunt98189192016-07-29 19:02:27 -0700211 * Returns the regions/devices that are "peers" to this region. That is,
212 * based on the layout the user is viewing, all the regions/devices that
213 * are associated with layouts that share the same parent layout as this
214 * layout, AND that are linked to an element within this region.
Simon Hunt977aa052016-07-20 17:08:29 -0700215 *
216 * @param layout the layout being viewed
Simon Hunt98189192016-07-29 19:02:27 -0700217 * @return all regions/devices that are "siblings" to this layout's region
Simon Hunt977aa052016-07-20 17:08:29 -0700218 */
Simon Hunt98189192016-07-29 19:02:27 -0700219 public Set<UiNode> getPeerNodes(UiTopoLayout layout) {
220 Set<UiNode> peers = new HashSet<>();
221
222 // first, get the peer regions
223 Set<UiTopoLayout> peerLayouts = layoutService.getPeerLayouts(layout.id());
224 peerLayouts.forEach(l -> {
225 RegionId peerRegion = l.regionId();
226 peers.add(sharedModel.getRegion(peerRegion));
227 });
228
229 // now add the devices that reside in the parent region
230 if (!layout.isRoot()) {
231 UiTopoLayout parentLayout = layoutService.getLayout(layout.parent());
Simon Hunt8f60ff82017-04-24 17:19:30 -0700232 peers.addAll(getRegion(parentLayout).devices());
Simon Hunt98189192016-07-29 19:02:27 -0700233 }
234
235 // TODO: Finally, filter out regions / devices that are not connected
236 // directly to this region by an implicit link
Simon Huntb1ce2602016-07-23 14:04:31 -0700237 return peers;
Simon Hunt977aa052016-07-20 17:08:29 -0700238 }
239
240 /**
241 * Returns the subregions of the region in the specified layout.
242 *
243 * @param layout the layout being viewed
244 * @return all regions that are "contained within" this layout's region
245 */
246 public Set<UiRegion> getSubRegions(UiTopoLayout layout) {
Simon Huntb1ce2602016-07-23 14:04:31 -0700247 Set<UiTopoLayout> kidLayouts = layoutService.getChildren(layout.id());
248 Set<UiRegion> kids = new HashSet<>();
249 kidLayouts.forEach(l -> kids.add(sharedModel.getRegion(l.regionId())));
250 return kids;
Simon Hunt977aa052016-07-20 17:08:29 -0700251 }
252
253 /**
Simon Huntc13082f2016-08-03 21:20:23 -0700254 * Returns the (synthetic) links of the region in the specified layout.
255 *
256 * @param layout the layout being viewed
257 * @return all links that are contained by this layout's region
258 */
259 public List<UiSynthLink> getLinks(UiTopoLayout layout) {
260 return sharedModel.getSynthLinks(layout.regionId());
261 }
262
263 /**
Simon Huntb1ce2602016-07-23 14:04:31 -0700264 * Refreshes the model's internal state.
Simon Hunt977aa052016-07-20 17:08:29 -0700265 */
Simon Huntb1ce2602016-07-23 14:04:31 -0700266 public void refreshModel() {
267 sharedModel.refresh();
Simon Hunt977aa052016-07-20 17:08:29 -0700268 }
Simon Hunt377f5d22016-09-01 16:27:21 -0700269
270 /**
271 * Navigates to the specified region by setting the associated layout as
272 * current.
273 *
274 * @param regionId region identifier
275 */
276 public void navToRegion(String regionId) {
277 // 1. find the layout corresponding to the region ID
278 // 2. set this layout to be "current"
279 RegionId r = RegionId.regionId(regionId);
280 UiTopoLayout layout = layoutService.getLayout(r);
281 setCurrentLayout(layout);
282 }
Simon Hunted804d52016-03-30 09:51:40 -0700283}