<document>
  <header>
    <product>resin</product>
    <title>Hello, World WebSocket in Resin</title>
    <description><p>A "hello, world" WebSocket servlet in Resin</p></description>
    <type>tutorial</type>
   <tutorial-startpage>websocket.php</tutorial-startpage>
  </header>

  <body>
    <localtoc/>

<s1 title="WebSocket Overview">

<p>WebSocket is a new browser capability being developed for HTML 5 browsers,
enabling fully interactive applications. With WebSockets, both the browser
and the server can send asynchronous messages over a single TCP socket, without
resorting to long polling or comet.</p>

<p>Essentially, a WebSocket is a standard bidirectional TCP socket between
the client and the server. The socket starts out as a HTTP connection and
then "Upgrades" to a TCP socket after a HTTP handshake. After the handshake,
either side can send data.</p>

<example title="WebSocket handshake">
GET /test HTTP/1.1
Upgrade: WebSocket
Connection: Upgrade
Origin: http://localhost/test
Host: localhost
Content-Length: 0

...

HTTP/1.1 101 Web Socket Protocol Handshake
Upgrade: WebSocket
Connection: Upgrade
Server: Resin/4.0.2
WebSocket-Location: ws://localhost/websocket
WebSocket-Origin: http://localhost/test
Content-Length: 0
Date: Fri, 08 May 2009 09:51:31 GMT

...
</example>

<s2 title="WebSocket packets">

<p>After the WebSocket connection is established, all data is encoded
in lightweight packets. While the spec defines a text packet and a
binary packet format, browsers use the text packet exclusively. (Resin's
HMTP uses the binary packet format.)</p>

<p>A text packet is the byte 0x00 followed by UTF-8 encoded data followed
by a 0xff byte.</p>

<def title="WebSocket text packet">
x00 <em>utf-8-data</em> xff
</def>

<def title="Example: hello text packet">
\x00hello, world\xff
</def>

</s2>


</s1>


<s1 title="Tutorial Description">

<p>Since the tutorial is a hello, world, the JavaScript
just does the following:</p>

<ol>
<li>Connects to the Resin WebSocket servlet</li>
<li>Sends a "hello" query to the servlet</li>
<li>Sends a "server" query to the servlet</li>
<li>Displays any received messages from the servlet</li>
</ol>

</s1>

<s1 title="Files in this tutorial">
<deftable>
<tr>
  <th>File</th>
  <th>Description</th>
</tr>
<tr>
  <td><viewfile-link file="websocket.php"/></td>
  <td>websocket HTML page and JavaScript</td>
</tr>
<tr>
  <td><viewfile-link file="WEB-INF/classes/example/WebSocketServlet.java"/></td>
  <td>websocket servlet</td>
</tr>
<tr>
  <td><viewfile-link file="WEB-INF/classes/example/WebSocketHandler.java"/></td>
  <td>websocket handler</td>
</tr>
<tr>
  <td><viewfile-link file="WEB-INF/resin-web.xml"/></td>
  <td>resin-web.xml configuration</td>
</tr>
</deftable>
</s1>

<s1 title="WebSocket JavaScript">

<p>The JavaScript for this example has been tested with the nightly
build of Chromium.</p>

<s2 title="Connecting to the WebSocket in JavaScript">

<example title="Example: WebSocket connect in JavaScript">
&lt;?php
  $url = "ws://localhost:8080/example/websocket";
?>

&lt;script language='javascript'>

function onopen(event) { ... }
function onmessage(event) { ... }
function onclose(event) { ... }

ws = new WebSocket("&lt;?= $url ?>");
wsopen.ws = ws;
ws.onopen = wsopen;
ws.onmessage = wsmessage;
ws.onclose = wsclose;

&lt;/script>
</example>

</s2>

<s2 title="Receiving WebSocket data in JavaScript">

<example title="Example: receive WebSocket message">
&lt;script language='javascript'>

function wsmessage(event)
{
  data = event.data;

  alert("Received: [" + data + "]");
}

&lt;/script>
</example>

</s2>

<s2 title="Sending WebSocket data in JavaScript">

<example title="Example: send WebSocket message">
&lt;script language='javascript'>

function wsopen(event)
{
  ws = this.ws;

  ws.send("my-message");
}

ws = new WebSocket(...);
wsopen.ws = ws;
ws.onopen = wsopen;

&lt;/script>
</example>

</s2>
</s1>

<s1 title="WebSocket Servlet">

<p>Resin's WebSocket support is designed to be similar to the
Servlet 3.0 Async API, although the requirements for WebSockets are
significantly different.</p>

<p>To upgrade a HTTP socket to WebSocket, the ServletRequest is cast to
a WebSocketServletRequest (implemented by Resin), and then call
startWebSocket(...)</p>

<example title="Example: Upgrading to WebSocket">
import com.caucho.servlet.WebSocketServletRequest;
import com.caucho.servlet.WebSocketListener;

...
public class MyServlet extends GenericServlet {

  public void service(ServletRequest req, ServletResponse res)
    throws IOException, ServletException
  {
    WebSocketServletRequest wsReq = (WebSocketServletRequest) req;

    WebSocketListener handler = new MyHandler();

    wsReq.startWebSocket(handler);
  }
}
</example>

<p>The WebSocketListener is the heart of the server-side implementation
of websockets. It is a single-threaded listener for client events.</p>

<p>When a new packet is available, Resin will call the <code>onRead</code>
method, expecting the listener to read data from the client. While
the <code>onRead</code> is processing, Resin will not call <code>onRead</code>
again until the first one has completed processing.</p>

<p>In this example, the handler reads a WebSocket text packet and sends
a response.</p>

<p>The <code>InputStream</code> and <code>OutputStream</code> from the
<code>WebSocketContext</code> are not thread safe, so it's important for
the server to synchronize writes so packets don't get jumbled up.</p>

<example title="Example: MyHandler.java">
package example;

import com.caucho.servlet.WebSocketContext;
import com.caucho.servlet.WebSocketListener;

public class MyHandler implements WebSocketListener
{
  ...

  public void onRead(WebSocketContext context)
    throws IOException
  {
    StringBuilder sb = new StringBuilder();

    InputStream is = context.getInputStream();
    OutputStream os = context.getOutputStream();

    int ch = _is.read();

    assert(ch == 0x00); // packet starts with 0x00

    while ((ch = _is.read()) >= 0 &amp;&amp; ch != 0xff) {
      sb.append((char) ch);
    }

    String message = sb.toString();

    String result = "received message";

    _os.write(0x00);
    _os.write(result.getBytes("utf-8"));
    _os.write(0xff);
    _os.flush();
  }
}
</example>

<p>Resin's WebSocketListener has four callback methods. <code>onRead</code>
will be called the majority of the time, and <code>onStart</code> called
at the beginning of the connection and <code>onComplete</code> called
at the end.</p>

<def title="WebSocketListener.java">
package com.caucho.servlet;

public interface WebSocketListener
{
  public void onStart(WebSocketContext context) throws IOException;

  public void onRead(WebSocketContext context) throws IOException;

  public void onComplete(WebSocketContext context) throws IOException;

  public void onTimeout(WebSocketContext context) throws IOException;
}
</def>

<p>The WebSocket context gives access to the WebSocket streams, as well
as allowing setting of the socket timeout, and closing the connection.</p>

<def title="WebSocketContext.java">
package com.caucho.servlet;

public interface WebSocketContext
{
  public InputStream getInputStream() throws IOException;

  public OutputStream getOutputStream() throws IOException;

  public void setTimeout(long timeout);

  public long getTimeout();

  public void complete();
}
</def>

</s1>

  </body>
</document>
