blob: f13ebc523648046ad089bfba2440c18e1be5ecb8 [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 Hunt537bc762016-12-20 12:15:13 -080019import com.fasterxml.jackson.databind.node.ObjectNode;
Simon Huntb1ce2602016-07-23 14:04:31 -070020import org.onosproject.net.region.RegionId;
Simon Huntf679c4e2016-04-01 17:02:24 -070021import org.onosproject.ui.UiTopoLayoutService;
22import org.onosproject.ui.impl.UiWebSocket;
Simon Huntcda9c032016-04-11 10:32:54 -070023import org.onosproject.ui.impl.topo.model.UiModelEvent;
24import 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 Hunt977aa052016-07-20 17:08:29 -070037import java.util.Set;
Simon Huntd5b96732016-07-08 13:22:27 -070038
Simon Hunted804d52016-03-30 09:51:40 -070039/**
Simon Huntf679c4e2016-04-01 17:02:24 -070040 * Coordinates with the {@link UiTopoLayoutService} to access
41 * {@link UiTopoLayout}s, and with the {@link UiSharedTopologyModel} which
Simon Huntcda9c032016-04-11 10:32:54 -070042 * maintains a local model of the network entities, tailored specifically
43 * for displaying on the UI.
Simon Hunted804d52016-03-30 09:51:40 -070044 * <p>
45 * Note that an instance of this class will be created for each
Simon Huntf679c4e2016-04-01 17:02:24 -070046 * {@link UiWebSocket} connection, and will contain
Simon Hunted804d52016-03-30 09:51:40 -070047 * the state of how the topology is laid out for the logged-in user.
Simon Huntd5b96732016-07-08 13:22:27 -070048 * <p>
49 * The expected pattern is for the {@link Topo2ViewMessageHandler} to obtain
50 * a reference to the session instance (via the {@link UiWebSocket}), and
51 * interact with it when topo-related events come in from the client.
Simon Hunted804d52016-03-30 09:51:40 -070052 */
Simon Huntcda9c032016-04-11 10:32:54 -070053public class UiTopoSession implements UiModelListener {
Simon Hunt977aa052016-07-20 17:08:29 -070054
Simon Hunt537bc762016-12-20 12:15:13 -080055 private static final String TOPO2_UI_MODEL_EVENT = "topo2UiModelEvent";
56
Simon Hunted804d52016-03-30 09:51:40 -070057 private final Logger log = LoggerFactory.getLogger(getClass());
58
Simon Huntf679c4e2016-04-01 17:02:24 -070059 private final UiWebSocket webSocket;
Simon Hunt7092cc42016-04-06 18:40:17 -070060 private final String username;
Simon Hunt537bc762016-12-20 12:15:13 -080061 private final Topo2Jsonifier t2json;
Simon Hunt7092cc42016-04-06 18:40:17 -070062
63 final UiSharedTopologyModel sharedModel;
Simon Hunted804d52016-03-30 09:51:40 -070064
65 private boolean registered = false;
66
Thomas Vachuska92b016b2016-05-20 11:37:57 -070067 private UiTopoLayoutService layoutService;
Simon Hunt7092cc42016-04-06 18:40:17 -070068 private UiTopoLayout currentLayout;
Thomas Vachuska92b016b2016-05-20 11:37:57 -070069 private boolean messagesEnabled;
Simon Huntf679c4e2016-04-01 17:02:24 -070070
Simon Hunted804d52016-03-30 09:51:40 -070071 /**
Simon Hunt537bc762016-12-20 12:15:13 -080072 * Creates a new topology session for the specified web socket connection,
73 * and references to JSONifier, shared model, and layout service.
Simon Hunt7092cc42016-04-06 18:40:17 -070074 *
Thomas Vachuska92b016b2016-05-20 11:37:57 -070075 * @param webSocket web socket
Simon Hunt537bc762016-12-20 12:15:13 -080076 * @param jsonifier JSONifier instance
Thomas Vachuska92b016b2016-05-20 11:37:57 -070077 * @param model share topology model
78 * @param layoutService topology layout service
Simon Hunted804d52016-03-30 09:51:40 -070079 */
Thomas Vachuska92b016b2016-05-20 11:37:57 -070080 public UiTopoSession(UiWebSocket webSocket,
Simon Hunt537bc762016-12-20 12:15:13 -080081 Topo2Jsonifier jsonifier,
Thomas Vachuska92b016b2016-05-20 11:37:57 -070082 UiSharedTopologyModel model,
83 UiTopoLayoutService layoutService) {
Simon Huntf679c4e2016-04-01 17:02:24 -070084 this.webSocket = webSocket;
Simon Hunt7092cc42016-04-06 18:40:17 -070085 this.username = webSocket.userName();
Simon Hunt537bc762016-12-20 12:15:13 -080086 this.t2json = jsonifier;
Simon Huntcda9c032016-04-11 10:32:54 -070087 this.sharedModel = model;
Thomas Vachuska92b016b2016-05-20 11:37:57 -070088 this.layoutService = layoutService;
Simon Hunted804d52016-03-30 09:51:40 -070089 }
90
Simon Hunt977aa052016-07-20 17:08:29 -070091 // constructs a neutered instance, for unit testing
92 UiTopoSession() {
93 webSocket = null;
94 username = null;
Simon Hunt537bc762016-12-20 12:15:13 -080095 t2json = null;
Simon Hunt977aa052016-07-20 17:08:29 -070096 sharedModel = null;
97 }
98
Simon Hunted804d52016-03-30 09:51:40 -070099 /**
Simon Hunt7092cc42016-04-06 18:40:17 -0700100 * Initializes the session; registering with the shared model.
Simon Hunted804d52016-03-30 09:51:40 -0700101 */
102 public void init() {
103 if (!registered) {
Simon Hunt7092cc42016-04-06 18:40:17 -0700104 log.debug("{} : Registering with shared model", this);
Simon Hunted804d52016-03-30 09:51:40 -0700105 sharedModel.register(this);
Thomas Vachuska92b016b2016-05-20 11:37:57 -0700106 currentLayout = layoutService.getRootLayout();
Simon Hunted804d52016-03-30 09:51:40 -0700107 registered = true;
108 } else {
109 log.warn("already registered");
110 }
111 }
112
113 /**
Simon Hunt7092cc42016-04-06 18:40:17 -0700114 * Destroys the session; unregistering from the shared model.
Simon Hunted804d52016-03-30 09:51:40 -0700115 */
116 public void destroy() {
Simon Hunt7092cc42016-04-06 18:40:17 -0700117 if (registered) {
118 log.debug("{} : Unregistering from shared model", this);
Simon Hunted804d52016-03-30 09:51:40 -0700119 sharedModel.unregister(this);
Simon Huntf679c4e2016-04-01 17:02:24 -0700120 registered = false;
Simon Hunted804d52016-03-30 09:51:40 -0700121 } else {
122 log.warn("already unregistered");
123 }
124 }
125
126 @Override
127 public String toString() {
Simon Huntf679c4e2016-04-01 17:02:24 -0700128 return String.format("{UiTopoSession for user <%s>}", username);
Simon Hunted804d52016-03-30 09:51:40 -0700129 }
Simon Huntcda9c032016-04-11 10:32:54 -0700130
131 @Override
132 public void event(UiModelEvent event) {
Yuta HIGUCHI28ad09a2016-06-28 17:08:29 -0700133 log.debug("Event received: {}", event);
Simon Hunt537bc762016-12-20 12:15:13 -0800134 ObjectNode payload = t2json.jsonEvent(event);
135
136 // TODO: add filtering for relevant objects only...
137 // TO Decide: Since the session holds the state of what is being
138 // displayed on the client, we should filter out any model events
139 // that are not relevant, and only send up events for objects that
140 // are currently being viewed by the user.
141
Simon Huntc5368182017-01-10 13:32:04 -0800142 webSocket.sendMessage(TOPO2_UI_MODEL_EVENT, payload);
Simon Huntcda9c032016-04-11 10:32:54 -0700143 }
Thomas Vachuska92b016b2016-05-20 11:37:57 -0700144
145 /**
146 * Returns the current layout context.
147 *
148 * @return current topology layout
149 */
150 public UiTopoLayout currentLayout() {
151 return currentLayout;
152 }
153
154 /**
Simon Huntf836a872016-08-10 17:37:36 -0700155 * Returns the breadcrumb trail from current layout to root. That is,
156 * element 0 of the list will be the current layout; the last element
157 * of the list will be the root layout. This list is guaranteed to have
158 * size of at least 1.
159 *
160 * @return breadcrumb trail
161 */
162 public List<UiTopoLayout> breadCrumbs() {
163 UiTopoLayout current = currentLayout;
164 List<UiTopoLayout> crumbs = new ArrayList<>();
165 crumbs.add(current);
166 while (!current.isRoot()) {
167 current = layoutService.getLayout(current.parent());
168 crumbs.add(current);
169 }
170 return crumbs;
171 }
172
173 /**
Thomas Vachuska92b016b2016-05-20 11:37:57 -0700174 * Changes the current layout context to the specified layout.
175 *
176 * @param topoLayout new topology layout context
177 */
178 public void setCurrentLayout(UiTopoLayout topoLayout) {
179 currentLayout = topoLayout;
180 }
181
182 /**
183 * Enables or disables the transmission of topology event update messages.
184 *
185 * @param enabled true if messages should be sent
186 */
187 public void enableEvent(boolean enabled) {
188 messagesEnabled = enabled;
189 }
Simon Huntd5b96732016-07-08 13:22:27 -0700190
191 /**
192 * Returns the list of ONOS instances (cluster members).
193 *
194 * @return the list of ONOS instances
195 */
196 public List<UiClusterMember> getAllInstances() {
197 return sharedModel.getClusterMembers();
198 }
199
200 /**
201 * Returns the region for the specified layout.
202 *
203 * @param layout layout filter
204 * @return region that the layout is based upon
205 */
206 public UiRegion getRegion(UiTopoLayout layout) {
Simon Huntb1ce2602016-07-23 14:04:31 -0700207 RegionId rid = layout.regionId();
208 return rid == null ? sharedModel.getNullRegion() : sharedModel.getRegion(rid);
Simon Huntd5b96732016-07-08 13:22:27 -0700209 }
Simon Hunt977aa052016-07-20 17:08:29 -0700210
211 /**
Simon Hunt98189192016-07-29 19:02:27 -0700212 * Returns the regions/devices that are "peers" to this region. That is,
213 * based on the layout the user is viewing, all the regions/devices that
214 * are associated with layouts that share the same parent layout as this
215 * layout, AND that are linked to an element within this region.
Simon Hunt977aa052016-07-20 17:08:29 -0700216 *
217 * @param layout the layout being viewed
Simon Hunt98189192016-07-29 19:02:27 -0700218 * @return all regions/devices that are "siblings" to this layout's region
Simon Hunt977aa052016-07-20 17:08:29 -0700219 */
Simon Hunt98189192016-07-29 19:02:27 -0700220 public Set<UiNode> getPeerNodes(UiTopoLayout layout) {
221 Set<UiNode> peers = new HashSet<>();
222
223 // first, get the peer regions
224 Set<UiTopoLayout> peerLayouts = layoutService.getPeerLayouts(layout.id());
225 peerLayouts.forEach(l -> {
226 RegionId peerRegion = l.regionId();
227 peers.add(sharedModel.getRegion(peerRegion));
228 });
229
230 // now add the devices that reside in the parent region
231 if (!layout.isRoot()) {
232 UiTopoLayout parentLayout = layoutService.getLayout(layout.parent());
233 getRegion(parentLayout).devices().forEach(peers::add);
234 }
235
236 // TODO: Finally, filter out regions / devices that are not connected
237 // directly to this region by an implicit link
Simon Huntb1ce2602016-07-23 14:04:31 -0700238 return peers;
Simon Hunt977aa052016-07-20 17:08:29 -0700239 }
240
241 /**
242 * Returns the subregions of the region in the specified layout.
243 *
244 * @param layout the layout being viewed
245 * @return all regions that are "contained within" this layout's region
246 */
247 public Set<UiRegion> getSubRegions(UiTopoLayout layout) {
Simon Huntb1ce2602016-07-23 14:04:31 -0700248 Set<UiTopoLayout> kidLayouts = layoutService.getChildren(layout.id());
249 Set<UiRegion> kids = new HashSet<>();
250 kidLayouts.forEach(l -> kids.add(sharedModel.getRegion(l.regionId())));
251 return kids;
Simon Hunt977aa052016-07-20 17:08:29 -0700252 }
253
254 /**
Simon Huntc13082f2016-08-03 21:20:23 -0700255 * Returns the (synthetic) links of the region in the specified layout.
256 *
257 * @param layout the layout being viewed
258 * @return all links that are contained by this layout's region
259 */
260 public List<UiSynthLink> getLinks(UiTopoLayout layout) {
261 return sharedModel.getSynthLinks(layout.regionId());
262 }
263
264 /**
Simon Huntb1ce2602016-07-23 14:04:31 -0700265 * Refreshes the model's internal state.
Simon Hunt977aa052016-07-20 17:08:29 -0700266 */
Simon Huntb1ce2602016-07-23 14:04:31 -0700267 public void refreshModel() {
268 sharedModel.refresh();
Simon Hunt977aa052016-07-20 17:08:29 -0700269 }
Simon Hunt377f5d22016-09-01 16:27:21 -0700270
271 /**
272 * Navigates to the specified region by setting the associated layout as
273 * current.
274 *
275 * @param regionId region identifier
276 */
277 public void navToRegion(String regionId) {
278 // 1. find the layout corresponding to the region ID
279 // 2. set this layout to be "current"
280 RegionId r = RegionId.regionId(regionId);
281 UiTopoLayout layout = layoutService.getLayout(r);
282 setCurrentLayout(layout);
283 }
Simon Hunted804d52016-03-30 09:51:40 -0700284}