Thomas Vachuska
Committed by Gerrit Code Review

Removed legacy GUI.

FIxed an NPE in the devices table.
Added cord-gui to obs.exclude

Change-Id: I18a53d2c44c6c97fb7f5d16b7446942a1a37ddca
Showing 34 changed files with 5 additions and 3133 deletions
......@@ -3,3 +3,4 @@
.*/build/conf/.*
.*/docs/.*
.*/openflow/drivers/.*
.*/cord-gui/.*
\ No newline at end of file
......
......@@ -121,6 +121,8 @@ public class DeviceViewMessageHandler extends UiMessageHandler {
boolean available = ds.isAvailable(id);
String iconId = available ? ICON_ID_ONLINE : ICON_ID_OFFLINE;
String protocol = dev.annotations().value(PROTOCOL);
row.cell(ID, id)
.cell(AVAILABLE, available)
.cell(AVAILABLE_IID, iconId)
......@@ -128,7 +130,7 @@ public class DeviceViewMessageHandler extends UiMessageHandler {
.cell(MFR, dev.manufacturer())
.cell(HW, dev.hwVersion())
.cell(SW, dev.swVersion())
.cell(PROTOCOL, dev.annotations().value(PROTOCOL))
.cell(PROTOCOL, protocol != null ? protocol : "")
.cell(NUM_PORTS, ds.getPorts(id).size())
.cell(MASTER_ID, ms.getMasterFor(id));
}
......
/*
* Copyright 2014-2015 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.
*/
package org.onosproject.ui.impl;
import org.eclipse.jetty.websocket.WebSocket;
import org.eclipse.jetty.websocket.WebSocketServlet;
import org.onlab.osgi.DefaultServiceDirectory;
import org.onlab.osgi.ServiceDirectory;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
/**
* Web socket servlet capable of creating various sockets for the user interface.
*/
@Deprecated
public class GuiWebSocketServlet extends WebSocketServlet {
private static final long PING_DELAY_MS = 5000;
private ServiceDirectory directory = new DefaultServiceDirectory();
private final Set<TopologyViewWebSocket> sockets = new HashSet<>();
private final Timer timer = new Timer();
private final TimerTask pruner = new Pruner();
@Override
public void init() throws ServletException {
super.init();
timer.schedule(pruner, PING_DELAY_MS, PING_DELAY_MS);
}
@Override
public WebSocket doWebSocketConnect(HttpServletRequest request, String protocol) {
TopologyViewWebSocket socket = new TopologyViewWebSocket(directory);
synchronized (sockets) {
sockets.add(socket);
}
return socket;
}
// Task for pruning web-sockets that are idle.
private class Pruner extends TimerTask {
@Override
public void run() {
synchronized (sockets) {
Iterator<TopologyViewWebSocket> it = sockets.iterator();
while (it.hasNext()) {
TopologyViewWebSocket socket = it.next();
if (socket.isIdle()) {
it.remove();
socket.close();
}
}
}
}
}
}
......@@ -52,7 +52,7 @@ public class TopologyResource extends BaseResource {
ArrayNode devices = mapper.createArrayNode();
ArrayNode hosts = mapper.createArrayNode();
Map<String, ObjectNode> metaUi = TopologyViewMessages.getMetaUi();
Map<String, ObjectNode> metaUi = TopologyViewMessageHandler.getMetaUi();
for (String id : metaUi.keySet()) {
ObjectNode memento = metaUi.get(id);
if (id.charAt(17) == '/') {
......
......@@ -161,15 +161,4 @@
<url-pattern>/websock/*</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>Legacy Web Socket Service</servlet-name>
<servlet-class>org.onosproject.ui.impl.GuiWebSocketServlet</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Legacy Web Socket Service</servlet-name>
<url-pattern>/ws/*</url-pattern>
</servlet-mapping>
</web-app>
......
/*
* Copyright 2014 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.
*/
/*
Base CSS file
*/
html {
font-family: sans-serif;
-webkit-text-size-adjust: 100%;
-ms-text-size-adjust: 100%;
}
body {
margin: 0;
}
This diff could not be displayed because it is too large.
/*
* Copyright 2014 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.
*/
/*
D3 Utilities CSS file
*/
#d3u .light.norm.c1 {
color: #1f77b4;
}
#d3u .light.norm.c2 {
color: #2ca02c;
}
#d3u .light.norm.c3 {
color: #d62728;
}
#d3u .light.norm.c4 {
color: #9467bd;
}
#d3u .light.norm.c5 {
color: #e377c2;
}
#d3u .light.norm.c6 {
color: #bcbd22;
}
#d3u .light.norm.c7 {
color: #17becf;
}
#d3u .light.mute.c1 {
color: #aec7e8;
}
#d3u .light.mute.c2 {
color: #98df8a;
}
#d3u .light.mute.c3 {
color: #ff9896;
}
#d3u .light.mute.c4 {
color: #c5b0d5;
}
#d3u .light.mute.c5 {
color: #f7b6d2;
}
#d3u .light.mute.c6 {
color: #dbdb8d;
}
#d3u .light.mute.c7 {
color: #9edae5;
}
#d3u .dark.norm.c1 {
color: #1f77b4;
}
#d3u .dark.norm.c2 {
color: #2ca02c;
}
#d3u .dark.norm.c3 {
color: #d62728;
}
#d3u .dark.norm.c4 {
color: #9467bd;
}
#d3u .dark.norm.c5 {
color: #e377c2;
}
#d3u .dark.norm.c6 {
color: #bcbd22;
}
#d3u .dark.norm.c7 {
color: #17becf;
}
#d3u .dark.mute.c1 {
color: #aec7e8;
}
#d3u .dark.mute.c2 {
color: #639a56;
}
#d3u .dark.mute.c3 {
color: #ff9896;
}
#d3u .dark.mute.c4 {
color: #c5b0d5;
}
#d3u .dark.mute.c5 {
color: #f7b6d2;
}
#d3u .dark.mute.c6 {
color: #dbdb8d;
}
#d3u .dark.mute.c7 {
color: #9edae5;
}
/*
* Copyright 2014 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.
*/
/*
Utility functions for D3 visualizations.
*/
(function (onos) {
'use strict';
function isF(f) {
return $.isFunction(f) ? f : null;
}
// TODO: sensible defaults
function createDragBehavior(force, selectCb, atDragEnd,
dragEnabled, clickEnabled) {
var draggedThreshold = d3.scale.linear()
.domain([0, 0.1])
.range([5, 20])
.clamp(true),
drag,
fSel = isF(selectCb),
fEnd = isF(atDragEnd),
fDEn = isF(dragEnabled),
fCEn = isF(clickEnabled),
bad = [];
function naf(what) {
return 'd3util.createDragBehavior(): '+ what + ' is not a function';
}
if (!fSel) {
bad.push(naf('selectCb'));
}
if (!fEnd) {
bad.push(naf('atDragEnd'));
}
if (!fDEn) {
bad.push(naf('dragEnabled'));
}
if (!fCEn) {
bad.push(naf('clickEnabled'));
}
if (bad.length) {
alert(bad.join('\n'));
return null;
}
function dragged(d) {
var threshold = draggedThreshold(force.alpha()),
dx = d.oldX - d.px,
dy = d.oldY - d.py;
if (Math.abs(dx) >= threshold || Math.abs(dy) >= threshold) {
d.dragged = true;
}
return d.dragged;
}
drag = d3.behavior.drag()
.origin(function(d) { return d; })
.on('dragstart', function(d) {
if (clickEnabled() || dragEnabled()) {
d3.event.sourceEvent.stopPropagation();
d.oldX = d.x;
d.oldY = d.y;
d.dragged = false;
d.fixed |= 2;
d.dragStarted = true;
}
})
.on('drag', function(d) {
if (dragEnabled()) {
d.px = d3.event.x;
d.py = d3.event.y;
if (dragged(d)) {
if (!force.alpha()) {
force.alpha(.025);
}
}
}
})
.on('dragend', function(d) {
if (d.dragStarted) {
d.dragStarted = false;
if (!dragged(d)) {
// consider this the same as a 'click'
// (selection of a node)
if (clickEnabled()) {
selectCb(d, this); // TODO: set 'this' context instead of param
}
}
d.fixed &= ~6;
// hook at the end of a drag gesture
if (dragEnabled()) {
atDragEnd(d, this); // TODO: set 'this' context instead of param
}
}
});
return drag;
}
function loadGlow(defs) {
// TODO: parameterize color
var glow = defs.append('filter')
.attr('x', '-50%')
.attr('y', '-50%')
.attr('width', '200%')
.attr('height', '200%')
.attr('id', 'blue-glow');
glow.append('feColorMatrix')
.attr('type', 'matrix')
.attr('values',
'0 0 0 0 0 ' +
'0 0 0 0 0 ' +
'0 0 0 0 .7 ' +
'0 0 0 1 0 ');
glow.append('feGaussianBlur')
.attr('stdDeviation', 3)
.attr('result', 'coloredBlur');
glow.append('feMerge').selectAll('feMergeNode')
.data(['coloredBlur', 'SourceGraphic'])
.enter().append('feMergeNode')
.attr('in', String);
}
// --- Ordinal scales for 7 values.
// TODO: tune colors for light and dark themes
// Note: These colors look good on the white background. Still, need to tune for dark.
// blue brown brick red sea green purple dark teal lime
var lightNorm = ['#3E5780', '#78533B', '#CB4D28', '#018D61', '#8A2979', '#006D73', '#56AF00'],
lightMute = ['#A8B8CC', '#CCB3A8', '#FFC2BD', '#96D6BF', '#D19FCE', '#8FCCCA', '#CAEAA4'],
darkNorm = ['#3E5780', '#78533B', '#CB4D28', '#018D61', '#8A2979', '#006D73', '#56AF00'],
darkMute = ['#A8B8CC', '#CCB3A8', '#FFC2BD', '#96D6BF', '#D19FCE', '#8FCCCA', '#CAEAA4'];
function cat7() {
var colors = {
light: {
norm: d3.scale.ordinal().range(lightNorm),
mute: d3.scale.ordinal().range(lightMute)
},
dark: {
norm: d3.scale.ordinal().range(darkNorm),
mute: d3.scale.ordinal().range(darkMute)
}
},
tcid = 'd3utilTestCard';
function get(id, muted, theme) {
// NOTE: since we are lazily assigning domain ids, we need to
// get the color from all 4 scales, to keep the domains
// in sync.
var ln = colors.light.norm(id),
lm = colors.light.mute(id),
dn = colors.dark.norm(id),
dm = colors.dark.mute(id);
if (theme === 'dark') {
return muted ? dm : dn;
} else {
return muted ? lm : ln;
}
}
function testCard(svg) {
var g = svg.select('g#' + tcid),
dom = d3.range(7),
k, muted, theme, what;
if (!g.empty()) {
g.remove();
} else {
g = svg.append('g')
.attr('id', tcid)
.attr('transform', 'scale(4)translate(20,20)');
for (k=0; k<4; k++) {
muted = k%2;
what = muted ? ' muted' : ' normal';
theme = k < 2 ? 'light' : 'dark';
dom.forEach(function (id, i) {
var x = i * 20,
y = k * 20,
f = get(id, muted, theme);
g.append('circle').attr({
cx: x,
cy: y,
r: 5,
fill: f
});
});
g.append('rect').attr({
x: 140,
y: k * 20 - 5,
width: 32,
height: 10,
rx: 2,
fill: '#888'
});
g.append('text').text(theme + what)
.attr({
x: 142,
y: k * 20 + 2,
fill: 'white'
})
.style('font-size', '4pt');
}
}
}
return {
testCard: testCard,
get: get
};
}
// === register the functions as a library
onos.ui.addLib('d3util', {
createDragBehavior: createDragBehavior,
loadGlow: loadGlow,
cat7: cat7
});
}(ONOS));
/*
* Copyright 2014 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.
*/
/*
Geometry library - based on work by Mike Bostock.
*/
(function() {
if (typeof geo == 'undefined') {
geo = {};
}
var tolerance = 1e-10;
function eq(a, b) {
return (Math.abs(a - b) < tolerance);
}
function gt(a, b) {
return (a - b > -tolerance);
}
function lt(a, b) {
return gt(b, a);
}
geo.eq = eq;
geo.gt = gt;
geo.lt = lt;
geo.LineSegment = function(x1, y1, x2, y2) {
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
// Ax + By = C
this.a = y2 - y1;
this.b = x1 - x2;
this.c = x1 * this.a + y1 * this.b;
if (eq(this.a, 0) && eq(this.b, 0)) {
throw new Error(
'Cannot construct a LineSegment with two equal endpoints.');
}
};
geo.LineSegment.prototype.intersect = function(that) {
var d = (this.x1 - this.x2) * (that.y1 - that.y2) -
(this.y1 - this.y2) * (that.x1 - that.x2);
if (eq(d, 0)) {
// The two lines are parallel or very close.
return {
x : NaN,
y : NaN
};
}
var t1 = this.x1 * this.y2 - this.y1 * this.x2,
t2 = that.x1 * that.y2 - that.y1 * that.x2,
x = (t1 * (that.x1 - that.x2) - t2 * (this.x1 - this.x2)) / d,
y = (t1 * (that.y1 - that.y2) - t2 * (this.y1 - this.y2)) / d,
in1 = (gt(x, Math.min(this.x1, this.x2)) && lt(x, Math.max(this.x1, this.x2)) &&
gt(y, Math.min(this.y1, this.y2)) && lt(y, Math.max(this.y1, this.y2))),
in2 = (gt(x, Math.min(that.x1, that.x2)) && lt(x, Math.max(that.x1, that.x2)) &&
gt(y, Math.min(that.y1, that.y2)) && lt(y, Math.max(that.y1, that.y2)));
return {
x : x,
y : y,
in1 : in1,
in2 : in2
};
};
geo.LineSegment.prototype.x = function(y) {
// x = (C - By) / a;
if (this.a) {
return (this.c - this.b * y) / this.a;
} else {
// a == 0 -> horizontal line
return NaN;
}
};
geo.LineSegment.prototype.y = function(x) {
// y = (C - Ax) / b;
if (this.b) {
return (this.c - this.a * x) / this.b;
} else {
// b == 0 -> vertical line
return NaN;
}
};
geo.LineSegment.prototype.length = function() {
return Math.sqrt(
(this.y2 - this.y1) * (this.y2 - this.y1) +
(this.x2 - this.x1) * (this.x2 - this.x1));
};
geo.LineSegment.prototype.offset = function(x, y) {
return new geo.LineSegment(
this.x1 + x, this.y1 + y,
this.x2 + x, this.y2 + y);
};
})();
/*
* Copyright 2014 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 -- SVG Glyphs Library.
*/
(function (onos) {
'use strict';
var birdViewBox = '352 224 113 112',
birdData = {
bird: "M427.7,300.4 c-6.9,0.6-13.1,5-19.2,7.1c-18.1,6.2-33.9," +
"9.1-56.5,4.7c24.6,17.2,36.6,13,63.7,0.1c-0.5,0.6-0.7,1.3-1.3," +
"1.9c1.4-0.4,2.4-1.7,3.4-2.2c-0.4,0.7-0.9,1.5-1.4,1.9c2.2-0.6," +
"3.7-2.3,5.9-3.9c-2.4,2.1-4.2,5-6,8c-1.5,2.5-3.1,4.8-5.1,6.9c-1," +
"1-1.9,1.9-2.9,2.9c-1.4,1.3-2.9,2.5-5.1,2.9c1.7,0.1,3.6-0.3,6.5" +
"-1.9c-1.6,2.4-7.1,6.2-9.9,7.2c10.5-2.6,19.2-15.9,25.7-18c18.3" +
"-5.9,13.8-3.4,27-14.2c1.6-1.3,3-1,5.1-0.8c1.1,0.1,2.1,0.3,3.2," +
"0.5c0.8,0.2,1.4,0.4,2.2,0.8l1.8,0.9c-1.9-4.5-2.3-4.1-5.9-6c-2.3" +
"-1.3-3.3-3.8-6.2-4.9c-7.1-2.6-11.9,11.7-11.7-5c0.1-8,4.2-14.4," +
"6.4-22c1.1-3.8,2.3-7.6,2.4-11.5c0.1-2.3,0-4.7-0.4-7c-2-11.2-8.4" +
"-21.5-19.7-24.8c-1-0.3-1.1-0.3-0.9,0c9.6,17.1,7.2,38.3,3.1,54.2" +
"C429.9,285.5,426.7,293.2,427.7,300.4z"
},
glyphViewBox = '0 0 110 110',
glyphData = {
unknown: "M35,40a5,5,0,0,1,5-5h30a5,5,0,0,1,5,5v30a5,5,0,0,1-5,5" +
"h-30a5,5,0,0,1-5-5z",
node: "M15,100a5,5,0,0,1-5-5v-65a5,5,0,0,1,5-5h80a5,5,0,0,1,5,5" +
"v65a5,5,0,0,1-5,5zM14,22.5l11-11a10,3,0,0,1,10-2h40a10,3,0,0,1," +
"10,2l11,11zM16,35a5,5,0,0,1,10,0a5,5,0,0,1-10,0z",
switch: "M10,20a10,10,0,0,1,10-10h70a10,10,0,0,1,10,10v70a10,10," +
"0,0,1-10,10h-70a10,10,0,0,1-10-10zM60,26l12,0,0-8,18,13-18,13,0" +
"-8-12,0zM60,60l12,0,0-8,18,13-18,13,0-8-12,0zM50,40l-12,0,0-8" +
"-18,13,18,13,0-8,12,0zM50,74l-12,0,0-8-18,13,18,13,0-8,12,0z",
roadm: "M10,35l25-25h40l25,25v40l-25,25h-40l-25-25zM58,26l12,0,0" +
"-8,18,13-18,13,0-8-12,0zM58,60l12,0,0-8,18,13-18,13,0-8-12,0z" +
"M52,40l-12,0,0-8-18,13,18,13,0-8,12,0zM52,74l-12,0,0-8-18,13," +
"18,13,0-8,12,0z",
endstation: "M10,15a5,5,0,0,1,5-5h65a5,5,0,0,1,5,5v80a5,5,0,0,1" +
"-5,5h-65a5,5,0,0,1-5-5zM87.5,14l11,11a3,10,0,0,1,2,10v40a3,10," +
"0,0,1,-2,10l-11,11zM17,19a2,2,0,0,1,2-2h56a2,2,0,0,1,2,2v26a2," +
"2,0,0,1-2,2h-56a2,2,0,0,1-2-2zM20,20h54v10h-54zM20,33h54v10h" +
"-54zM42,70a5,5,0,0,1,10,0a5,5,0,0,1-10,0z",
router: "M10,55A45,45,0,0,1,100,55A45,45,0,0,1,10,55M20,50l12,0," +
"0-8,18,13-18,13,0-8-12,0zM90,50l-12,0,0-8-18,13,18,13,0-8,12,0z" +
"M50,47l0-12-8,0,13-18,13,18-8,0,0,12zM50,63l0,12-8,0,13,18,13" +
"-18-8,0,0-12z",
bgpSpeaker: "M10,40a45,35,0,0,1,90,0Q100,77,55,100Q10,77,10,40z" +
"M50,29l12,0,0-8,18,13-18,13,0-8-12,0zM60,57l-12,0,0-8-18,13," +
"18,13,0-8,12,0z",
chain: "M60.4,77.6c-4.9,5.2-9.6,11.3-15.3,16.3c-8.6,7.5-20.4,6.8" +
"-28-0.8c-7.7-7.7-8.4-19.6-0.8-28.4c6.5-7.4,13.5-14.4,20.9-20.9" +
"c7.5-6.7,19.2-6.7,26.5-0.8c3.5,2.8,4.4,6.1,2.2,8.7c-2.7,3.1" +
"-5.5,2.5-8.5,0.3c-4.7-3.4-9.7-3.2-14,0.9C37.1,58.7,31,64.8," +
"25.2,71c-4.2,4.4-4.2,10.6-0.6,14.3c3.7,3.7,9.7,3.7,14.3-0.4" +
"c2.9-2.5,5.3-5.5,8.3-8c1-0.9,3-1.1,4.4-0.9C54.8,76.3,57.9,77.1," +
"60.4,77.6zM49.2,32.2c5-5.2,9.7-10.9,15.2-15.7c12.8-11,31.2" +
"-4.9,34.3,11.2C100,34.2,98.3,40.2,94,45c-6.7,7.4-13.7,14.6" +
"-21.2,21.2C65.1,73,53.2,72.7,46,66.5c-3.2-2.8-3.9-5.8-1.6-8.4" +
"c2.6-2.9,5.3-2.4,8.2-0.3c5.2,3.7,10,3.3,14.7-1.1c5.8-5.6,11.6" +
"-11.3,17.2-17.2c4.6-4.8,4.9-11.1,0.9-15c-3.9-3.9-10.1-3.4-15," +
"1.2c-3.1,2.9-5.7,7.4-9.3,8.5C57.6,35.3,53,33,49.2,32.2z",
crown: "M99.5,21.6c0,3-2.3,5.4-5.1,5.4c-0.3,0-0.7,0-1-0.1c-1.8," +
"4-4.8,10-7.2,17.3c-3.4,10.6-0.9,26.2,2.7,27.3C90.4,72,91.3," +
"75,88,75H22.7c-3.3,0-2.4-3-0.9-3.5c3.6-1.1,6.1-16.7,2.7-27.3" +
"c-2.4-7.4-5.4-13.5-7.2-17.5c-0.5,0.2-1,0.3-1.6,0.3c-2.8,0" +
"-5.1-2.4-5.1-5.4c0-3,2.3-5.4,5.1-5.4c2.8,0,5.1,2.4,5.1,5.4c0," +
"1-0.2,1.9-0.7,2.7c0.7,0.8,1.4,1.6,2.4,2.6c8.8,8.9,11.9,12.7," +
"18.1,11.7c6.5-1,11-8.2,13.3-14.1c-2-0.8-3.3-2.7-3.3-5.1c0-3," +
"2.3-5.4,5.1-5.4c2.8,0,5.1,2.4,5.1,5.4c0,2.5-1.6,4.5-3.7,5.2" +
"c2.3,5.9,6.8,13,13.2,14c6.2,1,9.3-2.7,18.1-11.7c0.7-0.7,1.4" +
"-1.5,2-2.1c-0.6-0.9-1-2-1-3.1c0-3,2.3-5.4,5.1-5.4C97.2,16.2," +
"99.5,18.6,99.5,21.6zM92,87.9c0,2.2-1.7,4.1-3.8,4.1H22.4c" +
"-2.1,0-4.4-1.9-4.4-4.1v-3.3c0-2.2,2.3-4.5,4.4-4.5h65.8c2.1," +
"0,3.8,2.3,3.8,4.5V87.9z"
},
badgeViewBox = '0 0 10 10',
badgeData = {
uiAttached: "M2,2.5a.5,.5,0,0,1,.5-.5h5a.5,.5,0,0,1,.5,.5v3" +
"a.5,.5,0,0,1-.5,.5h-5a.5,.5,0,0,1-.5-.5zM2.5,2.8a.3,.3,0,0,1," +
".3-.3h4.4a.3,.3,0,0,1,.3,.3v2.4a.3,.3,0,0,1-.3,.3h-4.4" +
"a.3,.3,0,0,1-.3-.3zM2,6.55h6l1,1.45h-8z"
};
function defStuff(defs, viewbox, data) {
d3.map(data).keys().forEach(function (key) {
defs.append('symbol')
.attr({ id: key, viewBox: viewbox })
.append('path').attr('d', data[key]);
});
}
function loadDefs(defs) {
defStuff(defs, birdViewBox, birdData);
defStuff(defs, glyphViewBox, glyphData);
defStuff(defs, badgeViewBox, badgeData);
}
onos.ui.addLib('glyphs', {
loadDefs: loadDefs
});
}(ONOS));
<!DOCTYPE html>
<!--
~ Copyright 2014 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 UI - single page web app
Version 1.1
-->
<html>
<head>
<meta charset="utf-8">
<link rel="shortcut icon" href="../img/onos-logo.png">
<title>ONOS</title>
<!-- Third party library code included here -->
<!--TODO: use the minified version of d3, once debugging is complete -->
<script src="../tp/d3.js"></script>
<script src="../tp/topojson.v1.min.js"></script>
<script src="../tp/jquery-2.1.1.min.js"></script>
<!-- ONOS UI Framework included here -->
<script src="onos.js"></script>
<!-- Framework and library stylesheets included here -->
<link rel="stylesheet" href="base.css">
<link rel="stylesheet" href="onos.css">
<link rel="stylesheet" href="onosMast.css">
<link rel="stylesheet" href="onosFloatPanel.css">
<link rel="stylesheet" href="onosFlash.css">
<link rel="stylesheet" href="onosQuickHelp.css">
<!-- This is where contributed stylesheets get INJECTED -->
<!-- TODO: replace with template marker and inject refs server-side -->
<link rel="stylesheet" href="topo.css">
</head>
<body>
<div id="frame">
<div id="mast">
<!-- NOTE: masthead injected here by mast.js -->
</div>
<div id="view">
<!-- NOTE: views injected here by onos.js -->
</div>
<div id="floatPanels">
<!-- NOTE: floating panels injected here, as needed -->
<!-- see onos.ui.addFloatingPanel -->
</div>
<div id="alerts">
<!-- NOTE: alert content injected here, as needed -->
</div>
<div id="feedback">
<!-- NOTE: feedback flashes to user -->
</div>
<div id="quickhelp">
<!-- NOTE: key bindings and mouse gesture help -->
</div>
</div>
<!-- Initialize the UI...-->
<script type="text/javascript">
var ONOS = $.onos({
comment: 'configuration options',
theme: 'dark',
startVid: 'topo'
});
</script>
<!-- Library modules included here -->
<script src="d3Utils.js"></script>
<script src="geometry.js"></script>
<script src="glyphs.js"></script>
<!-- Framework modules included here -->
<script src="onosMast.js"></script>
<script src="onosFlash.js"></script>
<script src="onosQuickHelp.js"></script>
<!-- View Module Templates; REMOVE THESE LINES, FOR PRODUCTION -->
<script src="module-svg-template.js"></script>
<script src="module-div-template.js"></script>
<!-- Sample Views; REMOVE THESE LINES, FOR PRODUCTION -->
<script src="sample.js"></script>
<script src="sampleRadio.js"></script>
<script src="sampleKeys.js"></script>
<script src="sampleHash.js"></script>
<!-- Contributed (application) views injected here -->
<!-- TODO: replace with template marker and inject refs server-side -->
<script src="topo.js"></script>
<!-- finally, build the UI-->
<script type="text/javascript">
$(ONOS.buildUi);
</script>
</body>
</html>
/*
* Copyright 2014 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.
*/
/*
Module template file for DIV based view.
*/
(function (onos) {
'use strict';
var list,
data = [ 'foo', 'bar', 'baz' ];
// invoked only the first time the view is loaded
// - used to initialize the view contents
function init(view, ctx, flags) {
// NOTE: view.$div is a D3 selection of the view's div
list = view.$div.append('ul');
// ... further code to initialize the SVG view ...
}
// invoked just prior to loading the view
// - used to clear the view of stale data
function reset(view, ctx, flags) {
}
// invoked when the view is loaded
// - used to load data into the view,
// when the view is shown
function load(view, ctx, flags) {
list.selectAll('li')
.data(data)
.enter()
.append('li')
.text(function (d) { return d; })
}
// invoked when the view is unloaded
// - used to clean up data that should be removed,
// when the view is hidden
function unload(view, ctx, flags) {
}
// invoked when the view is resized
// - used to reconfigure elements to the new view size
function resize(view, ctx, flags) {
var w = view.width(),
h = view.height();
}
// invoked when the framework needs to alert the view of an error
// - (EXPERIMENTAL -- not currently used)
function error(view, ctx, flags) {
}
// ================================================================
// == register the view here, with links to lifecycle callbacks
// A typical setup that initializes the view once, then reacts to
// load and resize events would look like this:
onos.ui.addView('myDivViewId', {
init: init,
load: load,
resize: resize
});
// A minimum setup that builds the view every time it is loaded
// would look like this:
//
// onos.ui.addView('myViewId', {
// reset: true, // clear view contents on reset
// load: load
// });
// The complete gamut of callbacks would look like this:
//
// onos.ui.addView('myViewId', {
// init: init,
// reset: reset,
// load: load,
// unload: unload,
// resize: resize,
// error: error
// });
}(ONOS));
/*
* Copyright 2014 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.
*/
/*
Module template file for SVG based view.
*/
(function (onos) {
'use strict';
var svg,
data = [ 60 ];
// invoked only the first time the view is loaded
// - used to initialize the view contents
function init(view, ctx, flags) {
svg = view.$div.append('svg');
resize(view);
// ... further code to initialize the SVG view ...
}
// invoked just prior to loading the view
// - used to clear the view of stale data
function reset(view, ctx, flags) {
// e.g. clear svg of all objects...
// svg.html('');
}
// invoked when the view is loaded
// - used to load data into the view,
// when the view is shown
function load(view, ctx, flags) {
var w = view.width(),
h = view.height();
// as an example...
svg.selectAll('circle')
.data(data)
.enter()
.append('circle')
.attr({
cx: w / 2,
cy: h / 2,
r: function (d) { return d; }
})
.style({
fill: 'goldenrod',
stroke: 'black',
'stroke-width': 3.5,
});
}
// invoked when the view is unloaded
// - used to clean up data that should be removed,
// when the view is hidden
function unload(view, ctx, flags) {
}
// invoked when the view is resized
// - used to reconfigure elements to the new size of the view
function resize(view, ctx, flags) {
var w = view.width(),
h = view.height();
// resize svg layer to match new size of view
svg.attr({
width: w,
height: h
});
// as an example...
svg.selectAll('circle')
.attr({
cx: w / 2,
cy: h / 2
});
// ... further code to handle resize of view ...
}
// invoked when the framework needs to alert the view of an error
// - (EXPERIMENTAL -- not currently used)
function error(view, ctx, flags) {
}
// ================================================================
// == register the view here, with links to lifecycle callbacks
// A typical setup that initializes the view once, then reacts to
// load and resize events would look like this:
onos.ui.addView('mySvgViewId', {
init: init,
load: load,
resize: resize
});
// A minimum setup that builds the view every time it is loaded
// would look like this:
//
// onos.ui.addView('myViewId', {
// reset: true, // clear view contents on reset
// load: load
// });
// The complete gamut of callbacks would look like this:
//
// onos.ui.addView('myViewId', {
// init: init,
// reset: reset,
// load: load,
// unload: unload,
// resize: resize,
// error: error
// });
}(ONOS));
/*
* Copyright 2014 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 -- Base Framework -- CSS file
*/
html, body {
height: 100%;
}
/* This is to ensure that the body does not expand to account for the
flyout details pane, that is positioned "off screen".
*/
body {
overflow: hidden;
}
#frame {
width: 100%;
height: 100%;
background-color: #fff;
}
div.onosView {
display: none;
}
div.onosView.currentView {
display: block;
}
#alerts {
display: none;
position: absolute;
z-index: 1200;
opacity: 0.65;
background-color: #006;
color: white;
top: 80px;
left: 40px;
padding: 3px 6px;
-moz-border-radius: 6px;
border-radius: 6px;
box-shadow: 0px 2px 12px #777;
}
#alerts pre {
margin: 0.2em 6px;
}
#alerts span.close {
color: #6af;
float: right;
right: 2px;
cursor: pointer;
}
#alerts span.close:hover {
color: #fff;
}
#alerts p.footnote {
text-align: right;
font-size: 8pt;
margin: 8px 0 0 0;
color: #66d;
}
#floatPanels {
z-index: 1100;
}
#flyout {
position: absolute;
display: block;
top: 10%;
width: 280px;
right: -300px;
opacity: 0;
background-color: rgba(255,255,255,0.8);
padding: 10px;
color: black;
font-size: 10pt;
box-shadow: 2px 2px 16px #777;
}
#flyout h2 {
margin: 8px 4px;
color: black;
vertical-align: middle;
}
#flyout h2 img {
height: 32px;
padding-right: 8px;
vertical-align: middle;
}
#flyout p, table {
margin: 4px 4px;
}
#flyout td.label {
font-style: italic;
color: #777;
padding-right: 12px;
}
#flyout td.value {
}
#flyout hr {
height: 1px;
color: #ccc;
background-color: #ccc;
border: 0;
}
This diff is collapsed. Click to expand it.
/*
* Copyright 2014 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 -- Feedback layer -- CSS file
*/
#feedback {
z-index: 1400;
}
#feedback svg {
position: absolute;
bottom: 0;
opacity: 0.8;
}
#feedback svg g.feedbackItem {
background-color: teal;
}
#feedback svg g.feedbackItem rect {
fill: #ccc;
}
#feedback svg g.feedbackItem text {
fill: #333;
stroke: none;
text-anchor: middle;
alignment-baseline: middle;
font-size: 16pt;
}
/*
* Copyright 2014 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 -- Feedback layer
Defines the feedback layer for the UI. Used to give user visual feedback
of choices, typically responding to keystrokes.
*/
(function (onos){
'use strict';
// API's
var api = onos.api;
// Config variables
var w = '100%',
h = 200,
fade = 200,
showFor = 1200,
vb = '-200 -' + (h/2) + ' 400 ' + h,
xpad = 20,
ypad = 10;
// State variables
var timer = null,
data = [];
// DOM elements and the like
var fb = d3.select('#feedback');
var svg;
//var svg = fb.append('svg').attr({
// width: w,
// height: h,
// viewBox: vb
//});
function computeBox(el) {
var text = el.select('text'),
box = text.node().getBBox();
// center
box.x = -box.width / 2;
box.y = -box.height / 2;
// add some padding
box.x -= xpad;
box.width += xpad * 2;
box.y -= ypad;
box.height += ypad * 2;
return box;
}
function updateFeedback() {
if (!svg) {
svg = fb.append('svg').attr({
width: w,
height: h,
viewBox: vb
});
}
var items = svg.selectAll('.feedbackItem')
.data(data);
var entering = items.enter()
.append('g')
.attr({
class: 'feedbackItem',
opacity: 0
})
.transition()
.duration(fade)
.attr('opacity', 1);
entering.each(function (d) {
var el = d3.select(this),
box;
d.el = el;
el.append('rect').attr({ rx: 10, ry: 10});
el.append('text').text(d.label);
box = computeBox(el);
el.select('rect').attr(box);
});
items.exit()
.transition()
.duration(fade)
.attr({ opacity: 0})
.remove();
if (svg && data.length === 0) {
svg.transition()
.delay(fade + 10)
.remove();
svg = null;
}
}
function clearFlash() {
if (timer) {
clearInterval(timer);
}
data = [];
updateFeedback();
}
// for now, simply display some text feedback
function flash(text) {
// cancel old scheduled event if there was one
if (timer) {
clearInterval(timer);
}
timer = setInterval(function () {
clearFlash();
}, showFor);
data = [{
label: text
}];
updateFeedback();
}
onos.ui.addLib('feedback', {
flash: flash
});
}(ONOS));
/*
* Copyright 2014 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 -- Floating Panels -- CSS file
*/
.fpanel {
position: absolute;
z-index: 100;
display: block;
top: 64px;
width: 260px;
right: -300px;
opacity: 0;
background-color: rgba(255,255,255,0.8);
padding: 10px;
color: black;
font-size: 10pt;
-moz-border-radius: 6px;
border-radius: 6px;
box-shadow: 0px 2px 12px #777;
}
/* TODO: light/dark themes */
.light .fpanel {
}
.dark .fpanel {
}
/*
* Copyright 2014 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 -- Masthead -- CSS file
*/
#mast {
height: 36px;
padding: 4px;
vertical-align: baseline;
}
.light #mast {
background-color: #bbb;
box-shadow: 0 2px 8px #777;
}
.dark #mast {
background-color: #444;
box-shadow: 0 2px 8px #777;
}
#mast img#logo {
height: 38px;
padding-left: 8px;
padding-right: 8px;
}
#mast span.title {
font-size: 14pt;
font-style: italic;
vertical-align: 12px;
}
.light #mast span.title {
color: #369;
}
.dark #mast span.title {
color: #eee;
}
#mast span.right {
padding-top: 8px;
padding-right: 16px;
float: right;
}
#mast span.radio {
font-size: 10pt;
margin: 4px 2px;
padding: 1px 6px;
-moz-border-radius: 3px;
border-radius: 3px;
cursor: pointer;
}
.light #mast span.radio {
border: 1px dotted #222;
color: #eee;
}
.dark #mast span.radio {
border: 1px dotted #bbb;
color: #888;
}
#mast span.radio.active {
padding: 1px 6px;
}
.light #mast span.radio.active {
background-color: #bbb;
border: 1px solid #eee;
color: #666;
}
.dark #mast span.radio.active {
background-color: #222;
border: 1px solid #eee;
color: #78a;
}
/* Button Bar */
#bb {
margin: 0 30px;
padding: 0 2px;
}
#bb .btn {
margin: 0 4px;
padding: 2px 6px;
-moz-border-radius: 3px;
border-radius: 3px;
font-size: 9pt;
cursor: pointer;
}
.light #bb .btn {
border: 1px solid #fff;
border-right-color: #444;
border-bottom-color: #444;
color: #222;
}
.light #bb .btn.active {
border: 1px solid #444;
border-right-color: #fff;
border-bottom-color: #fff;
background-color: #888;
color: #ddf;
}
.dark #bb .btn {
border: 1px solid #888;
border-right-color: #111;
border-bottom-color: #111;
color: #888;
}
.dark #bb .btn.active {
border: 1px solid #111;
border-right-color: #888;
border-bottom-color: #888;
background-color: #555;
color: #78a;
}
/*
* Copyright 2014 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 -- Masthead script
Defines the masthead for the UI. Injects logo and title, as well as providing
the placeholder for a set of radio buttons.
*/
(function (onos){
'use strict';
// API's
var api = onos.api;
// Config variables
var guiTitle = 'Open Network Operating System';
// DOM elements and the like
var mast = d3.select('#mast');
mast.append('img')
.attr({
id: 'logo',
src: 'onos-logo.png'
});
mast.append('span')
.attr({
class: 'title'
})
.text(guiTitle);
mast.append('span')
.attr({
id: 'mastRadio',
class: 'right'
});
}(ONOS));
/*
* Copyright 2014 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 -- Quick Help layer -- CSS file
*/
#quickhelp {
z-index: 1300;
}
#quickhelp svg {
position: absolute;
top: 180px;
opacity: 1;
}
#quickhelp svg g.help rect {
fill: black;
opacity: 0.7;
}
#quickhelp svg text.title {
font-size: 10pt;
font-style: italic;
text-anchor: middle;
fill: #999;
}
#quickhelp svg g.keyItem {
fill: white;
}
#quickhelp svg g line.qhrowsep {
stroke: #888;
stroke-dasharray: 2 2;
}
#quickhelp svg text {
font-size: 7pt;
alignment-baseline: middle;
}
#quickhelp svg text.key {
fill: #add;
}
#quickhelp svg text.desc {
fill: #ddd;
}
/*
* Copyright 2014 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 -- Quick Help Layer
Defines the key-map layer for the UI. Used to give user a list of
key bindings; both global, and for the current view.
*/
(function (onos){
'use strict';
// Config variables
var w = '100%',
h = '80%',
fade = 500,
vb = '-200 0 400 400';
// layout configuration
var pad = 10,
offy = 45,
sepYDelta = 20,
colXDelta = 16,
yTextSpc = 12,
offDesc = 8;
// State variables
var data = [],
yCount;
// DOM elements and the like
var qhdiv = d3.select('#quickhelp'),
svg = qhdiv.select('svg'),
pane, rect, items;
// General functions
function isA(a) { return $.isArray(a) ? a : null; }
function isS(s) { return typeof s === 'string'; }
function cap(s) {
return s.replace(/^[a-z]/, function (m) { return m.toUpperCase(); });
}
var keyDisp = {
equals: '=',
dash: '-',
slash: '/',
backSlash: '\\',
backQuote: '`',
leftArrow: 'L-arrow',
upArrow: 'U-arrow',
rightArrow: 'R-arrow',
downArrow: 'D-arrow'
};
function mkKeyDisp(id) {
var v = keyDisp[id] || id;
return cap(v);
}
function addSeparator(el, i) {
var y = sepYDelta/2 - 5;
el.append('line')
.attr({ 'class': 'qhrowsep', x1: 0, y1: y, x2: 0, y2: y });
}
function addContent(el, data, ri) {
var xCount = 0,
clsPfx = 'qh-r' + ri + '-c';
function addColumn(el, c, i) {
var cls = clsPfx + i,
oy = 0,
aggKey = el.append('g').attr('visibility', 'hidden'),
gcol = el.append('g').attr({
'class': cls,
transform: translate(xCount, 0)
});
c.forEach(function (j) {
var k = j[0],
v = j[1];
if (k !== '-') {
aggKey.append('text').text(k);
gcol.append('text').text(k)
.attr({
'class': 'key',
y: oy
});
gcol.append('text').text(v)
.attr({
'class': 'desc',
y: oy
});
}
oy += yTextSpc;
});
// adjust position of descriptions, based on widest key
var kbox = aggKey.node().getBBox(),
ox = kbox.width + offDesc;
gcol.selectAll('.desc').attr('x', ox);
aggKey.remove();
// now update x-offset for next column
var bbox = gcol.node().getBBox();
xCount += bbox.width + colXDelta;
}
data.forEach(function (d, i) {
addColumn(el, d, i);
});
// finally, return the height of the row..
return el.node().getBBox().height;
}
function updateKeyItems() {
var rows = items.selectAll('.qhRow').data(data);
yCount = offy;
var entering = rows.enter()
.append('g')
.attr({
'class': 'qhrow'
});
entering.each(function (r, i) {
var el = d3.select(this),
sep = r.type === 'sep',
dy;
el.attr('transform', translate(0, yCount));
if (sep) {
addSeparator(el, i);
yCount += sepYDelta;
} else {
dy = addContent(el, r.data, i);
yCount += dy;
}
});
// size the backing rectangle
var ibox = items.node().getBBox(),
paneW = ibox.width + pad * 2,
paneH = ibox.height + offy;
items.selectAll('.qhrowsep').attr('x2', ibox.width);
items.attr('transform', translate(-paneW/2, -pad));
rect.attr({
width: paneW,
height: paneH,
transform: translate(-paneW/2-pad, 0)
});
}
function translate(x, y) {
return 'translate(' + x + ',' + y + ')';
}
function checkFmt(fmt) {
// should be a single array of keys,
// or array of arrays of keys (one per column).
// return null if there is a problem.
var a = isA(fmt),
n = a && a.length,
ns = 0,
na = 0;
if (n) {
// it is an array which has some content
a.forEach(function (d) {
isA(d) && na++;
isS(d) && ns++;
});
if (na === n || ns === n) {
// all arrays or all strings...
return a;
}
}
return null;
}
function buildBlock(map, fmt) {
var b = [];
fmt.forEach(function (k) {
var v = map.get(k),
a = isA(v),
d = (a && a[1]);
// '-' marks a separator; d is the description
if (k === '-' || d) {
b.push([mkKeyDisp(k), d]);
}
});
return b;
}
function emptyRow() {
return { type: 'row', data: []};
}
function mkArrRow(fmt) {
var d = emptyRow();
d.data.push(fmt);
return d;
}
function mkColumnarRow(map, fmt) {
var d = emptyRow();
fmt.forEach(function (a) {
d.data.push(buildBlock(map, a));
});
return d;
}
function mkMapRow(map, fmt) {
var d = emptyRow();
d.data.push(buildBlock(map, fmt));
return d;
}
function addRow(row) {
var d = row || { type: 'sep' };
data.push(d);
}
function aggregateData(bindings) {
var hf = '_helpFormat',
gmap = d3.map(bindings.globalKeys),
gfmt = bindings.globalFormat,
vmap = d3.map(bindings.viewKeys),
vgest = bindings.viewGestures,
vfmt, vkeys;
// filter out help format entry
vfmt = checkFmt(vmap.get(hf));
vmap.remove(hf);
// if bad (or no) format, fallback to sorted keys
if (!vfmt) {
vkeys = vmap.keys();
vfmt = vkeys.sort();
}
data = [];
addRow(mkMapRow(gmap, gfmt));
addRow();
addRow(isA(vfmt[0]) ? mkColumnarRow(vmap, vfmt) : mkMapRow(vmap, vfmt));
addRow();
addRow(mkArrRow(vgest));
}
function popBind(bindings) {
pane = svg.append('g')
.attr({
class: 'help',
opacity: 0
});
rect = pane.append('rect')
.attr('rx', 8);
pane.append('text')
.text('Quick Help')
.attr({
class: 'title',
dy: '1.2em',
transform: translate(-pad,0)
});
items = pane.append('g');
aggregateData(bindings);
updateKeyItems();
_fade(1);
}
function fadeBindings() {
_fade(0);
}
function _fade(o) {
svg.selectAll('g.help')
.transition()
.duration(fade)
.attr('opacity', o);
}
function addSvg() {
svg = qhdiv.append('svg')
.attr({
width: w,
height: h,
viewBox: vb
});
}
function removeSvg() {
svg.transition()
.delay(fade + 20)
.remove();
}
function showQuickHelp(bindings) {
svg = qhdiv.select('svg');
if (svg.empty()) {
addSvg();
popBind(bindings);
} else {
hideQuickHelp();
}
}
function hideQuickHelp() {
svg = qhdiv.select('svg');
if (!svg.empty()) {
fadeBindings();
removeSvg();
return true;
}
return false;
}
onos.ui.addLib('quickHelp', {
show: showQuickHelp,
hide: hideQuickHelp
});
}(ONOS));
/*
* Copyright 2014 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.
*/
/*
Sample module file to illustrate framework integration.
*/
(function (onos) {
'use strict';
var pi = Math.PI,
svg,
dotG,
nCircles = 12,
circleData = [],
dotId = 0,
angle = 360 / nCircles,
baseAngle = -90 - angle,
groupRadius = 120,
dotRadius = 24,
dotMoveMs = 800,
dotAppearMs = 300,
dotEase = 'elastic',
colorScale = d3.scale.linear()
.domain([-pi/2, 2*pi/4, 3*pi/2])
.range(['green', 'goldenrod', 'blue']);
// set the size of the SVG layer to match that of the view
function sizeSvg(view) {
svg.attr({
width: view.width(),
height: view.height()
});
}
// gets invoked only the first time the view is loaded
function init(view, ctx, flags) {
// prepare our SVG layer...
svg = view.$div.append('svg');
sizeSvg(view);
dotG = svg.append('g').attr('id', 'dots');
}
// gets invoked just before our view is loaded
function reset(view, ctx, flags) {
// clear dot group and reset circle data
dotG.html('');
circleData = [];
// also clear text, if any
svg.selectAll('text').remove();
}
function updateCirclePositions(view, addNew) {
var w = view.width(),
h = view.height(),
ox = w / 2,
oy = h / 2;
// reposition existing dots
circleData.forEach(function (c, i) {
var inc = addNew ? 1 : 0,
theta = ((i + inc) * angle + baseAngle) * pi/180,
dx = Math.cos(theta) * groupRadius,
dy = Math.sin(theta) * groupRadius,
x = ox + dx,
y = oy + dy;
if (!addNew && i === 0) {
x = ox;
y = oy;
}
c.cx = x;
c.cy = y;
c.rgb = colorScale(theta);
});
if (addNew) {
// introduce a new dot
circleData.unshift({
cx: ox,
cy: oy,
id: dotId++
});
}
// +1 to account for the circle in the center..
if (circleData.length > nCircles + 1) {
circleData.splice(nCircles + 1, 1);
}
}
function doCircles(view) {
var ox = view.width() / 2,
oy = view.height() / 2,
stroke = 'black',
fill = 'red',
hoverFill = 'magenta';
// move existing circles, and add a new one
updateCirclePositions(view, true);
var circ = dotG.selectAll('circle')
.data(circleData, function (d) { return d.id; });
// operate on existing elements
circ.on('mouseover', null)
.on('mouseout', null)
.on('click', null)
.transition()
.duration(dotMoveMs)
.ease(dotEase)
.attr({
cx: function (d) { return d.cx; },
cy: function (d) { return d.cy; }
})
.style({
cursor: 'default',
fill: function (d) { return d.rgb; }
});
// operate on entering elements
circ.enter()
.append('circle')
.attr({
cx: function (d) { return d.cx; },
cy: function (d) { return d.cy; },
r: 0
})
.style({
fill: fill,
stroke: stroke,
'stroke-width': 3.5,
cursor: 'pointer',
opacity: 0
})
.on('mouseover', function (d) {
d3.select(this).style('fill', hoverFill);
})
.on('mouseout', function (d) {
d3.select(this).style('fill', fill);
})
.on('click', function (d) {
setTimeout(function() {
doCircles(view, true);
}, 10);
})
.transition()
.delay(dotMoveMs)
.duration(dotAppearMs)
.attr('r', dotRadius)
.style('opacity', 1);
// operate on exiting elements
circ.exit()
.transition()
.duration(750)
.style('opacity', 0)
.attr({
cx: ox,
cy: oy,
r: groupRadius - dotRadius
})
.remove();
}
function load(view, ctx, flags) {
var ctxText = ctx ? 'Context is "' + ctx + '"' : '';
// display our view context
if (ctxText) {
svg.append('text')
.text(ctxText)
.attr({
x: 20,
y: '1.5em'
})
.style({
fill: 'darkgreen',
'font-size': '20pt'
});
}
doCircles(view);
}
function resize(view, ctx, flags) {
sizeSvg(view);
updateCirclePositions(view);
// move exiting dots into new positions, relative to view size
var circ = dotG.selectAll('circle')
.data(circleData, function (d) { return d.id; });
circ.attr({
cx: function (d) { return d.cx; },
cy: function (d) { return d.cy; }
});
}
// == register our view here, with links to lifecycle callbacks
onos.ui.addView('sample', {
init: init,
reset: reset,
load: load,
resize: resize
});
}(ONOS));
/*
* Copyright 2014 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.
*/
/*
Sample view to illustrate hash formats.
*/
(function (onos) {
'use strict';
var intro = "Try using the following hashes in the address bar:",
hashPrefix = '#sampleHash',
suffixes = [
'',
',one',
',two',
',context,ignored',
',context,ignored?a,b,c',
',two?foo',
',three?foo,bar'
],
$d;
function note(txt) {
$d.append('p')
.text(txt)
.style({
'font-size': '10pt',
color: 'darkorange',
padding: '0 20px',
margin: 0
});
}
function para(txt, color) {
var c = color || 'black';
$d.append('p')
.text(txt)
.style({
padding: '2px 8px',
color: c
});
}
function load(view, ctx, flags) {
var c = ctx || '(undefined)',
f = flags ? d3.map(flags).keys() : [];
$d = view.$div;
para(intro);
suffixes.forEach(function (s) {
note(hashPrefix + s);
});
para('View ID: ' + view.vid, 'blue');
para('Context: ' + c, 'blue');
para('Flags: { ' + f.join(', ') + ' }', 'magenta');
}
// == register the view here, with links to lifecycle callbacks
onos.ui.addView('sampleHash', {
reset: true, // empty the div on reset
load: load
});
}(ONOS));
/*
* Copyright 2014 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.
*/
/*
Sample view to illustrate key bindings.
*/
(function (onos) {
'use strict';
var keyDispatch = {
Z: keyUndo,
X: keyCut,
C: keyCopy,
V: keyPaste,
space: keySpace
};
function keyUndo(view) {
note(view, 'Z = UNDO');
}
function keyCut(view) {
note(view, 'X = CUT');
}
function keyCopy(view) {
note(view, 'C = COPY');
}
function keyPaste(view) {
note(view, 'V = PASTE');
}
function keySpace(view) {
note(view, 'The SpaceBar');
}
function note(view, msg) {
view.$div.append('p')
.text(msg)
.style({
'font-size': '10pt',
color: 'darkorange',
padding: '0 20px',
margin: 0
});
}
function keyCallback(view, key, keyCode, event) {
note(view, 'Key = ' + key + ' KeyCode = ' + keyCode);
}
function load(view, ctx) {
// this maps specific keys to specific functions (1)
view.setKeys(keyDispatch);
// whereas, this installs a general key handler function (2)
view.setKeys(keyCallback);
// Note that (1) takes precedence over (2)
view.$div.append('p')
.text('Press a key or two (try Z,X,C,V and others) ...')
.style('padding', '2px 8px');
}
// == register the view here, with links to lifecycle callbacks
onos.ui.addView('sampleKeys', {
reset: true, // empty the div on reset
load: load
});
}(ONOS));
/*
* Copyright 2014 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.
*/
/*
Sample view to illustrate radio buttons.
*/
(function (onos) {
'use strict';
var intro = [ 'Yo, radio button set...', 'Time to shine' ],
btnSet = [
{ text: 'First Button', cb: cbRadio },
{ text: 'Second Button', cb: cbRadio },
{ text: 'Third Button', cb: cbRadio }
];
// radio button callback
function cbRadio(view, btn) {
write(view, 'You pressed the ' + btn.text);
}
function write(view, msg) {
view.$div.append('p')
.text(msg)
.style({
'font-size': '10pt',
color: 'green',
padding: '0 20px',
margin: '2px'
});
}
// invoked when the view is loaded
function load(view, ctx) {
view.setRadio(btnSet);
view.$div.selectAll('p')
.data(intro)
.enter()
.append('p')
.text(function (d) { return d; })
.style('padding', '2px 8px');
}
// == register the view here, with links to lifecycle callbacks
onos.ui.addView('sampleRadio', {
reset: true, // empty the div on reset
load: load
});
}(ONOS));
/*
* Copyright 2014 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 -- CSS file
*/
#topo svg #topo-bg {
opacity: 0.5;
}
#topo #map {
stroke-width: 2px;
stroke: #eee;
fill: transparent;
}
/* TODO: move glyphs into framework */
#topo svg .glyphIcon {
fill: black;
stroke: none;
fill-rule: evenodd;
}
#topo svg .glyphIcon rect {
fill: #ddd;
stroke: none;
}
#topo svg .noDevsLayer {
visibility: hidden;
}
#topo svg .noDevsLayer text {
font-size: 60pt;
font-style: italic;
fill: #dde;
}
#topo svg .noDevsBird {
fill: #ecd;
}
/* NODES */
#topo svg .node {
cursor: pointer;
}
#topo svg .node.selected rect,
#topo svg .node.selected circle {
fill: #f90;
filter: url(#blue-glow);
}
#topo svg .node text {
pointer-events: none;
}
/* Device Nodes */
#topo svg .node.device {
}
#topo svg .node.device rect {
stroke-width: 1.5;
}
#topo svg .node.device.fixed rect {
stroke-width: 1.5;
stroke: #ccc;
}
/* note: device is offline without the 'online' class */
#topo svg .node.device {
fill: #777;
}
#topo svg .node.device.online {
fill: #6e7fa3;
}
/* note: device is offline without the 'online' class */
#topo svg .node.device text {
fill: #bbb;
font: 10pt sans-serif;
}
#topo svg .node.device.online text {
fill: white;
}
#topo svg .node.device .glyphIcon rect {
fill: #aaa;
}
#topo svg .node.device .glyphIcon use {
fill: #777;
}
#topo svg .node.device.selected .glyphIcon rect {
fill: #f90;
}
#topo svg .node.device.online .glyphIcon rect {
fill: #ccc;
}
#topo svg .node.device.online .glyphIcon use {
fill: #000;
}
#topo svg .node.device.online.selected .glyphIcon rect {
fill: #f90;
}
/* Host Nodes */
#topo svg .node.host {
stroke: #000;
}
#topo svg .node.host text {
fill: #846;
stroke: none;
font: 9pt sans-serif;
}
svg .node.host circle {
stroke: #000;
fill: #edb;
}
/* LINKS */
#topo svg .link {
opacity: .9;
}
#topo svg .link.inactive {
opacity: .5;
stroke-dasharray: 8 4;
}
#topo svg .link.secondary {
stroke: rgba(0,153,51,0.5);
stroke-width: 3px;
}
#topo svg .link.primary {
stroke: #ffA300;
stroke-width: 4px;
}
#topo svg .link.animated {
stroke: #ffA300;
}
#topo svg .link.secondary.optical {
stroke: rgba(128,64,255,0.5);
stroke-width: 4px;
}
#topo svg .link.primary.optical {
stroke: #74f;
stroke-width: 6px;
}
#topo svg .link.animated.optical {
stroke: #74f;
stroke-width: 10px;
}
#topo svg .linkLabel rect {
fill: #eee;
stroke: none;
}
#topo svg .linkLabel text {
text-anchor: middle;
stroke: #777;
stroke-width: 0.1;
font-size: 9pt;
}
/* Fly-in summary pane */
#topo-summary {
/* gets base CSS from .fpanel in floatPanel.css */
top: 64px;
}
#topo-summary svg {
display: inline-block;
width: 42px;
height: 42px;
}
#topo-summary svg .glyphIcon {
fill: black;
stroke: none;
fill-rule: evenodd;
}
#topo-summary h2 {
position: absolute;
margin: 0 4px;
top: 20px;
left: 50px;
color: black;
}
#topo-summary h3 {
margin: 0 4px;
top: 20px;
left: 50px;
color: black;
}
#topo-summary p, table {
margin: 4px 4px;
}
#topo-summary td.label {
font-style: italic;
color: #777;
padding-right: 12px;
}
#topo-summary td.value {
}
#topo-summary hr {
height: 1px;
color: #ccc;
background-color: #ccc;
border: 0;
}
/* Fly-in details pane */
#topo-detail {
/* gets base CSS from .fpanel in floatPanel.css */
top: 320px;
}
#topo-detail svg {
display: inline-block;
width: 42px;
height: 42px;
}
#topo-detail svg .glyphIcon {
fill: black;
stroke: none;
fill-rule: evenodd;
}
#topo-detail h2 {
position: absolute;
margin: 0 4px;
top: 20px;
left: 50px;
color: black;
}
#topo-detail h3 {
margin: 0 4px;
top: 20px;
left: 50px;
color: black;
}
#topo-detail p, table {
margin: 4px 4px;
}
#topo-detail td.label {
font-style: italic;
color: #777;
padding-right: 12px;
}
#topo-detail td.value {
}
#topo-detail .actionBtn {
margin: 6px 12px;
padding: 2px 6px;
font-size: 9pt;
cursor: pointer;
width: 200px;
text-align: center;
/* theme specific... */
border: 2px solid #ddd;
border-radius: 4px;
color: #eee;
background: #888;
}
#topo-detail .actionBtn:hover {
/* theme specific... */
border: 2px solid #ddd;
color: #eee;
background: #444;
}
#topo-detail hr {
height: 1px;
color: #ccc;
background-color: #ccc;
border: 0;
}
/* ONOS instance stuff */
#topo-oibox {
height: 100px;
}
#topo-oibox div.onosInst {
display: inline-block;
width: 170px;
height: 85px;
cursor: pointer;
}
#topo-oibox svg rect {
fill: #ccc;
stroke: #aaa;
stroke-width: 3.5;
}
#topo-oibox .online svg rect {
opacity: 1;
fill: #9cf;
stroke: #555;
}
#topo-oibox svg .glyphIcon {
fill: #888;
fill-rule: evenodd;
}
#topo-oibox .online svg .glyphIcon {
fill: #000;
}
#topo-oibox svg .badgeIcon {
fill: #777;
fill-rule: evenodd;
}
#topo-oibox .online svg .badgeIcon {
fill: #fff;
}
#topo-oibox svg text {
text-anchor: middle;
fill: #777;
}
#topo-oibox .online svg text {
fill: #eee;
}
#topo-oibox svg text.instTitle {
font-size: 11pt;
font-weight: bold;
}
#topo-oibox svg text.instLabel {
font-size: 9pt;
font-style: italic;
}
#topo-oibox .onosInst.mastership {
opacity: 0.3;
}
#topo-oibox .onosInst.mastership.affinity {
opacity: 1.0;
}
#topo-oibox .onosInst.mastership.affinity svg rect {
filter: url(#blue-glow);
}
#topo svg .suppressed {
opacity: 0.2;
}
/* Death Mask (starts hidden) */
#topo-mask {
display: none;
position: absolute;
top: 0;
left: 0;
width: 10000px;
height: 8000px;
z-index: 5000;
background-color: rgba(0,0,0,0.75);
padding: 60px;
}
#topo-mask p {
margin: 8px 20px;
color: #ddd;
font-size: 14pt;
font-style: italic;
}
This diff is collapsed. Click to expand it.
/*
* Copyright 2015 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.
*/
package org.onosproject.ui.impl;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.collect.ImmutableSet;
import org.junit.Before;
import org.junit.Test;
import org.onlab.osgi.ServiceDirectory;
import org.onlab.osgi.TestServiceDirectory;
import org.onlab.packet.ChassisId;
import org.onlab.packet.IpAddress;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import org.onosproject.cluster.ClusterService;
import org.onosproject.cluster.ClusterServiceAdapter;
import org.onosproject.core.CoreService;
import org.onosproject.core.CoreServiceAdapter;
import org.onosproject.core.Version;
import org.onosproject.mastership.MastershipService;
import org.onosproject.mastership.MastershipServiceAdapter;
import org.onosproject.net.DefaultDevice;
import org.onosproject.net.DefaultHost;
import org.onosproject.net.Device;
import org.onosproject.net.DeviceId;
import org.onosproject.net.Host;
import org.onosproject.net.HostId;
import org.onosproject.net.HostLocation;
import org.onosproject.net.Port;
import org.onosproject.net.PortNumber;
import org.onosproject.net.device.DeviceService;
import org.onosproject.net.device.DeviceServiceAdapter;
import org.onosproject.net.flow.FlowEntry;
import org.onosproject.net.flow.FlowRuleService;
import org.onosproject.net.flow.FlowRuleServiceAdapter;
import org.onosproject.net.host.HostService;
import org.onosproject.net.host.HostServiceAdapter;
import org.onosproject.net.intent.IntentService;
import org.onosproject.net.intent.IntentServiceAdapter;
import org.onosproject.net.link.LinkService;
import org.onosproject.net.link.LinkServiceAdapter;
import org.onosproject.net.provider.ProviderId;
import org.onosproject.net.statistic.StatisticService;
import org.onosproject.net.statistic.StatisticServiceAdapter;
import org.onosproject.net.topology.TopologyService;
import org.onosproject.net.topology.TopologyServiceAdapter;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import static org.junit.Assert.assertEquals;
public class TopologyViewWebSocketTest {
private static final ProviderId PID = new ProviderId("of", "foo.bar");
private static final ChassisId CHID = new ChassisId(123L);
private static final MacAddress MAC = MacAddress.valueOf("00:00:00:00:00:19");
private static final DeviceId DID = DeviceId.deviceId("of:foo");
private static final Set<IpAddress> IPS = ImmutableSet.of(IpAddress.valueOf("1.2.3.4"));
private TestWebSocket ws;
private TestServiceDirectory sd;
@Before
public void setUp() {
sd = new TestServiceDirectory();
sd.add(DeviceService.class, new TestDeviceService());
sd.add(ClusterService.class, new ClusterServiceAdapter());
sd.add(LinkService.class, new LinkServiceAdapter());
sd.add(HostService.class, new TestHostService());
sd.add(MastershipService.class, new MastershipServiceAdapter());
sd.add(IntentService.class, new IntentServiceAdapter());
sd.add(FlowRuleService.class, new TestFlowService());
sd.add(StatisticService.class, new StatisticServiceAdapter());
sd.add(TopologyService.class, new TopologyServiceAdapter());
sd.add(CoreService.class, new TestCoreService());
ws = new TestWebSocket(sd);
}
@Test
public void requestDetailsDevice() {
// build the request
String request = "{\"event\":\"requestDetails\", \"sid\":0, "
+ "\"payload\":{\"id\":\"of:000001\",\"class\":\"device\"}}";
ws.onMessage(request);
// look at the ws reply, and verify that it is correct
assertEquals("incorrect id", "of:000001", ws.reply.path("payload").path("id").asText());
assertEquals("incorrect mfr", "foo", ws.reply.path("payload").path("props").path("Vendor").asText());
}
@Test
public void requestDetailsHost() {
// build the request
String request = "{\"event\":\"requestDetails\", \"sid\":0, "
+ "\"payload\":{\"id\":\"00:00:00:00:00:19/-1\",\"class\":\"host\"}}";
ws.onMessage(request);
// look at the ws reply, and verify that it is correct
assertEquals("incorrect id", "00:00:00:00:00:19/-1", ws.reply.path("payload").path("id").asText());
assertEquals("incorrect ip address", "1.2.3.4", ws.reply.path("payload").path("props").path("IP").asText());
}
private class TestWebSocket extends TopologyViewWebSocket {
private ObjectNode reply;
/**
* Creates a new web-socket for serving data to GUI topology view.
*
* @param directory service directory
*/
public TestWebSocket(ServiceDirectory directory) {
super(directory);
}
@Override
protected synchronized void sendMessage(ObjectNode data) {
reply = data;
}
}
private class TestCoreService extends CoreServiceAdapter {
@Override
public Version version() {
return Version.version("1.2.3");
}
}
private class TestDeviceService extends DeviceServiceAdapter {
@Override
public Device getDevice(DeviceId deviceId) {
return new DefaultDevice(PID, deviceId, Device.Type.SWITCH,
"foo", "hw", "sw", "sn", CHID);
}
@Override
public List<Port> getPorts(DeviceId deviceId) {
return new ArrayList<>();
}
}
private class TestFlowService extends FlowRuleServiceAdapter {
@Override
public Iterable<FlowEntry> getFlowEntries(DeviceId deviceId) {
return new ArrayList<>();
}
}
private class TestHostService extends HostServiceAdapter {
@Override
public Host getHost(HostId hostId) {
return new DefaultHost(PID, hostId, MAC, VlanId.NONE,
new HostLocation(DID, PortNumber.P0, 123L), IPS);
}
}
}
\ No newline at end of file