ONOS-4971: Synthetic Link Data -- WIP, merge anyway
- created temp Topology2 View (topoX) to "process" and display topology data.
- made root layout parent of itself (just like /.. = /) to simplify layout hierarchy operations.
- added nodeType property to JSON rep of regions/devices/hosts.
- augmented peers to include devices.
- added skeleton topo2NavRegion event.
Change-Id: I8219125d7dfe33d211350ae27111a3d9de6eb4ca
diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/UiExtensionManager.java b/web/gui/src/main/java/org/onosproject/ui/impl/UiExtensionManager.java
index 79f3d77..0cbc848 100644
--- a/web/gui/src/main/java/org/onosproject/ui/impl/UiExtensionManager.java
+++ b/web/gui/src/main/java/org/onosproject/ui/impl/UiExtensionManager.java
@@ -134,6 +134,7 @@
// FIXME: leave commented out for now, while still under development
// new UiView(NETWORK, "topo2", "New-Topo"),
+// new UiView(NETWORK, "topoX", "Topo-X"),
new UiView(NETWORK, "device", "Devices", "nav_devs"),
new UiViewHidden("flow"),
diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/topo/Topo2Jsonifier.java b/web/gui/src/main/java/org/onosproject/ui/impl/topo/Topo2Jsonifier.java
index 02df84c..8a26a92 100644
--- a/web/gui/src/main/java/org/onosproject/ui/impl/topo/Topo2Jsonifier.java
+++ b/web/gui/src/main/java/org/onosproject/ui/impl/topo/Topo2Jsonifier.java
@@ -40,6 +40,8 @@
import org.onosproject.ui.model.topo.UiNode;
import org.onosproject.ui.model.topo.UiRegion;
import org.onosproject.ui.model.topo.UiTopoLayout;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.HashMap;
@@ -62,6 +64,12 @@
private static final String E_UNKNOWN_UI_NODE =
"Unknown subclass of UiNode: ";
+ private static final String REGION = "region";
+ private static final String DEVICE = "device";
+ private static final String HOST = "host";
+
+ private final Logger log = LoggerFactory.getLogger(getClass());
+
private final ObjectMapper mapper = new ObjectMapper();
private ServiceDirectory directory;
@@ -245,6 +253,7 @@
private ObjectNode json(UiDevice device) {
ObjectNode node = objectNode()
.put("id", device.idAsString())
+ .put("nodeType", DEVICE)
.put("type", device.type())
.put("online", device.isOnline())
.put("master", nullIsEmpty(device.master()))
@@ -266,6 +275,7 @@
private ObjectNode json(UiHost host) {
return objectNode()
.put("id", host.idAsString())
+ .put("nodeType", HOST)
.put("layer", host.layer());
// TODO: complete host details
}
@@ -281,10 +291,31 @@
private ObjectNode jsonClosedRegion(UiRegion region) {
return objectNode()
.put("id", region.idAsString())
+ .put("nodeType", REGION)
.put("nDevs", region.deviceCount());
// TODO: complete closed-region details
}
+ /**
+ * Returns a JSON array representation of a set of regions/devices. Note
+ * that the information is sufficient for showing regions as nodes.
+ *
+ * @param nodes the nodes
+ * @return a JSON representation of the nodes
+ */
+ public ArrayNode closedNodes(Set<UiNode> nodes) {
+ ArrayNode array = arrayNode();
+ for (UiNode node: nodes) {
+ if (node instanceof UiRegion) {
+ array.add(jsonClosedRegion((UiRegion) node));
+ } else if (node instanceof UiDevice) {
+ array.add(json((UiDevice) node));
+ } else {
+ log.warn("Unexpected node instance: {}", node.getClass());
+ }
+ }
+ return array;
+ }
/**
* Returns a JSON array representation of a list of regions. Note that the
diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/topo/Topo2ViewMessageHandler.java b/web/gui/src/main/java/org/onosproject/ui/impl/topo/Topo2ViewMessageHandler.java
index 5449d93..7795271 100644
--- a/web/gui/src/main/java/org/onosproject/ui/impl/topo/Topo2ViewMessageHandler.java
+++ b/web/gui/src/main/java/org/onosproject/ui/impl/topo/Topo2ViewMessageHandler.java
@@ -24,6 +24,7 @@
import org.onosproject.ui.UiMessageHandler;
import org.onosproject.ui.impl.UiWebSocket;
import org.onosproject.ui.model.topo.UiClusterMember;
+import org.onosproject.ui.model.topo.UiNode;
import org.onosproject.ui.model.topo.UiRegion;
import org.onosproject.ui.model.topo.UiTopoLayout;
import org.slf4j.Logger;
@@ -55,8 +56,9 @@
private final Logger log = LoggerFactory.getLogger(getClass());
// === Inbound event identifiers
- private static final String TOPO2_START = "topo2Start";
- private static final String TOPO2_STOP = "topo2Stop";
+ private static final String START = "topo2Start";
+ private static final String NAV_REGION = "topo2navRegion";
+ private static final String STOP = "topo2Stop";
// === Outbound event identifiers
private static final String ALL_INSTANCES = "topo2AllInstances";
@@ -83,6 +85,7 @@
protected Collection<RequestHandler> createRequestHandlers() {
return ImmutableSet.of(
new Topo2Start(),
+ new Topo2NavRegion(),
new Topo2Stop()
);
}
@@ -92,7 +95,7 @@
private final class Topo2Start extends RequestHandler {
private Topo2Start() {
- super(TOPO2_START);
+ super(START);
}
@Override
@@ -124,10 +127,10 @@
Set<UiRegion> kids = topoSession.getSubRegions(currentLayout);
sendMessage(CURRENT_REGION, t2json.region(region, kids));
- // these are the regions that are siblings to this one
- Set<UiRegion> peers = topoSession.getPeerRegions(currentLayout);
+ // these are the regions/devices that are siblings to this region
+ Set<UiNode> peers = topoSession.getPeerNodes(currentLayout);
ObjectNode peersPayload = objectNode();
- peersPayload.set("peers", t2json.closedRegions(peers));
+ peersPayload.set("peers", t2json.closedNodes(peers));
sendMessage(PEER_REGIONS, peersPayload);
// finally, tell the UI that we are done : TODO review / delete??
@@ -146,9 +149,22 @@
}
+ private final class Topo2NavRegion extends RequestHandler {
+ private Topo2NavRegion() {
+ super(NAV_REGION);
+ }
+
+ @Override
+ public void process(long sid, ObjectNode payload) {
+ String dir = string(payload, "dir");
+ String rid = string(payload, "rid");
+ log.debug("NavRegion: dir={}, rid={}", dir, rid);
+ }
+ }
+
private final class Topo2Stop extends RequestHandler {
private Topo2Stop() {
- super(TOPO2_STOP);
+ super(STOP);
}
@Override
diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/topo/UiTopoLayoutManager.java b/web/gui/src/main/java/org/onosproject/ui/impl/topo/UiTopoLayoutManager.java
index 28e345c..fcf4c46 100644
--- a/web/gui/src/main/java/org/onosproject/ui/impl/topo/UiTopoLayoutManager.java
+++ b/web/gui/src/main/java/org/onosproject/ui/impl/topo/UiTopoLayoutManager.java
@@ -111,15 +111,17 @@
}
@Override
- public Set<UiTopoLayout> getPeers(UiTopoLayoutId layoutId) {
+ public Set<UiTopoLayout> getPeerLayouts(UiTopoLayoutId layoutId) {
checkNotNull(layoutId, ID_NULL);
+
UiTopoLayout layout = layoutMap.get(layoutId);
- if (layout == null) {
+ if (layout == null || layout.isRoot()) {
return Collections.emptySet();
}
UiTopoLayoutId parentId = layout.parent();
return layoutMap.values().stream()
+ // all layouts who are NOT me and who share my parent...
.filter(l -> !Objects.equals(l.id(), layoutId) &&
Objects.equals(l.parent(), parentId))
.collect(Collectors.toSet());
@@ -129,7 +131,7 @@
public Set<UiTopoLayout> getChildren(UiTopoLayoutId layoutId) {
checkNotNull(layoutId, ID_NULL);
return layoutMap.values().stream()
- .filter(l -> Objects.equals(l.parent(), layoutId))
+ .filter(l -> !l.isRoot() && Objects.equals(l.parent(), layoutId))
.collect(Collectors.toSet());
}
diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/topo/UiTopoSession.java b/web/gui/src/main/java/org/onosproject/ui/impl/topo/UiTopoSession.java
index 47907d4..7127ec1 100644
--- a/web/gui/src/main/java/org/onosproject/ui/impl/topo/UiTopoSession.java
+++ b/web/gui/src/main/java/org/onosproject/ui/impl/topo/UiTopoSession.java
@@ -23,6 +23,7 @@
import org.onosproject.ui.impl.topo.model.UiModelListener;
import org.onosproject.ui.impl.topo.model.UiSharedTopologyModel;
import org.onosproject.ui.model.topo.UiClusterMember;
+import org.onosproject.ui.model.topo.UiNode;
import org.onosproject.ui.model.topo.UiRegion;
import org.onosproject.ui.model.topo.UiTopoLayout;
import org.slf4j.Logger;
@@ -170,17 +171,32 @@
}
/**
- * Returns the regions that are "peers" to this region. That is, based on
- * the layout the user is viewing, all the regions that are associated with
- * layouts that share the same parent layout as this layout.
+ * Returns the regions/devices that are "peers" to this region. That is,
+ * based on the layout the user is viewing, all the regions/devices that
+ * are associated with layouts that share the same parent layout as this
+ * layout, AND that are linked to an element within this region.
*
* @param layout the layout being viewed
- * @return all regions that are "siblings" to this layout's region
+ * @return all regions/devices that are "siblings" to this layout's region
*/
- public Set<UiRegion> getPeerRegions(UiTopoLayout layout) {
- Set<UiTopoLayout> peerLayouts = layoutService.getPeers(layout.id());
- Set<UiRegion> peers = new HashSet<>();
- peerLayouts.forEach(l -> peers.add(sharedModel.getRegion(l.regionId())));
+ public Set<UiNode> getPeerNodes(UiTopoLayout layout) {
+ Set<UiNode> peers = new HashSet<>();
+
+ // first, get the peer regions
+ Set<UiTopoLayout> peerLayouts = layoutService.getPeerLayouts(layout.id());
+ peerLayouts.forEach(l -> {
+ RegionId peerRegion = l.regionId();
+ peers.add(sharedModel.getRegion(peerRegion));
+ });
+
+ // now add the devices that reside in the parent region
+ if (!layout.isRoot()) {
+ UiTopoLayout parentLayout = layoutService.getLayout(layout.parent());
+ getRegion(parentLayout).devices().forEach(peers::add);
+ }
+
+ // TODO: Finally, filter out regions / devices that are not connected
+ // directly to this region by an implicit link
return peers;
}
diff --git a/web/gui/src/main/webapp/app/view/topo2/topo2.css b/web/gui/src/main/webapp/app/view/topo2/topo2.css
index 7f878a5..6ec4f02 100644
--- a/web/gui/src/main/webapp/app/view/topo2/topo2.css
+++ b/web/gui/src/main/webapp/app/view/topo2/topo2.css
@@ -25,3 +25,28 @@
/* prevents the little cut/copy/paste square that would appear on iPad */
-webkit-user-select: none;
}
+
+/* -- TEMPORARY CSS (to be deleted) -- */
+#topo2tmp div {
+ padding: 8px 24px;
+ margin: 8px;
+ background-color: #ddddff;
+}
+#topo2tmp div div {
+ padding: 4px 10px;
+}
+
+#topo2tmp h4 {
+ margin: 0
+}
+#topo2tmp p {
+ margin: 0
+}
+#topo2tmp .nav-me:hover {
+ background-color: #bbbbdd;
+}
+#topo2tmp .nav-me {
+ font-weight: bold;
+ text-decoration: underline;
+ cursor: pointer;
+}
diff --git a/web/gui/src/main/webapp/app/view/topo2/topo2.html b/web/gui/src/main/webapp/app/view/topo2/topo2.html
index 9b987a6..1f0c6d6 100644
--- a/web/gui/src/main/webapp/app/view/topo2/topo2.html
+++ b/web/gui/src/main/webapp/app/view/topo2/topo2.html
@@ -1,5 +1,36 @@
<!-- Topology View partial HTML -->
<div id="ov-topo2">
+ <div id="topo2tmp">
+ <div class="parentRegion">
+ Parent Region: <span> - </span>
+ </div>
+ <div class="thisRegion">
+ This Region: <span> - </span>
+ </div>
+ <div class="subRegions">
+ <h4>Subregions</h4>
+ <div></div>
+ </div>
+ <div class="devices">
+ <h4>Devices</h4>
+ <div></div>
+ </div>
+ <div class="hosts">
+ <h4>Hosts</h4>
+ <div></div>
+ </div>
+ <div class="links">
+ <h4>Links</h4>
+ <div></div>
+ </div>
+ <div class="peers">
+ <h4>Peers</h4>
+ <div></div>
+ </div>
+ </div>
+
+ <!-- Below here is good; Above here is temporary, for debugging -->
+
<svg viewBox="0 0 1000 1000"
resize offset-height="56" offset-width="12"
notifier="notifyResize()">
diff --git a/web/gui/src/main/webapp/app/view/topo2/topo2Event.js b/web/gui/src/main/webapp/app/view/topo2/topo2Event.js
index 83dcae2..2d13a5c 100644
--- a/web/gui/src/main/webapp/app/view/topo2/topo2Event.js
+++ b/web/gui/src/main/webapp/app/view/topo2/topo2Event.js
@@ -42,6 +42,7 @@
topo2AllInstances: t2fs,
topo2CurrentLayout: t2fs,
topo2CurrentRegion: t2fs,
+ topo2PeerRegions: t2fs,
topo2StartDone: t2fs
// Add further event names / module references as needed
diff --git a/web/gui/src/main/webapp/app/view/topo2/topo2Force.js b/web/gui/src/main/webapp/app/view/topo2/topo2Force.js
index db6a1c2..254f176 100644
--- a/web/gui/src/main/webapp/app/view/topo2/topo2Force.js
+++ b/web/gui/src/main/webapp/app/view/topo2/topo2Force.js
@@ -35,10 +35,79 @@
$log.debug('Destroy topo force layout');
}
+ // ========================== Temporary Code (to be deleted later)
+
+ function request(dir, rid) {
+ wss.sendEvent('topo2navRegion', {
+ dir: dir,
+ rid: rid
+ });
+ }
+
+ function doTmpCurrentLayout(data) {
+ var topdiv = d3.select('#topo2tmp');
+ var parentRegion = data.parent;
+ var span = topdiv.select('.parentRegion').select('span');
+ span.text(parentRegion || '[no parent]');
+ span.classed('nav-me', !!parentRegion);
+ }
+
+ function doTmpCurrentRegion(data) {
+ var topdiv = d3.select('#topo2tmp');
+ var span = topdiv.select('.thisRegion').select('span');
+ var div;
+
+ span.text(data.id);
+
+ div = topdiv.select('.subRegions').select('div');
+ data.subregions.forEach(function (r) {
+
+ function nav() {
+ request('down', r.id);
+ }
+
+ div.append('p')
+ .classed('nav-me', true)
+ .text(r.id)
+ .on('click', nav);
+ });
+
+ div = topdiv.select('.devices').select('div');
+ data.layerOrder.forEach(function (tag, idx) {
+ var devs = data.devices[idx];
+ devs.forEach(function (d) {
+ div.append('p')
+ .text('[' + tag + '] ' + d.id);
+ });
+
+ });
+
+ div = topdiv.select('.hosts').select('div');
+ data.layerOrder.forEach(function (tag, idx) {
+ var hosts = data.hosts[idx];
+ hosts.forEach(function (h) {
+ div.append('p')
+ .text('[' + tag + '] ' + h.id);
+ });
+ });
+
+ div = topdiv.select('.links').select('div');
+ var links = data.links;
+ links.forEach(function (lnk) {
+ div.append('p')
+ .text(lnk.id);
+ });
+ }
+
+ function doTmpPeerRegions(data) {
+
+ }
+
// ========================== Event Handlers
function allInstances(data) {
$log.debug('>> topo2AllInstances event:', data)
+ doTmpCurrentLayout(data);
}
function currentLayout(data) {
@@ -47,6 +116,16 @@
function currentRegion(data) {
$log.debug('>> topo2CurrentRegion event:', data)
+ doTmpCurrentRegion(data);
+ }
+
+ function topo2PeerRegions(data) {
+ $log.debug('>> topo2PeerRegions event:', data)
+ doTmpPeerRegions(data);
+ }
+
+ function topo2PeerRegions(data) {
+ $log.debug('>> topo2PeerRegions event:', data)
}
function startDone(data) {
@@ -69,6 +148,7 @@
topo2AllInstances: allInstances,
topo2CurrentLayout: currentLayout,
topo2CurrentRegion: currentRegion,
+ topo2PeerRegions: topo2PeerRegions,
topo2StartDone: startDone
};
}]);
diff --git a/web/gui/src/main/webapp/app/view/topoX/topoX-theme.css b/web/gui/src/main/webapp/app/view/topoX/topoX-theme.css
new file mode 100644
index 0000000..af95a40
--- /dev/null
+++ b/web/gui/src/main/webapp/app/view/topoX/topoX-theme.css
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+/*
+ ONOS GUI -- Topology View (theme) -- CSS file
+ */
+
+/* --- Base SVG Layer --- */
+
+#ov-topoX svg {
+ /*background-color: #f4f4f4;*/
+ background-color: goldenrod; /* just for testing */
+}
+
+/* --- "No Devices" Layer --- */
+
+#ov-topoX svg .noDevsBird {
+ fill: #db7773;
+}
+
+#ov-topoX svg #topoX-noDevsLayer text {
+ fill: #7e9aa8;
+}
+
+/* --- Topo Map --- */
+
+#ov-topoX svg #topoX-map {
+ stroke-width: 2px;
+ stroke: #f4f4f4;
+ fill: #e5e5e6;
+}
+
diff --git a/web/gui/src/main/webapp/app/view/topoX/topoX.css b/web/gui/src/main/webapp/app/view/topoX/topoX.css
new file mode 100644
index 0000000..26661b0
--- /dev/null
+++ b/web/gui/src/main/webapp/app/view/topoX/topoX.css
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+/*
+ ONOS GUI -- Topology View (layout) -- CSS file
+ */
+
+/* --- Base SVG Layer --- */
+
+#ov-topoX svg {
+ /* prevents the little cut/copy/paste square that would appear on iPad */
+ -webkit-user-select: none;
+}
+
+/* -- TEMPORARY CSS (to be deleted) -- */
+#topoXtmp div {
+ padding: 8px 24px;
+ margin: 8px;
+ background-color: #ddddff;
+}
+#topoXtmp div div {
+ padding: 4px 10px;
+}
+
+#topoXtmp h4 {
+ margin: 0
+}
+#topoXtmp p {
+ margin: 0
+}
+#topoXtmp .nav-me:hover {
+ background-color: #bbbbdd;
+}
+#topoXtmp .nav-me {
+ font-weight: bold;
+ text-decoration: underline;
+ cursor: pointer;
+}
diff --git a/web/gui/src/main/webapp/app/view/topoX/topoX.html b/web/gui/src/main/webapp/app/view/topoX/topoX.html
new file mode 100644
index 0000000..41a94a5
--- /dev/null
+++ b/web/gui/src/main/webapp/app/view/topoX/topoX.html
@@ -0,0 +1,47 @@
+<!--
+ ~ Copyright 2016-present Open Networking Laboratory
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<!-- Topology View partial HTML -->
+<div id="ov-topoX">
+ <div id="topoXtmp">
+ <div class="parentRegion">
+ Parent Region: <span> - </span>
+ </div>
+ <div class="thisRegion">
+ This Region: <span> - </span>
+ </div>
+ <div class="subRegions">
+ <h4>Subregions</h4>
+ <div></div>
+ </div>
+ <div class="devices">
+ <h4>Devices</h4>
+ <div></div>
+ </div>
+ <div class="hosts">
+ <h4>Hosts</h4>
+ <div></div>
+ </div>
+ <div class="links">
+ <h4>Links</h4>
+ <div></div>
+ </div>
+ <div class="peers">
+ <h4>Peers</h4>
+ <div></div>
+ </div>
+ </div>
+</div>
diff --git a/web/gui/src/main/webapp/app/view/topoX/topoX.js b/web/gui/src/main/webapp/app/view/topoX/topoX.js
new file mode 100644
index 0000000..88114c8
--- /dev/null
+++ b/web/gui/src/main/webapp/app/view/topoX/topoX.js
@@ -0,0 +1,214 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ ONOS GUI -- Topology View Module
+
+ NOTE: currently under development to support Regions.
+ */
+
+(function () {
+ 'use strict';
+
+ // references to injected services
+ var $scope, $log, $loc,
+ fs, mast, ks, zs,
+ gs, ms, sus, flash,
+ wss, ps, th,
+ tXes, tXfs;
+
+ // DOM elements
+ var ovtopoX, svg, defs, zoomLayer, mapG, spriteG, forceG, noDevsLayer;
+
+ // Internal state
+ var zoomer, actionMap;
+
+
+ // === Helper Functions
+
+ // callback invoked when the SVG view has been resized..
+ function svgResized(s) {
+ $log.debug("topoX view resized", s);
+ }
+
+ function setUpKeys(overlayKeys) {
+ $log.debug('topoX: set up keys....');
+ }
+
+ // === Controller Definition -----------------------------------------
+
+ angular.module('ovTopoX', ['onosUtil', 'onosSvg', 'onosRemote'])
+ .controller('OvTopoXCtrl',
+ ['$scope', '$log', '$location',
+ 'FnService', 'MastService', 'KeyService', 'ZoomService',
+ 'GlyphService', 'MapService', 'SvgUtilService', 'FlashService',
+ 'WebSocketService', 'PrefsService', 'ThemeService',
+ 'TopoXEventService', 'TopoXForceService',
+
+ function (_$scope_, _$log_, _$loc_,
+ _fs_, _mast_, _ks_, _zs_,
+ _gs_, _ms_, _sus_, _flash_,
+ _wss_, _ps_, _th_,
+ _tXes_, _tXfs_) {
+
+ var params = _$loc_.search(),
+ projection,
+ dim,
+ wh,
+ uplink = {
+ // provides function calls back into this space
+ // showNoDevs: showNoDevs,
+ // projection: function () { return projection; },
+ // zoomLayer: function () { return zoomLayer; },
+ // zoomer: function () { return zoomer; },
+ // opacifyMap: opacifyMap,
+ // topoStartDone: topoStartDone
+ };
+
+ $scope = _$scope_;
+ $log = _$log_;
+ $loc = _$loc_;
+
+ fs = _fs_;
+ mast = _mast_;
+ ks = _ks_;
+ zs = _zs_;
+
+ gs = _gs_;
+ ms = _ms_;
+ sus = _sus_;
+ flash = _flash_;
+
+ wss = _wss_;
+ ps = _ps_;
+ th = _th_;
+
+ tXes = _tXes_;
+ tXfs = _tXfs_;
+
+ // capture selected intent parameters (if they are set in the
+ // query string) so that the traffic overlay can highlight
+ // the path for that intent
+ if (params.intentKey && params.intentAppId && params.intentAppName) {
+ $scope.intentData = {
+ key: params.intentKey,
+ appId: params.intentAppId,
+ appName: params.intentAppName
+ };
+ }
+
+ $scope.notifyResize = function () {
+ svgResized(fs.windowSize(mast.mastHeight()));
+ };
+
+ // Cleanup on destroyed scope..
+ $scope.$on('$destroy', function () {
+ $log.log('OvTopoXCtrl is saying Buh-Bye!');
+ tXes.stop();
+ ks.unbindKeys();
+ tXfs.destroy();
+ });
+
+ // svg layer and initialization of components
+ ovtopoX = d3.select('#ov-topoX');
+ svg = ovtopoX.select('svg');
+ // set the svg size to match that of the window, less the masthead
+ wh = fs.windowSize(mast.mastHeight());
+ $log.debug('setting topo SVG size to', wh);
+ svg.attr(wh);
+ dim = [wh.width, wh.height];
+
+
+ // set up our keyboard shortcut bindings
+ setUpKeys();
+
+ // make sure we can respond to topology events from the server
+ tXes.bindHandlers();
+
+ // initialize the force layout, ready to render the topology
+ tXfs.init();
+
+
+ // =-=-=-=-=-=-=-=-
+ // TODO: in future, we will load background map data
+ // asynchronously (hence the promise) and then chain off
+ // there to send the topoXstart event to the server.
+ // For now, we'll send the event inline...
+ tXes.start();
+
+
+ // === ORIGINAL CODE ===
+
+ // setUpKeys();
+ // setUpToolbar();
+ // setUpDefs();
+ // setUpZoom();
+ // setUpNoDevs();
+ /*
+ setUpMap().then(
+ function (proj) {
+ var z = ps.getPrefs('topo_zoom', { tx:0, ty:0, sc:1 });
+ zoomer.panZoom([z.tx, z.ty], z.sc);
+ $log.debug('** Zoom restored:', z);
+
+ projection = proj;
+ $log.debug('** We installed the projection:', proj);
+ flash.enable(false);
+ toggleMap(prefsState.bg);
+ flash.enable(true);
+ mapShader(true);
+
+ // now we have the map projection, we are ready for
+ // the server to send us device/host data...
+ tes.start();
+ // need to do the following so we immediately get
+ // the summary panel data back from the server
+ restoreSummaryFromPrefs();
+ }
+ );
+ */
+ // tes.bindHandlers();
+ // setUpSprites();
+
+ // forceG = zoomLayer.append('g').attr('id', 'topo-force');
+ // tfs.initForce(svg, forceG, uplink, dim);
+ // tis.initInst({ showMastership: tfs.showMastership });
+ // tps.initPanels();
+
+ // restoreConfigFromPrefs();
+ // ttbs.setDefaultOverlay(prefsState.ovidx);
+
+ // $log.debug('registered overlays...', tov.list());
+
+ $log.log('OvTopoXCtrl has been created');
+ }]);
+}());
diff --git a/web/gui/src/main/webapp/app/view/topoX/topoXEvent.js b/web/gui/src/main/webapp/app/view/topoX/topoXEvent.js
new file mode 100644
index 0000000..a9f7a99
--- /dev/null
+++ b/web/gui/src/main/webapp/app/view/topoX/topoXEvent.js
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ ONOS GUI -- Topology Event Module.
+
+ Defines the conduit between the client and the server:
+ - provides a clean API for sending events to the server
+ - dispatches incoming events from the server to the appropriate sub-module
+
+ */
+
+(function () {
+ 'use strict';
+
+ // injected refs
+ var $log, wss, tXfs;
+
+ // internal state
+ var handlerMap,
+ openListener;
+
+ // ========================== Helper Functions
+
+ function createHandlerMap() {
+ handlerMap = {
+ topo2AllInstances: tXfs,
+ topo2CurrentLayout: tXfs,
+ topo2CurrentRegion: tXfs,
+ topo2PeerRegions: tXfs,
+ topo2StartDone: tXfs
+
+ // Add further event names / module references as needed
+ };
+ }
+
+ function wsOpen(host, url) {
+ $log.debug('topoXEvent: WSopen - cluster node:', host, 'URL:', url);
+ // tell the server we are ready to receive topo events
+ wss.sendEvent('topo2Start');
+ }
+
+ // bind our event handlers to the web socket service, so that our
+ // callbacks get invoked for incoming events
+ function bindHandlers() {
+ wss.bindHandlers(handlerMap);
+ $log.debug('topoX event handlers bound');
+ }
+
+ // tell the server we are ready to receive topology events
+ function start() {
+ // in case we fail over to a new server,
+ // listen for wsock-open events
+ openListener = wss.addOpenListener(wsOpen);
+ wss.sendEvent('topo2Start');
+ $log.debug('topoX comms started');
+ }
+
+ // tell the server we no longer wish to receive topology events
+ function stop() {
+ wss.sendEvent('topo2Stop');
+ wss.unbindHandlers(handlerMap);
+ wss.removeOpenListener(openListener);
+ openListener = null;
+ $log.debug('topoX comms stopped');
+ }
+
+ // ========================== Main Service Definition
+
+ angular.module('ovTopoX')
+ .factory('TopoXEventService',
+ ['$log', 'WebSocketService', 'TopoXForceService',
+
+ function (_$log_, _wss_, _tXfs_) {
+ $log = _$log_;
+ wss = _wss_;
+ tXfs = _tXfs_;
+
+ // deferred creation of handler map, so module references are good
+ createHandlerMap();
+
+ return {
+ bindHandlers: bindHandlers,
+ start: start,
+ stop: stop
+ };
+ }]);
+}());
diff --git a/web/gui/src/main/webapp/app/view/topoX/topoXForce.js b/web/gui/src/main/webapp/app/view/topoX/topoXForce.js
new file mode 100644
index 0000000..9797a45
--- /dev/null
+++ b/web/gui/src/main/webapp/app/view/topoX/topoXForce.js
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ ONOS GUI -- Topology Force Module.
+ Visualization of the topology in an SVG layer, using a D3 Force Layout.
+ */
+
+(function () {
+ 'use strict';
+
+ // injected refs
+ var $log, wss;
+
+ // ========================== Helper Functions
+
+ function init() {
+ $log.debug('Initialize topo force layout');
+ }
+
+ function destroy() {
+ $log.debug('Destroy topo force layout');
+ }
+
+ // ========================== Temporary Code (to be deleted later)
+
+ function request(dir, rid) {
+ wss.sendEvent('topo2navRegion', {
+ dir: dir,
+ rid: rid
+ });
+ }
+
+ function doTmpCurrentLayout(data) {
+ var topdiv = d3.select('#topoXtmp');
+ var parentRegion = data.parent;
+ var span = topdiv.select('.parentRegion').select('span');
+ span.text(parentRegion || '[no parent]');
+ span.classed('nav-me', !!parentRegion);
+ }
+
+ function doTmpCurrentRegion(data) {
+ var topdiv = d3.select('#topoXtmp');
+ var span = topdiv.select('.thisRegion').select('span');
+ var div;
+
+ span.text(data.id);
+
+ div = topdiv.select('.subRegions').select('div');
+ data.subregions.forEach(function (r) {
+
+ function nav() {
+ request('down', r.id);
+ }
+
+ div.append('p')
+ .classed('nav-me', true)
+ .text(r.id)
+ .on('click', nav);
+ });
+
+ div = topdiv.select('.devices').select('div');
+ data.layerOrder.forEach(function (tag, idx) {
+ var devs = data.devices[idx];
+ devs.forEach(function (d) {
+ div.append('p')
+ .text('[' + tag + '] ' + d.id);
+ });
+
+ });
+
+ div = topdiv.select('.hosts').select('div');
+ data.layerOrder.forEach(function (tag, idx) {
+ var hosts = data.hosts[idx];
+ hosts.forEach(function (h) {
+ div.append('p')
+ .text('[' + tag + '] ' + h.id);
+ });
+ });
+
+ div = topdiv.select('.links').select('div');
+ var links = data.links;
+ links.forEach(function (lnk) {
+ div.append('p')
+ .text(lnk.id);
+ });
+ }
+
+ function doTmpPeerRegions(data) {
+
+ }
+
+ // ========================== Event Handlers
+
+ function allInstances(data) {
+ $log.debug('>> topo2AllInstances event:', data)
+ doTmpCurrentLayout(data);
+ }
+
+ function currentLayout(data) {
+ $log.debug('>> topo2CurrentLayout event:', data)
+ }
+
+ function currentRegion(data) {
+ $log.debug('>> topo2CurrentRegion event:', data)
+ doTmpCurrentRegion(data);
+ }
+
+ function peerRegions(data) {
+ $log.debug('>> topo2PeerRegions event:', data)
+ doTmpPeerRegions(data);
+ }
+
+ function startDone(data) {
+ $log.debug('>> topo2StartDone event:', data)
+ }
+
+ // ========================== Main Service Definition
+
+ angular.module('ovTopoX')
+ .factory('TopoXForceService',
+ ['$log', 'WebSocketService',
+
+ function (_$log_, _wss_) {
+ $log = _$log_;
+ wss = _wss_;
+
+ return {
+ init: init,
+ destroy: destroy,
+ topo2AllInstances: allInstances,
+ topo2CurrentLayout: currentLayout,
+ topo2CurrentRegion: currentRegion,
+ topo2PeerRegions: peerRegions,
+ topo2StartDone: startDone
+ };
+ }]);
+}());
diff --git a/web/gui/src/main/webapp/index.html b/web/gui/src/main/webapp/index.html
index 22865a1..c95597b 100644
--- a/web/gui/src/main/webapp/index.html
+++ b/web/gui/src/main/webapp/index.html
@@ -133,6 +133,12 @@
<link rel="stylesheet" href="app/view/topo2/topo2.css">
<link rel="stylesheet" href="app/view/topo2/topo2-theme.css">
+ <script src="app/view/topoX/topoX.js"></script>
+ <script src="app/view/topoX/topoXEvent.js"></script>
+ <script src="app/view/topoX/topoXForce.js"></script>
+ <link rel="stylesheet" href="app/view/topoX/topoX.css">
+ <link rel="stylesheet" href="app/view/topoX/topoX-theme.css">
+
<!-- Builtin views javascript. -->
<script src="app/view/topo/topo.js"></script>
<script src="app/view/topo/topoD3.js"></script>
diff --git a/web/gui/src/test/_karma/ev/topo2a/ev_3_currentRegion.json b/web/gui/src/test/_karma/ev/topo2a/ev_3_currentRegion.json
index dcf5086..b8b0c8a 100644
--- a/web/gui/src/test/_karma/ev/topo2a/ev_3_currentRegion.json
+++ b/web/gui/src/test/_karma/ev/topo2a/ev_3_currentRegion.json
@@ -4,9 +4,11 @@
"id": "<null-region>",
"subregions": [{
"id": "r2",
+ "nodeType":"region",
"nDevs": 2
}, {
"id": "r1",
+ "nodeType":"region",
"nDevs": 3
}],
"devices": [
@@ -14,6 +16,7 @@
[],
[{
"id": "null:0000000000000001",
+ "nodeType":"device",
"type": "switch",
"online": false,
"master": "",