blob: 3d164f5b4f631c72fa7b991ee6d26720ff7bc550 [file] [log] [blame]
Simon Hunted804d52016-03-30 09:51:40 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
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;
Simon Hunt0e161092017-05-08 17:41:38 -070022import org.onosproject.ui.model.topo.UiLinkId;
Thomas Vachuska8c0b18a2017-04-14 16:27:33 -070023import org.onosproject.ui.model.topo.UiModelEvent;
Simon Huntcda9c032016-04-11 10:32:54 -070024import org.onosproject.ui.impl.topo.model.UiModelListener;
Simon Huntf679c4e2016-04-01 17:02:24 -070025import org.onosproject.ui.impl.topo.model.UiSharedTopologyModel;
Simon Huntd5b96732016-07-08 13:22:27 -070026import org.onosproject.ui.model.topo.UiClusterMember;
Simon Hunt98189192016-07-29 19:02:27 -070027import org.onosproject.ui.model.topo.UiNode;
Simon Huntd5b96732016-07-08 13:22:27 -070028import org.onosproject.ui.model.topo.UiRegion;
Simon Huntc13082f2016-08-03 21:20:23 -070029import org.onosproject.ui.model.topo.UiSynthLink;
Simon Huntf679c4e2016-04-01 17:02:24 -070030import org.onosproject.ui.model.topo.UiTopoLayout;
Simon Hunted804d52016-03-30 09:51:40 -070031import org.slf4j.Logger;
32import org.slf4j.LoggerFactory;
33
Simon Huntf836a872016-08-10 17:37:36 -070034import java.util.ArrayList;
Simon Huntb1ce2602016-07-23 14:04:31 -070035import java.util.HashSet;
Simon Huntd5b96732016-07-08 13:22:27 -070036import java.util.List;
Simon Hunt0e161092017-05-08 17:41:38 -070037import java.util.Map;
Simon Hunt977aa052016-07-20 17:08:29 -070038import java.util.Set;
Simon Huntd5b96732016-07-08 13:22:27 -070039
Simon Hunted804d52016-03-30 09:51:40 -070040/**
Simon Huntf679c4e2016-04-01 17:02:24 -070041 * Coordinates with the {@link UiTopoLayoutService} to access
42 * {@link UiTopoLayout}s, and with the {@link UiSharedTopologyModel} which
Simon Huntcda9c032016-04-11 10:32:54 -070043 * maintains a local model of the network entities, tailored specifically
44 * for displaying on the UI.
Simon Hunted804d52016-03-30 09:51:40 -070045 * <p>
46 * Note that an instance of this class will be created for each
Simon Huntf679c4e2016-04-01 17:02:24 -070047 * {@link UiWebSocket} connection, and will contain
Simon Hunted804d52016-03-30 09:51:40 -070048 * the state of how the topology is laid out for the logged-in user.
Simon Huntd5b96732016-07-08 13:22:27 -070049 * <p>
50 * The expected pattern is for the {@link Topo2ViewMessageHandler} to obtain
51 * a reference to the session instance (via the {@link UiWebSocket}), and
52 * interact with it when topo-related events come in from the client.
Simon Hunted804d52016-03-30 09:51:40 -070053 */
Simon Huntcda9c032016-04-11 10:32:54 -070054public class UiTopoSession implements UiModelListener {
Simon Hunt977aa052016-07-20 17:08:29 -070055
Simon Hunt537bc762016-12-20 12:15:13 -080056 private static final String TOPO2_UI_MODEL_EVENT = "topo2UiModelEvent";
57
Simon Hunted804d52016-03-30 09:51:40 -070058 private final Logger log = LoggerFactory.getLogger(getClass());
59
Simon Huntf679c4e2016-04-01 17:02:24 -070060 private final UiWebSocket webSocket;
Simon Hunt7092cc42016-04-06 18:40:17 -070061 private final String username;
Simon Hunt537bc762016-12-20 12:15:13 -080062 private final Topo2Jsonifier t2json;
Simon Hunt7092cc42016-04-06 18:40:17 -070063
64 final UiSharedTopologyModel sharedModel;
Simon Hunted804d52016-03-30 09:51:40 -070065
66 private boolean registered = false;
67
Thomas Vachuska92b016b2016-05-20 11:37:57 -070068 private UiTopoLayoutService layoutService;
Simon Hunt7092cc42016-04-06 18:40:17 -070069 private UiTopoLayout currentLayout;
Simon Huntbbd0f462017-01-10 14:50:22 -080070 private boolean messagesEnabled = true;
Simon Huntf679c4e2016-04-01 17:02:24 -070071
Simon Hunted804d52016-03-30 09:51:40 -070072 /**
Simon Hunt537bc762016-12-20 12:15:13 -080073 * Creates a new topology session for the specified web socket connection,
74 * and references to JSONifier, shared model, and layout service.
Simon Hunt7092cc42016-04-06 18:40:17 -070075 *
Thomas Vachuska92b016b2016-05-20 11:37:57 -070076 * @param webSocket web socket
Simon Hunt537bc762016-12-20 12:15:13 -080077 * @param jsonifier JSONifier instance
Thomas Vachuska92b016b2016-05-20 11:37:57 -070078 * @param model share topology model
79 * @param layoutService topology layout service
Simon Hunted804d52016-03-30 09:51:40 -070080 */
Thomas Vachuska92b016b2016-05-20 11:37:57 -070081 public UiTopoSession(UiWebSocket webSocket,
Simon Hunt537bc762016-12-20 12:15:13 -080082 Topo2Jsonifier jsonifier,
Thomas Vachuska92b016b2016-05-20 11:37:57 -070083 UiSharedTopologyModel model,
84 UiTopoLayoutService layoutService) {
Simon Huntf679c4e2016-04-01 17:02:24 -070085 this.webSocket = webSocket;
Simon Hunt7092cc42016-04-06 18:40:17 -070086 this.username = webSocket.userName();
Simon Hunt537bc762016-12-20 12:15:13 -080087 this.t2json = jsonifier;
Simon Huntcda9c032016-04-11 10:32:54 -070088 this.sharedModel = model;
Thomas Vachuska92b016b2016-05-20 11:37:57 -070089 this.layoutService = layoutService;
Simon Hunted804d52016-03-30 09:51:40 -070090 }
91
Simon Hunt977aa052016-07-20 17:08:29 -070092 // constructs a neutered instance, for unit testing
93 UiTopoSession() {
94 webSocket = null;
95 username = null;
Simon Hunt537bc762016-12-20 12:15:13 -080096 t2json = null;
Simon Hunt977aa052016-07-20 17:08:29 -070097 sharedModel = null;
98 }
99
Simon Hunted804d52016-03-30 09:51:40 -0700100 /**
Simon Hunt7092cc42016-04-06 18:40:17 -0700101 * Initializes the session; registering with the shared model.
Simon Hunted804d52016-03-30 09:51:40 -0700102 */
103 public void init() {
104 if (!registered) {
Simon Hunt7092cc42016-04-06 18:40:17 -0700105 log.debug("{} : Registering with shared model", this);
Simon Hunted804d52016-03-30 09:51:40 -0700106 sharedModel.register(this);
Thomas Vachuska92b016b2016-05-20 11:37:57 -0700107 currentLayout = layoutService.getRootLayout();
Simon Hunted804d52016-03-30 09:51:40 -0700108 registered = true;
109 } else {
110 log.warn("already registered");
111 }
112 }
113
114 /**
Simon Hunt7092cc42016-04-06 18:40:17 -0700115 * Destroys the session; unregistering from the shared model.
Simon Hunted804d52016-03-30 09:51:40 -0700116 */
117 public void destroy() {
Simon Hunt7092cc42016-04-06 18:40:17 -0700118 if (registered) {
119 log.debug("{} : Unregistering from shared model", this);
Simon Hunted804d52016-03-30 09:51:40 -0700120 sharedModel.unregister(this);
Simon Huntf679c4e2016-04-01 17:02:24 -0700121 registered = false;
Simon Hunted804d52016-03-30 09:51:40 -0700122 } else {
123 log.warn("already unregistered");
124 }
125 }
126
127 @Override
128 public String toString() {
Simon Huntf679c4e2016-04-01 17:02:24 -0700129 return String.format("{UiTopoSession for user <%s>}", username);
Simon Hunted804d52016-03-30 09:51:40 -0700130 }
Simon Huntcda9c032016-04-11 10:32:54 -0700131
132 @Override
Thomas Vachuska8c0b18a2017-04-14 16:27:33 -0700133 public boolean isRelevant(UiModelEvent event) {
134 if (!messagesEnabled) {
135 return false;
Simon Huntbbd0f462017-01-10 14:50:22 -0800136 }
Thomas Vachuska8c0b18a2017-04-14 16:27:33 -0700137 UiRegion uiRegion = sharedModel.getRegion(currentLayout.regionId());
138 return uiRegion.isRelevant(event);
139 }
140
141 @Override
142 public void event(UiModelEvent event) {
143 webSocket.sendMessage(TOPO2_UI_MODEL_EVENT, t2json.jsonEvent(event));
Simon Huntcda9c032016-04-11 10:32:54 -0700144 }
Thomas Vachuska92b016b2016-05-20 11:37:57 -0700145
146 /**
147 * Returns the current layout context.
148 *
149 * @return current topology layout
150 */
151 public UiTopoLayout currentLayout() {
152 return currentLayout;
153 }
154
155 /**
Simon Huntf836a872016-08-10 17:37:36 -0700156 * Returns the breadcrumb trail from current layout to root. That is,
157 * element 0 of the list will be the current layout; the last element
158 * of the list will be the root layout. This list is guaranteed to have
159 * size of at least 1.
160 *
161 * @return breadcrumb trail
162 */
163 public List<UiTopoLayout> breadCrumbs() {
164 UiTopoLayout current = currentLayout;
165 List<UiTopoLayout> crumbs = new ArrayList<>();
166 crumbs.add(current);
167 while (!current.isRoot()) {
168 current = layoutService.getLayout(current.parent());
169 crumbs.add(current);
170 }
171 return crumbs;
172 }
173
174 /**
Thomas Vachuska92b016b2016-05-20 11:37:57 -0700175 * Changes the current layout context to the specified layout.
176 *
177 * @param topoLayout new topology layout context
178 */
179 public void setCurrentLayout(UiTopoLayout topoLayout) {
180 currentLayout = topoLayout;
181 }
182
183 /**
184 * Enables or disables the transmission of topology event update messages.
185 *
186 * @param enabled true if messages should be sent
187 */
188 public void enableEvent(boolean enabled) {
189 messagesEnabled = enabled;
190 }
Simon Huntd5b96732016-07-08 13:22:27 -0700191
192 /**
193 * Returns the list of ONOS instances (cluster members).
194 *
195 * @return the list of ONOS instances
196 */
197 public List<UiClusterMember> getAllInstances() {
198 return sharedModel.getClusterMembers();
199 }
200
201 /**
202 * Returns the region for the specified layout.
203 *
204 * @param layout layout filter
205 * @return region that the layout is based upon
206 */
207 public UiRegion getRegion(UiTopoLayout layout) {
Simon Huntb1ce2602016-07-23 14:04:31 -0700208 RegionId rid = layout.regionId();
209 return rid == null ? sharedModel.getNullRegion() : sharedModel.getRegion(rid);
Simon Huntd5b96732016-07-08 13:22:27 -0700210 }
Simon Hunt977aa052016-07-20 17:08:29 -0700211
212 /**
Simon Hunt98189192016-07-29 19:02:27 -0700213 * Returns the regions/devices that are "peers" to this region. That is,
214 * based on the layout the user is viewing, all the regions/devices that
215 * are associated with layouts that share the same parent layout as this
216 * layout, AND that are linked to an element within this region.
Simon Hunt977aa052016-07-20 17:08:29 -0700217 *
218 * @param layout the layout being viewed
Simon Hunt98189192016-07-29 19:02:27 -0700219 * @return all regions/devices that are "siblings" to this layout's region
Simon Hunt977aa052016-07-20 17:08:29 -0700220 */
Simon Hunt98189192016-07-29 19:02:27 -0700221 public Set<UiNode> getPeerNodes(UiTopoLayout layout) {
222 Set<UiNode> peers = new HashSet<>();
223
224 // first, get the peer regions
225 Set<UiTopoLayout> peerLayouts = layoutService.getPeerLayouts(layout.id());
226 peerLayouts.forEach(l -> {
227 RegionId peerRegion = l.regionId();
228 peers.add(sharedModel.getRegion(peerRegion));
229 });
230
231 // now add the devices that reside in the parent region
232 if (!layout.isRoot()) {
233 UiTopoLayout parentLayout = layoutService.getLayout(layout.parent());
Simon Hunt8f60ff82017-04-24 17:19:30 -0700234 peers.addAll(getRegion(parentLayout).devices());
Simon Hunt98189192016-07-29 19:02:27 -0700235 }
236
237 // TODO: Finally, filter out regions / devices that are not connected
238 // directly to this region by an implicit link
Simon Huntb1ce2602016-07-23 14:04:31 -0700239 return peers;
Simon Hunt977aa052016-07-20 17:08:29 -0700240 }
241
242 /**
243 * Returns the subregions of the region in the specified layout.
244 *
245 * @param layout the layout being viewed
246 * @return all regions that are "contained within" this layout's region
247 */
248 public Set<UiRegion> getSubRegions(UiTopoLayout layout) {
Simon Huntb1ce2602016-07-23 14:04:31 -0700249 Set<UiTopoLayout> kidLayouts = layoutService.getChildren(layout.id());
250 Set<UiRegion> kids = new HashSet<>();
251 kidLayouts.forEach(l -> kids.add(sharedModel.getRegion(l.regionId())));
252 return kids;
Simon Hunt977aa052016-07-20 17:08:29 -0700253 }
254
255 /**
Simon Huntc13082f2016-08-03 21:20:23 -0700256 * Returns the (synthetic) links of the region in the specified layout.
257 *
258 * @param layout the layout being viewed
259 * @return all links that are contained by this layout's region
260 */
261 public List<UiSynthLink> getLinks(UiTopoLayout layout) {
262 return sharedModel.getSynthLinks(layout.regionId());
263 }
264
265 /**
Simon Huntb1ce2602016-07-23 14:04:31 -0700266 * Refreshes the model's internal state.
Simon Hunt977aa052016-07-20 17:08:29 -0700267 */
Simon Huntb1ce2602016-07-23 14:04:31 -0700268 public void refreshModel() {
269 sharedModel.refresh();
Simon Hunt977aa052016-07-20 17:08:29 -0700270 }
Simon Hunt377f5d22016-09-01 16:27:21 -0700271
272 /**
273 * Navigates to the specified region by setting the associated layout as
274 * current.
275 *
276 * @param regionId region identifier
277 */
278 public void navToRegion(String regionId) {
279 // 1. find the layout corresponding to the region ID
280 // 2. set this layout to be "current"
281 RegionId r = RegionId.regionId(regionId);
282 UiTopoLayout layout = layoutService.getLayout(r);
283 setCurrentLayout(layout);
284 }
Simon Hunt0e161092017-05-08 17:41:38 -0700285
286 /**
287 * Returns synthetic links that are in the current region, mapped by
288 * original link ID.
289 *
290 * @return map of synth links
291 */
292 public Map<UiLinkId, UiSynthLink> relevantSynthLinks() {
293 return sharedModel.relevantSynthLinks(currentLayout.regionId());
294 }
Simon Hunted804d52016-03-30 09:51:40 -0700295}