Initial sketch of the GUI web-socket mechanics.
Change-Id: I5f481886fd45ce058be4aaf07fba466e702ae7ad
Showing
8 changed files
with
273 additions
and
0 deletions
| ... | @@ -119,6 +119,7 @@ | ... | @@ -119,6 +119,7 @@ |
| 119 | description="ONOS GUI console components"> | 119 | description="ONOS GUI console components"> |
| 120 | <feature>onos-api</feature> | 120 | <feature>onos-api</feature> |
| 121 | <feature>onos-thirdparty-web</feature> | 121 | <feature>onos-thirdparty-web</feature> |
| 122 | + <bundle>mvn:org.eclipse.jetty/jetty-websocket/8.1.15.v20140411</bundle> | ||
| 122 | <bundle>mvn:org.onlab.onos/onos-gui/1.0.0-SNAPSHOT</bundle> | 123 | <bundle>mvn:org.onlab.onos/onos-gui/1.0.0-SNAPSHOT</bundle> |
| 123 | </feature> | 124 | </feature> |
| 124 | 125 | ... | ... |
| ... | @@ -35,4 +35,16 @@ | ... | @@ -35,4 +35,16 @@ |
| 35 | <web.context>/onos/ui</web.context> | 35 | <web.context>/onos/ui</web.context> |
| 36 | </properties> | 36 | </properties> |
| 37 | 37 | ||
| 38 | + <dependencies> | ||
| 39 | + <dependency> | ||
| 40 | + <groupId>org.eclipse.jetty</groupId> | ||
| 41 | + <artifactId>jetty-websocket</artifactId> | ||
| 42 | + <version>8.1.15.v20140411</version> | ||
| 43 | + </dependency> | ||
| 44 | + <dependency> | ||
| 45 | + <groupId>javax.servlet</groupId> | ||
| 46 | + <artifactId>servlet-api</artifactId> | ||
| 47 | + <version>2.5</version> | ||
| 48 | + </dependency> | ||
| 49 | + </dependencies> | ||
| 38 | </project> | 50 | </project> | ... | ... |
| 1 | +/* | ||
| 2 | + * Copyright 2014 Open Networking Laboratory | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + */ | ||
| 16 | +package org.onlab.onos.gui; | ||
| 17 | + | ||
| 18 | +import org.eclipse.jetty.websocket.WebSocket; | ||
| 19 | +import org.eclipse.jetty.websocket.WebSocketServlet; | ||
| 20 | +import org.onlab.osgi.DefaultServiceDirectory; | ||
| 21 | +import org.onlab.osgi.ServiceDirectory; | ||
| 22 | + | ||
| 23 | +import javax.servlet.http.HttpServletRequest; | ||
| 24 | + | ||
| 25 | +/** | ||
| 26 | + * Web socket servlet capable of creating various sockets for the user interface. | ||
| 27 | + */ | ||
| 28 | +public class GuiWebSocketServlet extends WebSocketServlet { | ||
| 29 | + | ||
| 30 | + private ServiceDirectory directory = new DefaultServiceDirectory(); | ||
| 31 | + | ||
| 32 | + @Override | ||
| 33 | + public WebSocket doWebSocketConnect(HttpServletRequest request, String protocol) { | ||
| 34 | + | ||
| 35 | + return new TopologyWebSocket(directory); | ||
| 36 | + } | ||
| 37 | + | ||
| 38 | +} |
| 1 | +/* | ||
| 2 | + * Copyright 2014 Open Networking Laboratory | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + */ | ||
| 16 | +package org.onlab.onos.gui; | ||
| 17 | + | ||
| 18 | +import org.eclipse.jetty.websocket.WebSocket; | ||
| 19 | +import org.onlab.onos.net.device.DeviceService; | ||
| 20 | +import org.onlab.onos.net.topology.Topology; | ||
| 21 | +import org.onlab.onos.net.topology.TopologyEdge; | ||
| 22 | +import org.onlab.onos.net.topology.TopologyEvent; | ||
| 23 | +import org.onlab.onos.net.topology.TopologyGraph; | ||
| 24 | +import org.onlab.onos.net.topology.TopologyListener; | ||
| 25 | +import org.onlab.onos.net.topology.TopologyService; | ||
| 26 | +import org.onlab.onos.net.topology.TopologyVertex; | ||
| 27 | +import org.onlab.osgi.ServiceDirectory; | ||
| 28 | + | ||
| 29 | +import java.io.IOException; | ||
| 30 | + | ||
| 31 | +/** | ||
| 32 | + * Web socket capable of interacting with the GUI topology view. | ||
| 33 | + */ | ||
| 34 | +public class TopologyWebSocket implements WebSocket.OnTextMessage, TopologyListener { | ||
| 35 | + | ||
| 36 | + private final ServiceDirectory directory; | ||
| 37 | + private final TopologyService topologyService; | ||
| 38 | + private final DeviceService deviceService; | ||
| 39 | + | ||
| 40 | + private Connection connection; | ||
| 41 | + | ||
| 42 | + /** | ||
| 43 | + * Creates a new web-socket for serving data to GUI topology view. | ||
| 44 | + * | ||
| 45 | + * @param directory service directory | ||
| 46 | + */ | ||
| 47 | + public TopologyWebSocket(ServiceDirectory directory) { | ||
| 48 | + this.directory = directory; | ||
| 49 | + topologyService = directory.get(TopologyService.class); | ||
| 50 | + deviceService = directory.get(DeviceService.class); | ||
| 51 | + } | ||
| 52 | + | ||
| 53 | + @Override | ||
| 54 | + public void onOpen(Connection connection) { | ||
| 55 | + this.connection = connection; | ||
| 56 | + | ||
| 57 | + // Register for topology events... | ||
| 58 | + if (topologyService != null && deviceService != null) { | ||
| 59 | + topologyService.addListener(this); | ||
| 60 | + | ||
| 61 | + sendMessage("Yo!!!"); | ||
| 62 | + | ||
| 63 | + Topology topology = topologyService.currentTopology(); | ||
| 64 | + TopologyGraph graph = topologyService.getGraph(topology); | ||
| 65 | + for (TopologyVertex vertex : graph.getVertexes()) { | ||
| 66 | + sendMessage(deviceService.getDevice(vertex.deviceId()).toString()); | ||
| 67 | + } | ||
| 68 | + | ||
| 69 | + for (TopologyEdge edge : graph.getEdges()) { | ||
| 70 | + sendMessage(edge.link().toString()); | ||
| 71 | + } | ||
| 72 | + | ||
| 73 | + sendMessage("That's what we're starting with..."); | ||
| 74 | + | ||
| 75 | + } else { | ||
| 76 | + sendMessage("No topology service!!!"); | ||
| 77 | + } | ||
| 78 | + } | ||
| 79 | + | ||
| 80 | + @Override | ||
| 81 | + public void onClose(int closeCode, String message) { | ||
| 82 | + TopologyService topologyService = directory.get(TopologyService.class); | ||
| 83 | + if (topologyService != null) { | ||
| 84 | + topologyService.removeListener(this); | ||
| 85 | + } | ||
| 86 | + } | ||
| 87 | + | ||
| 88 | + @Override | ||
| 89 | + public void onMessage(String data) { | ||
| 90 | + System.out.println("Received: " + data); | ||
| 91 | + } | ||
| 92 | + | ||
| 93 | + public void sendMessage(String data) { | ||
| 94 | + try { | ||
| 95 | + connection.sendMessage(data); | ||
| 96 | + } catch (IOException e) { | ||
| 97 | + e.printStackTrace(); | ||
| 98 | + } | ||
| 99 | + } | ||
| 100 | + | ||
| 101 | + @Override | ||
| 102 | + public void event(TopologyEvent event) { | ||
| 103 | + sendMessage(event.toString()); | ||
| 104 | + } | ||
| 105 | +} | ||
| 106 | + |
| ... | @@ -39,4 +39,16 @@ | ... | @@ -39,4 +39,16 @@ |
| 39 | <url-pattern>/rs/*</url-pattern> | 39 | <url-pattern>/rs/*</url-pattern> |
| 40 | </servlet-mapping> | 40 | </servlet-mapping> |
| 41 | 41 | ||
| 42 | + <servlet> | ||
| 43 | + <servlet-name>Web Socket Service</servlet-name> | ||
| 44 | + <servlet-class>org.onlab.onos.gui.GuiWebSocketServlet</servlet-class> | ||
| 45 | + <load-on-startup>2</load-on-startup> | ||
| 46 | + </servlet> | ||
| 47 | + | ||
| 48 | + <servlet-mapping> | ||
| 49 | + <servlet-name>Web Socket Service</servlet-name> | ||
| 50 | + <url-pattern>/ws/*</url-pattern> | ||
| 51 | + </servlet-mapping> | ||
| 52 | + | ||
| 53 | + | ||
| 42 | </web-app> | 54 | </web-app> |
| ... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
| ... | @@ -40,6 +40,7 @@ | ... | @@ -40,6 +40,7 @@ |
| 40 | showBackground: true | 40 | showBackground: true |
| 41 | }, | 41 | }, |
| 42 | backgroundUrl: 'img/us-map.png', | 42 | backgroundUrl: 'img/us-map.png', |
| 43 | + webSockUrl: 'ws/topology', | ||
| 43 | data: { | 44 | data: { |
| 44 | live: { | 45 | live: { |
| 45 | jsonUrl: 'rs/topology/graph', | 46 | jsonUrl: 'rs/topology/graph', |
| ... | @@ -130,6 +131,7 @@ | ... | @@ -130,6 +131,7 @@ |
| 130 | links: [], | 131 | links: [], |
| 131 | lookup: {} | 132 | lookup: {} |
| 132 | }, | 133 | }, |
| 134 | + webSock, | ||
| 133 | labelIdx = 0, | 135 | labelIdx = 0, |
| 134 | selected = {}, | 136 | selected = {}, |
| 135 | highlighted = null, | 137 | highlighted = null, |
| ... | @@ -579,6 +581,52 @@ | ... | @@ -579,6 +581,52 @@ |
| 579 | } | 581 | } |
| 580 | 582 | ||
| 581 | // ============================== | 583 | // ============================== |
| 584 | + // Web-Socket for live data | ||
| 585 | + | ||
| 586 | + function webSockUrl() { | ||
| 587 | + return document.location.toString() | ||
| 588 | + .replace(/\#.*/, '') | ||
| 589 | + .replace('http://', 'ws://') | ||
| 590 | + .replace('https://', 'wss://') | ||
| 591 | + .replace('index2.html', config.webSockUrl); | ||
| 592 | + } | ||
| 593 | + | ||
| 594 | + webSock = { | ||
| 595 | + ws : null, | ||
| 596 | + | ||
| 597 | + connect : function() { | ||
| 598 | + webSock.ws = new WebSocket(webSockUrl()); | ||
| 599 | + | ||
| 600 | + webSock.ws.onopen = function() { | ||
| 601 | + webSock._send("Hi there!"); | ||
| 602 | + }; | ||
| 603 | + | ||
| 604 | + webSock.ws.onmessage = function(m) { | ||
| 605 | + if (m.data) { | ||
| 606 | + console.log(m.data); | ||
| 607 | + } | ||
| 608 | + }; | ||
| 609 | + | ||
| 610 | + webSock.ws.onclose = function(m) { | ||
| 611 | + webSock.ws = null; | ||
| 612 | + }; | ||
| 613 | + }, | ||
| 614 | + | ||
| 615 | + send : function(text) { | ||
| 616 | + if (text != null && text.length > 0) { | ||
| 617 | + webSock._send(text); | ||
| 618 | + } | ||
| 619 | + }, | ||
| 620 | + | ||
| 621 | + _send : function(message) { | ||
| 622 | + if (webSock.ws) { | ||
| 623 | + webSock.ws.send(message); | ||
| 624 | + } | ||
| 625 | + } | ||
| 626 | + | ||
| 627 | + }; | ||
| 628 | + | ||
| 629 | + // ============================== | ||
| 582 | // View life-cycle callbacks | 630 | // View life-cycle callbacks |
| 583 | 631 | ||
| 584 | function preload(view, ctx) { | 632 | function preload(view, ctx) { |
| ... | @@ -656,6 +704,7 @@ | ... | @@ -656,6 +704,7 @@ |
| 656 | .on('tick', tick); | 704 | .on('tick', tick); |
| 657 | 705 | ||
| 658 | network.drag = d3u.createDragBehavior(network.force, selectCb, atDragEnd); | 706 | network.drag = d3u.createDragBehavior(network.force, selectCb, atDragEnd); |
| 707 | + webSock.connect(); | ||
| 659 | } | 708 | } |
| 660 | 709 | ||
| 661 | function load(view, ctx) { | 710 | function load(view, ctx) { | ... | ... |
web/gui/src/main/webapp/ws.html
0 → 100644
| 1 | +<html> | ||
| 2 | +<head> | ||
| 3 | + <title>Web Sockets Demo</title> | ||
| 4 | + | ||
| 5 | + <script src="libs/jquery-2.1.1.min.js"></script> | ||
| 6 | + | ||
| 7 | + <script type='text/javascript'> | ||
| 8 | + if (!window.WebSocket) | ||
| 9 | + alert("WebSocket not supported by this browser"); | ||
| 10 | + | ||
| 11 | + var server = { | ||
| 12 | + connect : function() { | ||
| 13 | + var location = document.location.toString().replace('http://', | ||
| 14 | + 'ws://').replace('https://', 'wss://').replace('ws.html','ws/topology'); | ||
| 15 | + this.ws = new WebSocket(location); | ||
| 16 | + | ||
| 17 | + this.ws.onopen = function() { | ||
| 18 | + server._send("Hi there!"); | ||
| 19 | + }; | ||
| 20 | + | ||
| 21 | + this.ws.onmessage = function(m) { | ||
| 22 | + if (m.data) { | ||
| 23 | + $('#log').append(m.data).append($('<br/>')); | ||
| 24 | + } | ||
| 25 | + }; | ||
| 26 | + | ||
| 27 | + this.ws.onclose = function(m) { | ||
| 28 | + this.ws = null; | ||
| 29 | + }; | ||
| 30 | + }, | ||
| 31 | + | ||
| 32 | + _send : function(message) { | ||
| 33 | + if (this.ws) { | ||
| 34 | + this.ws.send(message); | ||
| 35 | + } | ||
| 36 | + }, | ||
| 37 | + | ||
| 38 | + send : function(text) { | ||
| 39 | + if (text != null && text.length > 0) { | ||
| 40 | + server._send(text); | ||
| 41 | + } | ||
| 42 | + } | ||
| 43 | + }; | ||
| 44 | + </script> | ||
| 45 | +</head> | ||
| 46 | +<body> | ||
| 47 | +<pre id='log'></pre> | ||
| 48 | + | ||
| 49 | +<script type='text/javascript'> | ||
| 50 | + server.connect(); | ||
| 51 | +</script> | ||
| 52 | + | ||
| 53 | +</body> | ||
| 54 | +</html> |
| ... | @@ -131,6 +131,7 @@ | ... | @@ -131,6 +131,7 @@ |
| 131 | com.fasterxml.jackson.databind, | 131 | com.fasterxml.jackson.databind, |
| 132 | com.fasterxml.jackson.databind.node, | 132 | com.fasterxml.jackson.databind.node, |
| 133 | com.google.common.base.*, | 133 | com.google.common.base.*, |
| 134 | + org.eclipse.jetty.websocket.*, | ||
| 134 | org.onlab.api.*, | 135 | org.onlab.api.*, |
| 135 | org.onlab.osgi.*, | 136 | org.onlab.osgi.*, |
| 136 | org.onlab.packet.*, | 137 | org.onlab.packet.*, | ... | ... |
-
Please register or login to post a comment