| <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> |
| |
| <!-- |
| Copyright (c) 2009, 2010, 2011, 2014 Oracle and/or its affiliates. All rights reserved. |
| --> |
| |
| <html> |
| <head> |
| <title>Using the WebSocket API in a Web Application</title> |
| <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" > |
| <meta name="description" content="A tutorial on how to use NetBeans IDE to use the WebSocket API in a Java EE 7 web application."> |
| <link rel="stylesheet" href="../../../netbeans.css"> |
| <meta name="author" content="ken ganfield"> |
| </head> |
| <body> |
| <h1>Using the WebSocket API in a Web Application</h1> |
| |
| <p>This tutorial demonstrates how to create a simple web application that enables |
| collaboration between client browsers that are connected to a single server application. |
| When a user draws a graphic element on a canvas in the client browser the element appears |
| on the canvas of all connected clients. |
| How does it work? |
| When the browser loads the web page a client-side script sends a WebSocket handshake |
| request to the application server. |
| The application can accept JSON and binary messages from the clients connected in the session and |
| broadcast the messages to all the connected clients.</p> |
| |
| <p>In this tutorial you will create a web application that uses the Java API for WebSocket |
| (<a href="http://www.jcp.org/en/jsr/detail?id=356">JSR 356</a>) to enable |
| bi-directional communication between browser clients and the application server. |
| The Java API for WebSocket provides support for creating |
| WebSocket Java components, initiating and intercepting WebSocket events and creating |
| and consuming WebSocket text and binary messages. |
| The tutorial will also demonstrate how you can use the Java API for JSON Processing |
| (<a href="http://jcp.org/en/jsr/detail?id=353">JSR 353</a>) to produce and consume JSON. |
| The Java API for WebSocket and the Java API for JSON Processing are part of the Java EE 7 platform |
| (<a href="http://jcp.org/en/jsr/detail?id=342">JSR 342</a>).</p> |
| |
| <p>The application contains a WebSocket endpoint and decoder and encoder interfaces, |
| a web page and some JavaScript files that are run in the client browser |
| when the page is loaded or when invoked from a form in the web page. |
| You will deploy the application to GlassFish Server Open Source Edition 4, |
| the reference implementation of Java EE 7 technology.</p> |
| |
| <p class="notes"><strong>Note.</strong> This tutorial is based on the <a href="https://blogs.oracle.com/arungupta/entry/collaborative_whiteboard_using_websocket_in" target="_blank"> |
| Collaborative Whiteboard using WebSocket in GlassFish 4 - Text/JSON and Binary/ArrayBuffer Data Transfer (TOTD #189) </a> blog post and |
| other blog entries which can be found on <a href="http://blog.arungupta.me/" target="_blank">Arun Gupta's blog</a>. |
| Be sure to visit the blog and see many other excellent entries on working with the WebSocket API and GlassFish 4.</p> |
| |
| <p class="tips">You can also watch the <a href="maven-websocketapi-screencast.html">Video of Using the WebSocket API in a Web Application</a>.</p> |
| |
| |
| |
| <p><b>Tutorial Exercises</b></p> |
| <img src="../../../images_www/articles/73/netbeans-stamp-80-74-73.png" class="stamp" alt="Content on this page applies to NetBeans IDE 7.3, 7.4 and 8.0" title="Content on this page applies to the NetBeans IDE 7.3, 7.4 and 8.0" > |
| |
| <ul> |
| <li><a href="#Exercise_1">Creating the Web Application Project</a></li> |
| <li><a href="#createendpoint">Creating the WebSocket Endpoint</a> |
| <ul> |
| <li><a href="#createendpoint1">Create the Endpoint</a></li> |
| <li><a href="#createendpoint2">Initiate the WebSocket Session</a></li> |
| <li><a href="#createendpoint3">Test the Endpoint</a></li> |
| </ul> |
| </li> |
| <li><a href="#createwhiteboard">Creating the Whiteboard</a> |
| <ul> |
| <li><a href="#createwhiteboard1">Add the Canvas</a></li> |
| <li><a href="#createwhiteboard2">Create the POJO</a></li> |
| <li><a href="#createwhiteboard3">Create a Coordinates Class</a></li> |
| <li><a href="#createwhiteboard6">Generate the JSON String</a></li> |
| <li><a href="#createwhiteboard4">Implement the Encoder and Decoder Interfaces</a></li> |
| <li><a href="#createwhiteboard5">Run the Application</a></li> |
| </ul> |
| </li> |
| <li><a href="#sendbinary">Sending Binary Data to the Endpoint</a></li> |
| <!--<li><a href="#Exercise_7">Downloading the Solution Project</a></li>--> |
| </ul> |
| |
| <p><b>To follow this tutorial, you need the following software and resources.</b></p> |
| <table> |
| <tbody> |
| <tr> |
| <th class="tblheader" scope="col">Software or Resource</th> |
| <th class="tblheader" scope="col">Version Required</th> |
| </tr> |
| <tr> |
| <td class="tbltd1"><a href="https://netbeans.org/downloads/index.html">NetBeans IDE</a></td> |
| <td class="tbltd1">7.3.1, 7.4, 8.0, Java EE version</td> |
| </tr> |
| <tr> |
| <td class="tbltd1"><a href="http://www.oracle.com/technetwork/java/javase/downloads/index.html">Java Development Kit (JDK)</a></td> |
| <td class="tbltd1">version 7 or 8</td> |
| </tr> |
| <tr> |
| <td class="tbltd1"><a href="https://glassfish.java.net/">GlassFish Server Open Source Edition</a></td> |
| <td class="tbltd1">4</td> |
| </tr> |
| </tbody> |
| </table> |
| <p class="notes"><strong>Note.</strong> GlassFish 4 is bundled with the Java EE download bundle of NetBeans IDE.</p> |
| |
| <p><b>Prerequisites</b></p> |
| <p>This document assumes you have some basic knowledge of, or programming experience with, the following technologies:</p> |
| <ul> |
| <li>Java Programming</li> |
| <li>JavaScript/HTML Programming</li> |
| <li>NetBeans IDE</li> |
| </ul> |
| |
| <p>Before starting this tutorial you may want to familiarize yourself with |
| the following documentation.</p> |
| <ul> |
| <li><a href="http://wiki.netbeans.org/MavenBestPractices" target="_blank">Best Practices for Apache Maven in NetBeans IDE</a></li> |
| <li><a href="http://books.sonatype.com/mvnref-book/reference/introduction.html" target="_blank">Chapter 1. Introducing Apache Maven</a> |
| (from <a href="http://books.sonatype.com/mvnref-book/reference/index.html" target="_blank">Maven: The Complete Reference </a>)</li> |
| </ul> |
| <p class="tips">You can download <a href="https://netbeans.org/projects/samples/downloads/download/Samples/JavaEE/WhiteboardApp.zip">a zip archive of the finished project</a>.</p> |
| |
| <!-- ===================================================================================== --> |
| <a name="Exercise_1"></a> |
| <!--Exercise 1: --> |
| <h2>Creating the Web Application Project</h2> |
| |
| <p>The goal of this exercise is to create a web application project |
| using the New Project wizard in the IDE. |
| When you create the project you will select Java EE 7 as the Java EE version and |
| GlassFish 4 as the application server. |
| GlassFish 4 is the reference implementation of the Java EE 7 platform. |
| You must have an application server that supports Java EE 7 registered with the IDE |
| to create the application in this tutorial.</p> |
| |
| |
| <ol> |
| <li>Choose File > New Project (Ctrl-Shift-N on Windows; ⌘-Shift-N on Mac) from the main menu.</li> |
| <li>Select Web Application from the Maven category. Click Next.</li> |
| <li>Type <strong>WhiteboardApp</strong> for the the Project Name and set the Project Location.</li> |
| <li>Type <strong>org.sample</strong> for the Group Id. Click Next.</li> |
| <li>Select <strong>GlassFish Server 4.0</strong> for the Server. </li> |
| <li>Set the Java EE Version to <strong>Java EE 7 Web</strong>. Click Finish.<br> |
| <img src="../../../images_www/articles/73/javaee/ee7-websocket/websocket-newproject.png" class="margin-around b-all" alt="Project details in the New Project wizard" title="Server and Java EE versions in the New Project wizard" > |
| </li> |
| </ol> |
| |
| |
| <p>When you click Finish, the IDE creates the project and opens the project in the Projects window.</p> |
| |
| <!-- ===================================================================================== --> |
| <a name="createendpoint"></a> |
| <h2>Creating the WebSocket Endpoint</h2> |
| <p>In this section you will create a WebSocket endpoint class and a JavaScript file. |
| The WebSocket endpoint class contains some basic methods that are run when the session is opened. |
| You will then create a JavaScript file that will initiate the handshake with the server when the page is loaded. |
| You will then run the application to test that the connection is successful.</p> |
| |
| <p class="tips">For more about using WebSocket APIs and annotations, see the summary of the |
| <a href="https://javaee-spec.java.net/nonav/javadocs/javax/websocket/package-summary.html" target="_blank"> |
| javax.websocket</a> package.</p> |
| |
| <div class="indent"> |
| <a name="createendpoint1"></a> |
| <h3>Creating the Endpoint</h3> |
| <p>In this exercise you will use a wizard in the IDE to help you create the WebSocket endpoint class.</p> |
| <ol> |
| <li>Right-click the Source Packages node in the Projects window and choose New > Other.</li> |
| <li>Select WebSocket Endpoint in the Web category. Click Next.</li> |
| <li>Type <strong>MyWhiteboard</strong> as the Class Name.</li> |
| <li>Select <tt>org.sample.whiteboardapp</tt> in the Package dropdown list.</li> |
| <li>Type <strong>/whiteboardendpoint</strong> as the WebSocket URI. Click Finish.<br> |
| <img src="../../../images_www/articles/73/javaee/ee7-websocket/websocket-newendpoint.png" class="margin-around b-all" alt="WebSocket Endpoint in the New File wizard" title="WebSocket Endpoint in the New File wizard" > |
| |
| <p>When you click Finish the IDE generates the WebSocket Endpoint class and opens the file in the source editor. |
| In the editor you can see that the IDE generated some annotations that are part of the WebSocket API. |
| The class is annotated with |
| <tt><a href="https://javaee-spec.java.net/nonav/javadocs/javax/websocket/server/ServerEndpoint.html" target="_blank">@ServerEndpoint</a></tt> |
| to identify the class as an endpoint and the WebSocket URI is specified as a parameter of the annotation. |
| The IDE also generated a default <tt>onMessage</tt> method that is annotated with |
| <tt><a href="https://javaee-spec.java.net/nonav/javadocs/javax/websocket/OnMessage.html" target="_blank">@OnMessage</a></tt>. |
| A method annotated with <tt>@OnMessage</tt> is invoked each time that the client receives a WebSocket message.</p> |
| |
| <pre class="examplecode"> |
| @ServerEndpoint("/whiteboardendpoint") |
| public class MyWhiteboard { |
| |
| @OnMessage |
| public String onMessage(String message) { |
| return null; |
| } |
| |
| }</pre> |
| </li> |
| <li>Add the following field (in <strong>bold</strong>) to the class. |
| <pre class="examplecode"> |
| @ServerEndpoint("/whiteboardendpoint") |
| public class MyWhiteboard { |
| <strong>private static Set<Session> peers = Collections.synchronizedSet(new HashSet<Session>());</strong> |
| |
| @OnMessage |
| public String onMessage(String message) { |
| return null; |
| } |
| }</pre> |
| </li> |
| <li>Add the following <tt>onOpen</tt> and <tt>onClose</tt> methods. |
| <pre class="examplecode"> |
| @OnOpen |
| public void onOpen (Session peer) { |
| peers.add(peer); |
| } |
| |
| @OnClose |
| public void onClose (Session peer) { |
| peers.remove(peer); |
| }</pre> |
| <p>You can see that the <tt>onOpen</tt> and <tt>onClose</tt> methods are annotated with |
| <tt><a href="https://javaee-spec.java.net/nonav/javadocs/javax/websocket/OnOpen.html" target="_blank">@OnOpen</a></tt> |
| and |
| <tt><a href="https://javaee-spec.java.net/nonav/javadocs/javax/websocket/OnClose.html" target="_blank">@OnClose</a></tt> |
| WebSocket API annotations. |
| A method annotated with <tt>@OnOpen</tt> is called when the web socket session is opened. |
| In this example the annotated <tt>onOpen</tt> method adds the browser client to the group of peers in |
| the current session and the <tt>onClose</tt> method removes the browser from the group.</p> |
| |
| <p class="tips">Use the hints and code completion in the source editor to help you generate the methods. |
| Click the hint glyph in the left margin next to the class declaration |
| (or place the insert cursor in the class declaration and type Alt-Enter) |
| and select the method in the popup menu. |
| The code completion can help you code the method.</p> |
| <img src="../../../images_www/articles/73/javaee/ee7-websocket/websocket-endpoint-hint.png" class="margin-around b-all" alt="screenshot of Code Hint in the Source Editor" title="Code Hint in the Source Editor" > |
| |
| </li> |
| <li>Right-click in the editor and choose Fix Imports (Alt-Shift-I; ⌘-Shift-I on Mac). Save your changes. |
| <p>You will see that import statements for classes in <tt>javax.websocket</tt> are added to the file.</p></li> |
| </ol> |
| <p>The endpoint is now created. You now need to create a JavaScript file to initiate the WebSocket session. |
| </p> |
| |
| <!-- ===================================================================================== --> |
| <a name="createendpoint2"></a> |
| <h3>Initiate the WebSocket Session</h3> |
| <p>In this exercise you will create a JavaScript file that will initiate a WebSocket session. |
| The browser client joins a session via an HTTP 'handshake' with the server over TCP. |
| In the JavaScript file you will specify the name of the <tt>wsURI</tt> of the endpoint and declare the WebSocket. |
| The <tt>wsURI</tt> URI scheme is part of the WebSocket protocol and |
| specifies the path to the endpoint for the application.</p> |
| |
| <ol> |
| <li>Right-click the project node in the Projects window and choose New > Other.</li> |
| <li>Select JavaScript File in the Web category of the New File wizard. Click Next.</li> |
| <li>Type <strong>websocket</strong> for the JavaScript File Name. Click Finish.</li> |
| <li>Add the following to the JavaScript file. |
| <pre class="examplecode"> |
| var wsUri = "ws://" + document.location.host + document.location.pathname + "whiteboardendpoint"; |
| var websocket = new WebSocket(wsUri); |
| |
| websocket.onerror = function(evt) { onError(evt) }; |
| |
| function onError(evt) { |
| writeToScreen('<span style="color: red;">ERROR:</span> ' + evt.data); |
| }</pre> |
| <p>This script will initiate the session handshake with the server when <tt>websocket.js</tt> is loaded by the browser.</p> |
| </li> |
| <li>Open <tt>index.html</tt> and add the following code (in <strong>bold</strong>) to the bottom of the file to load <tt>websocket.js</tt> when the page is finished loading. |
| <pre class="examplecode"><body> |
| <strong><h1>Collaborative Whiteboard App</h1> |
| |
| <script type="text/javascript" src="websocket.js"></script></strong> |
| </body></pre> |
| </li> |
| </ol> |
| <p>You can now test that the WebSocket endpoint is working and that the session is started and the client is added to the session.</p> |
| |
| <!-- ===================================================================================== --> |
| <a name="createendpoint3"></a> |
| <h3>Testing the Endpoint</h3> |
| <p>In this exercise you will add some some simple methods to the JavaScript file to print |
| the <tt>wsURI</tt> to the browser window when the browser is connected to the endpoint.</p> |
| |
| <ol> |
| <li>Add the following <tt><div></tt> tag (in <strong>bold</strong>) to <tt>index.html</tt> |
| <pre class="examplecode"><h1>Collaborative Whiteboard App</h1> |
| |
| <strong><div id="output"></div></strong> |
| <script type="text/javascript" src="websocket.js"></script></pre> |
| </li> |
| <li>Add the following declaration and methods to <tt>websocket.js</tt>. Save your changes. |
| <pre class="examplecode">// For testing purposes |
| var output = document.getElementById("output"); |
| websocket.onopen = function(evt) { onOpen(evt) }; |
| |
| function writeToScreen(message) { |
| output.innerHTML += message + "<br>"; |
| } |
| |
| function onOpen() { |
| writeToScreen("Connected to " + wsUri); |
| } |
| // End test functions</pre> |
| <p>When the page loads the JavaScript functions will print the message that the |
| browser is connected to the endpoint. |
| You can delete the functions after you confirm that the endpoint is performing correctly. </p> |
| </li> |
| <li>Right-click the project in the Projects window and choose Run.</li> |
| </ol> |
| <p>When you run the application the IDE will start the GlassFish server and build and deploy the application. |
| The index page will open in your browser and you will see the following message in the browser window.</p> |
| <img src="../../../images_www/articles/73/javaee/ee7-websocket/websocket-browser1.png" class="margin-around b-all" alt="Connected to endpoint message in browser window" title="Connected to endpoint message in browser window" > |
| <p>In the browser window you can see the following endpoint where messages are accepted: |
| <tt>http://localhost:8080/WhiteboardApp/whiteboardendpoint</tt></p> |
| </div> |
| |
| |
| |
| <!-- ===================================================================================== --> |
| <a name="createwhiteboard"></a> |
| <h2>Creating the Whiteboard</h2> |
| <p>In this section you will create the classes and JavaScript files to send and receive JSON text messages. |
| You will also add an |
| <a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html">HTML5 Canvas</a> |
| element for painting and displaying some content and an HTML <tt><form></tt> |
| with radio buttons that enable you to specify the shape and color of the paintbrush.</p> |
| |
| <!-- ===================================================================================== --> |
| <div class="indent"> |
| <a name="createwhiteboard1"></a> |
| <h3>Add the Canvas to the Web Page</h3> |
| <p>In this exercise you add a <tt>canvas</tt> element and a <tt>form</tt> element to the default index page. |
| The checkboxes in the form determine the properties of the paintbrush for the canvas.</p> |
| <ol> |
| <li>Open <tt>index.html</tt> in the source editor.</li> |
| <li>Delete the <tt><div></tt> tag that you added to test the endpoint and add the following |
| <tt><table></tt> and <tt><form></tt> elements (in <strong>bold</strong>) after the opening body tag. |
| <pre class="examplecode"><h1>Collaborative Whiteboard App</h1> |
| |
| <strong><table> |
| <tr> |
| <td> |
| </td> |
| <td> |
| <form name="inputForm"> |
| |
| |
| </form> |
| </td> |
| </tr> |
| </table></strong> |
| <script type="text/javascript" src="websocket.js"></script> |
| </body></pre> |
| </li> |
| <li>Add the following code (in <strong>bold</strong>) for the canvas element. |
| <pre class="examplecode"> |
| <table> |
| <tr> |
| <td> |
| <strong><canvas id="myCanvas" width="150" height="150" style="border:1px solid #000000;"></canvas></strong> |
| </td></pre> |
| </li> |
| <li>Add the following <tt><table></tt> to add radio buttons to select the color and shape. Save your changes. |
| |
| <pre class="examplecode"> |
| <table> |
| <tr> |
| <td> |
| <canvas id="myCanvas" width="150" height="150" style="border:1px solid #000000;"></canvas> |
| </td> |
| <td> |
| <form name="inputForm"> |
| <strong><table> |
| |
| <tr> |
| <th>Color</th> |
| <td><input type="radio" name="color" value="#FF0000" checked="true">Red</td> |
| <td><input type="radio" name="color" value="#0000FF">Blue</td> |
| <td><input type="radio" name="color" value="#FF9900">Orange</td> |
| <td><input type="radio" name="color" value="#33CC33">Green</td> |
| </tr> |
| |
| <tr> |
| <th>Shape</th> |
| <td><input type="radio" name="shape" value="square" checked="true">Square</td> |
| <td><input type="radio" name="shape" value="circle">Circle</td> |
| <td> </td> |
| <td> </td> |
| </tr> |
| |
| </table></strong> |
| </form></pre> |
| |
| <p>The shape, color, and coordinates of any figure drawn on the canvas |
| will be converted to a string in a JSON structure and sent as a message |
| to the WebSocket endpoint.</p> |
| </li> |
| </ol> |
| |
| <!-- ===================================================================================== --> |
| <a name="createwhiteboard2"></a> |
| <h3>Creating the POJO</h3> |
| <p>In this exercise you will create a simple POJO.</p> |
| |
| <ol> |
| <li>Right-click the project node and choose New > Java Class.</li> |
| <li>Type <strong>Figure</strong> as the Class Name and choose <tt>org.sample.whiteboardapp</tt> |
| in the Package dropdown list. Click Finish.</li> |
| <li>In the source editor, add the following (in <strong>bold</strong>): |
| <pre class="examplecode">public class Figure { |
| <strong>private JsonObject json;</strong> |
| }</pre> |
| <p>When you add the code you will be prompted to add an import statement for <tt>javax.json.JsonObject</tt>. |
| If you are not prompted, type Alt-Enter.</p> |
| <p class="tips">For more about <tt>javax.json.JsonObject</tt>, see the Java API for JSON Processing |
| (<a href="http://jcp.org/en/jsr/detail?id=353">JSR 353</a>), |
| which is part of the Java EE 7 Specification.</p> |
| </li> |
| <li>Create a getter and setter for <tt>json</tt>. |
| <p class="tips">You can select getter and setter in the Insert Code popup menu (Alt-Ins on Windows; Ctrl-I on Mac) |
| to open the Generate Getters and Setter dialog box. |
| Alternatively, you can choose Source > Insert Code from the main menu.</p> |
| <img src="../../../images_www/articles/73/javaee/ee7-websocket/websocket-generategetter.png" class="margin-around b-all" alt="Generate Getter and Setter dialog box" title="Generate Getter and Setter dialog box" > |
| </li> |
| <li>Add a constructor for <tt>json</tt>. |
| <pre class="examplecode"> |
| public Figure(JsonObject json) { |
| this.json = json; |
| }</pre> |
| <p class="tips">You can choose Constructor in the Insert Code popup menu (Ctrl-I).</p> |
| <img src="../../../images_www/articles/73/javaee/ee7-websocket/websocket-generateconstructor.png" class="margin-around b-all" alt="Generate Constructor popup menu" title="Generate Constructor popup menu" > |
| </li> |
| <li>Add the following <tt>toString</tt> method: |
| <pre class="examplecode"> |
| @Override |
| public String toString() { |
| StringWriter writer = new StringWriter(); |
| Json.createWriter(writer).write(json); |
| return writer.toString(); |
| }</pre> |
| </li> |
| <li>Right-click in the editor and choose Fix Imports (Alt-Shift-I; ⌘-Shift-I on Mac). Save your changes.</li> |
| </ol> |
| |
| <!-- ===================================================================================== --> |
| <a name="createwhiteboard3"></a> |
| <h3>Create a Coordinates Class</h3> |
| <p>You now create a class for the coordinates of the figures that are painted on the canvas.</p> |
| |
| <ol> |
| <li>Right-click the project node and choose New > Java Class.</li> |
| <li>In the New Java Class wizard, type <strong>Coordinates</strong> |
| as the Class Name and select <tt>org.sample.whiteboardapp</tt> |
| in the Package dropdown list. Click Finish.</li> |
| <li>In the source editor, add the following code. Save your changes. |
| <pre class="examplecode"> |
| private float x; |
| private float y; |
| |
| public Coordinates() { |
| } |
| |
| public Coordinates(float x, float y) { |
| this.x = x; |
| this.y = y; |
| } |
| |
| public float getX() { |
| return x; |
| } |
| |
| public void setX(float x) { |
| this.x = x; |
| } |
| |
| public float getY() { |
| return y; |
| } |
| |
| public void setY(float y) { |
| this.y = y; |
| } |
| </pre> |
| </li> |
| </ol> |
| <p>The class only contains a fields for the <tt>x</tt> and <tt>y</tt> coordinates and |
| some getters and setters.</p> |
| |
| |
| <!-- ===================================================================================== --> |
| <a name="createwhiteboard6"></a> |
| <h3>Generate the JSON String</h3> |
| <p>In this exercise you will create a JavaScript file that puts the details of the figure |
| that is drawn on the <tt>canvas</tt> element into a JSON structure that is sent to the websocket endpoint.</p> |
| <ol> |
| <li>Right-click the project node and choose New > JavaScript File to open the New JavaScript File wizard.</li> |
| <li>Type <strong>whiteboard</strong> for the File Name. |
| Click Finish. |
| <p>When you click Finish the IDE creates the empty JavaScript file |
| and opens the file in the editor. |
| You can see the new file under the Web Pages node in the Projects window.</p></li> |
| <li>Add the following code to initialize the canvas and to add an event listener. |
| <pre class="examplecode"> |
| var canvas = document.getElementById("myCanvas"); |
| var context = canvas.getContext("2d"); |
| canvas.addEventListener("click", defineImage, false);</pre> |
| <p>You can see that the <tt>defineImage</tt> method is invoked |
| when the user clicks in the <tt>canvas</tt> element.</p> |
| </li> |
| <li>Add the following <tt>getCurrentPos</tt>, <tt>defineImage</tt> and <tt>drawImageText</tt> methods |
| to construct the JSON structure and send it to the endpoint (<tt>sendText(json)</tt>). |
| |
| <pre class="examplecode"> |
| function getCurrentPos(evt) { |
| var rect = canvas.getBoundingClientRect(); |
| return { |
| x: evt.clientX - rect.left, |
| y: evt.clientY - rect.top |
| }; |
| } |
| |
| function defineImage(evt) { |
| var currentPos = getCurrentPos(evt); |
| |
| for (i = 0; i < document.inputForm.color.length; i++) { |
| if (document.inputForm.color[i].checked) { |
| var color = document.inputForm.color[i]; |
| break; |
| } |
| } |
| |
| for (i = 0; i < document.inputForm.shape.length; i++) { |
| if (document.inputForm.shape[i].checked) { |
| var shape = document.inputForm.shape[i]; |
| break; |
| } |
| } |
| |
| var json = JSON.stringify({ |
| "shape": shape.value, |
| "color": color.value, |
| "coords": { |
| "x": currentPos.x, |
| "y": currentPos.y |
| } |
| }); |
| drawImageText(json); |
| sendText(json); |
| } |
| |
| function drawImageText(image) { |
| console.log("drawImageText"); |
| var json = JSON.parse(image); |
| context.fillStyle = json.color; |
| switch (json.shape) { |
| case "circle": |
| context.beginPath(); |
| context.arc(json.coords.x, json.coords.y, 5, 0, 2 * Math.PI, false); |
| context.fill(); |
| break; |
| case "square": |
| default: |
| context.fillRect(json.coords.x, json.coords.y, 10, 10); |
| break; |
| } |
| }</pre> |
| <p>The JSON structure that is sent will be similar to the following:</p> |
| |
| <pre class="examplecode">{ |
| "shape": "square", |
| "color": "#FF0000", |
| "coords": { |
| "x": 31.59999942779541, |
| "y": 49.91999053955078 |
| } |
| } </pre> |
| |
| <p>You now need to add a <tt>sendText(json)</tt> method |
| to send the JSON string using <tt>websocket.send()</tt>.</p> |
| </li> |
| <li>Open <tt>websocket.js</tt> in the editor and add the following methods for sending JSON to the endpoint |
| and for drawing the image when a message is received from the endpoint. |
| <pre class="examplecode"> |
| websocket.onmessage = function(evt) { onMessage(evt) }; |
| |
| function sendText(json) { |
| console.log("sending text: " + json); |
| websocket.send(json); |
| } |
| |
| function onMessage(evt) { |
| console.log("received: " + evt.data); |
| drawImageText(evt.data); |
| }</pre> |
| <p class="notes"><strong>Note.</strong> |
| You can delete the code that you added to <tt>websocket.js</tt> for testing the endpoint.</p> |
| </li> |
| <li>Add the following line (in <strong>bold</strong>) to the bottom of <tt>index.html</tt> to load <tt>whiteboard.js</tt>. |
| <pre class="examplecode"> |
| </table> |
| <script type="text/javascript" src="websocket.js"></script> |
| <strong><script type="text/javascript" src="whiteboard.js"></script></strong> |
| <body> |
| </pre> |
| </li> |
| </ol> |
| |
| |
| |
| <!-- +++++++++++++++ Creating Implementations of Encoder and Decoder Interfaces +++++++++++++++ --> |
| <a name="createwhiteboard4"></a> |
| <h3>Implement the Encoder and Decoder Interfaces</h3> |
| <p>In this exercise you create classes to implement decoder and encoder interfaces |
| to decode web socket messages (JSON) to the POJO class <tt>Figure</tt> |
| and to encode <tt>Figure</tt> as a JSON string for sending to the endpoint.</p> |
| <p class="tips">For more details, see the section about message types and encoders and decoders in the technical article |
| <a href="http://www.oracle.com/technetwork/articles/java/jsr356-1937161.html">JSR 356, Java API for WebSocket</a>.</p> |
| |
| <ol> |
| <li>Right-click the project node and choose New > Java Class.</li> |
| <li>Type <strong>FigureEncoder</strong> as the Class Name and choose <tt>org.sample.whiteboardapp</tt> |
| in the Package dropdown list. Click Finish.</li> |
| <li>In the source editor, implement the WebSocket Encoder interface by |
| adding the following code (in <strong>bold</strong>): |
| <pre class="examplecode"> |
| public class FigureEncoder <strong>implements Encoder.Text<Figure></strong> { |
| |
| }</pre> |
| </li> |
| <li>Add an import statement for <tt>javax.websocket.Encoder</tt> and implement the abstract methods. |
| <p class="tips">Place your cursor in the class declaration and type Alt-Enter and choose <strong>Implement all abstract methods</strong> from the popup menu.</p></li> |
| <li>Modify the generated abstract methods by making the following changes (in <strong>bold</strong>). Save your changes. |
| <pre class="examplecode"> |
| @Override |
| public String encode(Figure <strong>figure</strong>) throws EncodeException { |
| <strong>return figure.getJson().toString();</strong> |
| } |
| |
| @Override |
| public void init(EndpointConfig ec) { |
| <strong>System.out.println("init");</strong> |
| } |
| |
| @Override |
| public void destroy() { |
| <strong>System.out.println("destroy");</strong> |
| }</pre> |
| |
| </li> |
| <li>Right-click the project node and choose New > Java Class.</li> |
| <li>Type <strong>FigureDecoder</strong> as the Class Name and choose <tt>org.sample.whiteboardapp</tt> |
| in the Package dropdown list. Click Finish.</li> |
| <li>In the source editor, implement the WebSocket Decoder interface by |
| adding the following code (in <strong>bold</strong>): |
| <pre class="examplecode"> |
| public class FigureDecoder <strong>implements Decoder.Text<Figure></strong> { |
| |
| }</pre> |
| </li> |
| <li>Add an import statement for <tt>javax.websocket.Decoder</tt> and implement abstract methods.</li> |
| <li>Make the following changes (in <strong>bold</strong>) to the generated abstract methods. |
| <pre class="examplecode"> |
| @Override |
| public Figure decode(String <strong>string</strong>) throws DecodeException { |
| <strong>JsonObject jsonObject = Json.createReader(new StringReader(string)).readObject(); |
| return new Figure(jsonObject);</strong> |
| } |
| |
| @Override |
| public boolean willDecode(String <strong>string</strong>) { |
| <strong>try { |
| Json.createReader(new StringReader(string)).readObject(); |
| return true; |
| } catch (JsonException ex) { |
| ex.printStackTrace(); |
| return false; |
| }</strong> |
| |
| } |
| |
| @Override |
| public void init(EndpointConfig ec) { |
| <strong>System.out.println("init");</strong> |
| } |
| |
| @Override |
| public void destroy() { |
| <strong>System.out.println("destroy");</strong> |
| }</pre> |
| </li> |
| <li>Fix the imports and save your changes.</li> |
| </ol> |
| <p>You now need to modify <tt>MyWhiteboard.java</tt> to specify the encoder and decoder.</p> |
| |
| <!-- +++++++++++++++ Running the Application +++++++++++++++ --> |
| <a name="createwhiteboard5"></a> |
| <h3>Running the Application</h3> |
| <p>You are now almost ready to run the application. |
| In this exercise you modify the WebSocket endpoint class to specify the encoder and decoder for the JSON string and |
| to add a method to send the JSON string to connected clients when a message is received.</p> |
| <ol> |
| <li>Open <tt>MyWhiteboard.java</tt> in the editor.</li> |
| <li>Modify the <tt>@ServerEndpoint</tt> annotation to specify the |
| encoder and decoder for the endopoint. |
| Note that you need to explicitly specify the <tt>value</tt> parameter for the name of the endpoint. |
| <pre class="examplecode"> |
| @ServerEndpoint(<strong>value=</strong>"/whiteboardendpoint"<strong>, encoders = {FigureEncoder.class}, decoders = {FigureDecoder.class}</strong>) |
| </pre> |
| </li> |
| <li>Delete the <tt>onMessage</tt> method that was generated by default.</li> |
| <li>Add the following <tt>broadcastFigure</tt> method and annotate the method with <tt>@OnMessage</tt>. |
| |
| <pre class="examplecode"> |
| @OnMessage |
| public void broadcastFigure(Figure figure, Session session) throws IOException, EncodeException { |
| System.out.println("broadcastFigure: " + figure); |
| for (Session peer : peers) { |
| if (!peer.equals(session)) { |
| peer.getBasicRemote().sendObject(figure); |
| } |
| } |
| }</pre> |
| </li> |
| |
| <li>Right-click in the editor and choose Fix Imports (Alt-Shift-I; ⌘-Shift-I on Mac). Save your changes.</li> |
| <li>Right-click the project in the Projects window and choose Run.</li> |
| </ol> |
| <p>When you click Run the IDE opens a browser window to <a href="http://localhost:8080/WhiteboardApp/">http://localhost:8080/WhiteboardApp/</a>.</p> |
| <p class="notes"><strong>Note.</strong> |
| You might need to undeploy the previous application from the application server or |
| force reload the page in the browser. |
| </p> |
| <p>If you view the browser messages you can see that a string is sent via JSON to the endpoint |
| each time you click in the canvas.</p> |
| <img src="../../../images_www/articles/73/javaee/ee7-websocket/websocket-onebrowser.png" class="margin-around b-all" alt="screenshot of application in browser" title="Canvas with figures in browser and JSON displayed in web console" > |
| <p>If you open another browser to <tt>http://localhost:8080/WhiteboardApp/</tt> you can see that each time you click in the canvas in one |
| browser the new circle or square is reproduced in the canvas of the other browser.</p> |
| <img src="../../../images_www/articles/73/javaee/ee7-websocket/websocket-twobrowsers.png" class="margin-around b-all" alt="screenshot of application in two browsers" title="Two browsers sending JSON via the endpoint" > |
| </div> |
| |
| |
| <!-- ===================================================================================== --> |
| <a name="sendbinary"></a> |
| <h2>Sending Binary Data to the Endpoint</h2> |
| <p>The application can now process and send a string via JSON to the endpoint and the string is then |
| sent to the connected clients. |
| In this section you will modify the JavaScript files to send and receive binary data.</p> |
| |
| <p>To send binary data to the endpoint you need to set the <tt>binaryType</tt> property of WebSocket to <tt>arraybuffer</tt>. |
| This ensures that any binary transfers using WebSocket are done using <tt>ArrayBuffer</tt>. |
| The binary data conversion is performed by the <tt>defineImageBinary</tt> method in <tt>whiteboard.js</tt>.</p> |
| |
| <ol> |
| <li>Open <tt>websocket.js</tt> and add the following code to set the <tt>binaryType</tt> |
| property of WebSocket to <tt>arraybuffer</tt>. |
| <pre class="examplecode"> |
| websocket.binaryType = "arraybuffer";</pre> |
| </li> |
| <li>Add the following method to send binary data to the endpoint. |
| <pre class="examplecode"> |
| function sendBinary(bytes) { |
| console.log("sending binary: " + Object.prototype.toString.call(bytes)); |
| websocket.send(bytes); |
| }</pre> |
| </li> |
| <li>Modify the <tt>onMessage</tt> method to add the following code (in <strong>bold</strong>) to |
| select the method for updating the canvas according to the type of data in the incoming message. |
| <pre class="examplecode"> |
| function onMessage(evt) { |
| console.log("received: " + evt.data); |
| <strong>if (typeof evt.data == "string") {</strong> |
| drawImageText(evt.data); |
| <strong>} else { |
| drawImageBinary(evt.data); |
| }</strong> |
| }</pre> |
| <p>The <tt>drawImageBinary</tt> method is invoked if |
| a message with binary data is received.</p> |
| </li> |
| <li>Open <tt>whiteboard.js</tt> and add the following methods. |
| The <tt>drawImageBinary</tt> method is invoked to update the canvas after parsing the |
| incoming binary data. |
| The <tt>defineImageBinary</tt> method is used to prepare a snapshot of the canvas |
| as binary data. |
| <pre class="examplecode"> |
| function drawImageBinary(blob) { |
| var bytes = new Uint8Array(blob); |
| // console.log('drawImageBinary (bytes.length): ' + bytes.length); |
| |
| var imageData = context.createImageData(canvas.width, canvas.height); |
| |
| for (var i=8; i<imageData.data.length; i++) { |
| imageData.data[i] = bytes[i]; |
| } |
| context.putImageData(imageData, 0, 0); |
| |
| var img = document.createElement('img'); |
| img.height = canvas.height; |
| img.width = canvas.width; |
| img.src = canvas.toDataURL(); |
| } |
| |
| function defineImageBinary() { |
| var image = context.getImageData(0, 0, canvas.width, canvas.height); |
| var buffer = new ArrayBuffer(image.data.length); |
| var bytes = new Uint8Array(buffer); |
| for (var i=0; i<bytes.length; i++) { |
| bytes[i] = image.data[i]; |
| } |
| sendBinary(buffer); |
| }</pre> |
| <p>You now need to add a way to invoke <tt>defineImageBinary</tt> when you want to generate |
| the binary data as the type <tt>ArrayBuffer</tt> and send it to the endpoint.</p> |
| </li> |
| <li>Open <tt>index.html</tt> and modify the <tt><table></tt> element to add the following row to the table |
| in the form. |
| <pre class="examplecode"> |
| <tr> |
| <th> </th> |
| <td><input type="submit" value="Send Snapshot" onclick="defineImageBinary(); return false;"></td> |
| <td> </td> |
| <td> </td> |
| <td> </td> |
| </tr> |
| </pre> |
| <p>The new row contains a Send Snapshot button to send a binary snapshot of the canvas to the connected peers. |
| The <tt>defineImageBinary</tt> method in <tt>whiteboard.js</tt> is invoked when the button is clicked.</p> |
| </li> |
| <li>Open <tt>MyWhiteboard.java</tt> and add the following method that will send the binary |
| data to peers when the endpoint receives a message with binary data. |
| <pre class="examplecode"> |
| @OnMessage |
| public void broadcastSnapshot(ByteBuffer data, Session session) throws IOException { |
| System.out.println("broadcastBinary: " + data); |
| for (Session peer : peers) { |
| if (!peer.equals(session)) { |
| peer.getBasicRemote().sendBinary(data); |
| } |
| } |
| }</pre> |
| <p class="notes"><strong>Note.</strong> |
| You will need to add an import statement for <tt>java.nio.ByteBuffer</tt>. |
| </p> |
| </li> |
| </ol> |
| |
| <p class="tips"> |
| You can modify the application to enable the user to stop sending data to the endpoint. |
| By default all peers are connected as soon as they open the page and data is sent from the browser |
| to all connected peers. |
| You can add a simple conditional so that data is not sent to the endpoint unless the option is selected. |
| This does not affect receiving data. Data is still received from the endpoint.</p> |
| <div class="indent"> |
| <ol> |
| <li>Modify the <tt>defineImage</tt> method in <tt>whiteboard.js</tt> to add the following code (in <strong>bold</strong>). |
| <pre class="examplecode"> |
| drawImageText(json); |
| <strong> if (document.getElementById("instant").checked) {</strong> |
| sendText(json); |
| <strong> }</strong> |
| }</pre> |
| <p>The conditional code that you checks that if the element with the id <tt>checked</tt></p> |
| </li> |
| <li>Open <tt>index.html</tt> and modify the <tt><table></tt> element to add a checkbox to the form. |
| <pre class="examplecode"> |
| <tr> |
| <th> </th> |
| <td><input type="submit" value="Send Snapshot" onclick="defineImageBinary(); return false;"></td> |
| <td><strong><input type="checkbox" id="instant" value="Online" checked="true">Online</strong></td> |
| <td> </td> |
| <td> </td> |
| </tr> |
| </pre> |
| <p>No data is sent when the Online checkbox is deselected, but the client will still receive data from the endpoint.</p> |
| |
| </ol> |
| <p>If you add the Send Snapshot button and the Online checkbox and |
| run the application again you will see the new elements in the index page. |
| If you open another browser and deselect the Online button you can see that the JSON |
| message is not sent to the endpoint when you click in the canvas.</p> |
| <img src="../../../images_www/articles/73/javaee/ee7-websocket/websocket-onebrowser-binary.png" class="margin-around b-all" alt="screenshot of application in browser" title="Web console in browser displaying message that binary data was sent" > |
| <p>If you click Send Snapshot the binary data is sent to the endpoint and broadcast to the |
| connected clients.</p> |
| </div> |
| |
| <!-- |
| <a name="Exercise_7"></a> |
| <h2>Downloading the Solution Project</h2> |
| <p>You can download the solution to this tutorial as a project in the following ways.</p> |
| <ul> |
| <li>Download <a href="https://netbeans.org/projects/samples/downloads/download/Samples%252FJavaEE%252FMavenEnterpriseApp.zip">a zip archive of the finished project</a>.</li> |
| <li>Checkout the project sources from the NetBeans Samples by performing the following steps: |
| <ol> |
| <li>Choose Team > Subversion > Checkout from the main menu.</li> |
| <li>In the Checkout dialog box, enter the following Repository URL:<br> |
| <tt>https://svn.netbeans.org/svn/samples~samples-source-code</tt><br> |
| Click Next.</li> |
| <li>Click Browse to open the Browse Repostiory Folders dialog box.</li> |
| <li>Expand the root node and select <strong>samples/javaee/MavenEnterpriseApp</strong>. Click OK.</li> |
| <li>Specify the Local Folder for the sources (the local folder must be empty).</li> |
| <li>Click Finish. |
| <p>When you click Finish, the IDE initializes the local folder as a Subversion repository |
| and checks out the project sources.</p> |
| </li> |
| <li>Click Open Project in the dialog that appears when checkout is complete.</li> |
| </ol> |
| <p class="notes"><strong>Notes.</strong> For more about installing Subversion, |
| see the section on <a href="../ide/subversion.html#settingUp">Setting up Subversion</a> in the <a href="../ide/subversion.html">Guide to Subversion in NetBeans IDE</a>.</p> |
| </li> |
| </ul> |
| --> |
| |
| |
| <!-- |
| <a name="Exercise_5"></a> |
| |
| <h2>Troubleshooting</h2> |
| <p>The following are some of the problems you may encounter when creating your project.</p> |
| <div class="indent"> |
| <h3 class="tutorial">Problem with JMS Resources</h3> |
| <p>When using the wizard to create JMS resources, |
| you may see the following server error message in the output window:</p> |
| <pre>[com.sun.enterprise.connectors.ConnectorRuntimeException: |
| JMS resource not created : jms/Queue] |
| </pre> |
| <p>This message could indicate that the JMS resource was not created or was not registered with the application server. |
| You can use the Admin Console of the application server to check, create and edit JMS resources.</p> |
| <p>To open the Admin Console, do the following:</p> |
| <ol> |
| <li>Confirm that the application server is running by expanding the Servers node in the Services window of the IDE. |
| A small green arrow next to the application server node indicates the server is running.</li> |
| <li>Right-click the application server node and choose View Admin Console to open the login window in your browser.</li> |
| <li>Log in to the server. The default user name and password are <tt>admin</tt> and <tt>adminadmin</tt>.</li> |
| <li>In the Admin Console in your browser, expand the Resources node and JMS Resources node in the left frame.</li> |
| <li>Click on the Connection Factories and Destination Resources links in the left frame to check if the resources are |
| registered with the server and if necessary modify the resources. If the resources do not exist, you can create them |
| in the Admin Console.</li> |
| </ol> |
| <p>You need to make sure that the JMS connection factory resource |
| in the PostMessage servlet is mapped to the correct JNDI name of the JMS connection factory resource |
| registered with the Sun Java System Application Server.</p> |
| <p>The following resources should be registered with the Sun Java System Application Server:</p> |
| <ul> |
| <li>a Destination resource with the JNDI name <tt>jms/NewMessage</tt> and type <tt>javax.jms.Queue</tt></li> |
| <li>a Connection Factory resource with the JNDI name <tt>jms/NewMessageFactory</tt> and type <tt> |
| javax.jms.QueueConnectionFactory</tt></li> |
| </ul> |
| |
| <p>make sure that the import in PostMessage is not <tt>javax.resource.cci.ConnectionFactory</tt></p> |
| |
| <h3 class="tutorial">Problem with the Datasource</h3> |
| |
| </div>--> |
| <br> |
| <div class="feedback-box" ><a href="/about/contact_form.html?to=3&subject=Feedback:%20Using%20the%20WebSocket%20API%20in%20a%20Web%20Application">Send Feedback on This Tutorial</a></div> |
| <br style="clear:both;" > |
| <!-- ======================================================================================= --> |
| <h2><a name="nextsteps"></a>See Also</h2> |
| <p>For more information about using NetBeans IDE to develop Java EE applications, see the following resources: |
| </p> |
| <ul> |
| <li>Demo: <a href="maven-websocketapi-screencast.html">Using the WebSocket API in a Web Application</a></li> |
| <li><a href="javaee-intro.html">Introduction to Java EE Technology</a></li> |
| <li><a href="javaee-gettingstarted.html">Getting Started with Java EE Applications</a></li> |
| <li><a href="../../trails/java-ee.html">Java EE & Java Web Learning Trail</a></li> |
| </ul> |
| <p>You can find more information about using Java EE in the |
| <a href="http://download.oracle.com/javaee/6/tutorial/doc/">Java EE Tutorial</a>.</p> |
| <p>To send comments and suggestions, get support, and keep informed on the latest |
| developments on the NetBeans IDE Java EE development features, <a href="../../../community/lists/top.html">join |
| the nbj2ee mailing list</a>.</p> |
| </body> |
| </html> |