<document>
  <header>
    <product>resin</product>
    <title>Hello, World WebSocket in Resin</title>
    <description><p>A "hello, world" WebSocket servlet demonstrating
    the Resin WebSocket API.</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>A WebSocket is a bidirectional message stream 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>

<p>While this tutorial shows the low-level Resin API on top of WebSockets,
it's expected that applications will build their own protocols on top of
WebSockets. So application code will typically be written to the application
protocols, not the low-level text and binary stream. Some possible examples
are given later in the tutorial.</p>

<p>Resin's WebSocket API follows the Servlet API's stream model, using
InputStream/OutputStream for binary messages and a Reader/PrintWriter for
text messages. HTTP browsers will use text messages, while custom clients
like phone/pad applications may use binary messages for efficiency.</p>

</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>

<p>Correspondingly, the server does the following:</p>

<ol>
<li>Checks the handshake for a valid "hello" protocol.</li>
<li>Dispatches a HelloListener to handle the web socket request.</li>
<li>Handles messages throught he HelloListener until the connection ends.</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/HelloWebSocketServlet.java"/></td>
  <td>servlet to upgrade HTTP handshake to websocket </td>
</tr>
<tr>
  <td><viewfile-link file="WEB-INF/classes/example/WebSocketListener.java"/></td>
  <td>websocket listener for client messages</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 Servlet">

<p>Resin's WebSocket support is designed to be as similar to the
Servlet stream model as possible, and to follow the 3.0 Async API model
where possible. Because the client and server APIs are symmetrical, the main
API classes (WebSocketListener and WebSocketContext) have
no servlet dependencies.</p>

<p>The WebSocket API is divided into three major tasks:</p>

<ul>
<li>WebSocketServletRequest - HTTP handshake to establish a socket.</li>
<li>WebSocketContext - API to send messages.</li>
<li>WebSocketListener - callback API to receive messages.</li>
</ul>

<s2 title="WebSocket handshake - starting the connection">

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

<p>(The <code>WebSocketServletRequest</code> API is temporary until the
next Servlet specification integrates the <code>startWebSocket</code>
method directly.)</p>

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

...
public class MyServlet extends HttpServlet {

  public void service(HttpServletRequest req, HttpServletResponse res)
    throws IOException, ServletException
  {
    String protocol = req.getHeader("Sec-WebSocket-Protocol");

    WebSocketListener listener;

    if ("my-protocol".equals(protocol)) {
      listener = new MyListener();
      
      res.setHeader("Sec-WebSocket-Protocol", "my-protocol");
    }
    else {
      res.sendError(404);
      return;
    }
    
    WebSocketServletRequest wsReq = (WebSocketServletRequest) req;

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

</s2>

<s2 title="WebSocketContext - sending messages">

<p>The <code>WebSocketContext</code> is used to send messages.
Applications will need to synchronize on the <code>WebSocketContext</code>
when sending messages, because WebSockets is designed for
multithreaded applications, and because the <code>WebSocketContext</code>
is not thread safe.</p>

<p>A message stream starts with <code>startTextMessage</code>
or <code>startBinaryMessage</code> and is then used like a normal
<code>PrintWriter</code> or <code>OutputStream</code>. Closing the stream
finishes the message. A new message cannot be started until the first
message is completed by calling <code>close()</code>.</p>

<example title="Example: sending a message">
public void sendHello(WebSocketContext webSocket)
  throws IOException
{  
  PrintWriter out = webSocket.startTextMessage();
  out.println("hello");
  out.println("world");
  out.close();
}
</example>

</s2>

<s2 title="WebSocketListener - receiving messages">

<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>Reader</code> and <code>PrintWriter</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: EchoHandler.java">
package example;

import com.caucho.websocket.WebSocketContext;
import com.caucho.websocket.AbstractWebSocketListener;

public class EchoHandler extends AbstractWebSocketListener
{
  ...

  @Override
  public void onReadText(WebSocketContext context, Reader is)
    throws IOException
  {
    PrintWriter out = context.startTextMessage();

    int ch;

    while ((ch = is.read()) >= 0) {
      out.print((char) ch);
    }

    out.close();
    is.close();
  }
}
</example>

</s2>

<s2 title="WebSocketListener">

<p>Resin's WebSocketListener is the primary interface for receiving
messages. The listener serializes messages: following messages will be
blocked until the callback finishes processing the current one. Since only
a single message is read at a time, the listener is single-threaded like
a servlet.</p>

<p>The <code>onStart</code> callback is called when the initial handshake
completes, letting the server send messages without waiting for a client
response.</p>

<p><code>onClose</code> is called when the peer gracefully closes
the connection. In other words, an expected close.</p>

<p><code>onDisconnect</code> is called when the socket is shut down.
So a graceful close will have <code>onClose</code> followed
by <code>onDisconnect</code>, while a dropped connection will
only have an <code>onDisconnect</code>.</p>

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

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

  public void onReadBinary(WebSocketContext context, InputStream is)
    throws IOException;

  public void onReadText(WebSocketContext context, Reader is)
    throws IOException;

  public void onClose(WebSocketContext context)
    throws IOException;

  public void onDisconnect(WebSocketContext context)
    throws IOException;

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

</s2>

<s2 title="WebSocketContext">

<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 OutputStream startBinaryMessage() throws IOException;

  public PrintWriter startTextMessage() throws IOException;

  public void setTimeout(long timeout);

  public long getTimeout();

  public void close();
  
  public void disconnect();
}
</def>

</s2>

</s1>

<s1 title="WebSocket JavaScript">

<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="Application Protocols">

<p>A typical application will implement an application-specific protocol
on top of the WebSocket protocol, either a general messaging protocol like
JMTP, or a simple IM protocol, or a compact binary game protocol like Quake.
Most application code will use the application protocol API, and only a
thin layer dealing with WebSocket itself.</p>

<p>The JMTP protocol below is an example of a general messaging protocol
that can be layered on top of WebSockets, providing routing,
request-response, and object-oriented service design.</p>

<s2 title="JMTP (JSON Message Transport Protocol)">

<p>An example of a general protocol is JMTP (JSON Message Transport Protocol),
which defines unidirectional and RPC messages routed to destination
services, something like a simpler XMPP or SOA.</p>

<p>The JMTP protocol has 5 messages:</p>
<ul>
<li>"message" - unidirectional message</li>
<li>"message_error" - optional error response for a message</li>
<li>"query" - request portion of a bidirectional query</li>
<li>"result" - response for a bidirectional query</li>
<li>"query_error" - error for a query</li>
</ul>

<p>Each JMTP message has the following components:</p>
<ul>
<li>"to" and "from" address, which looks like a
mail address "hello-service@example.com"</li>
<li>a type "com.foo.HelloMessage"</li>
<li>a JSON payload "{'value', 15}"</li>
</ul>

<p>The "to" and "from" allow a service or actor-oriented architecture,
where the server routes messages to simple encapsulated services.</p>

<p>The type is used for object-oriented messaging and extensibility. A
simple actor/service can implement a subset of messages and a full
actor/service can implement more messages. The object-oriented messaging
lets a system grow and upgrade as the application requirement evolve.</p>

<p>Each JMTP message is a single WebSocket text message where each component of
the message is a separate line, allowing for easy parsing an debugging.</p>

<p>The "message" is a unidirectional message. The receiving end can
process it or even ignore it. Although the receiver can return an error
message, there is no requirement to do so.</p>

<example title="Example: JMTP unidirectional message (WebSocket text)">
message
to@example.com
from@browser
com.example.HelloMessage
{"value", 15}
</example>

<p>The "query" is a request-response request with a numeric
query identifier, to allow requests to be matched up with responses.
The receiver must return a "response" or a "queryError" with a matching
query-id, because the sender will the waiting. Since there's no requirement of
ordering, several queries can be processing at the same time.</p>

<example title="Example: JMTP query request with qid=15">
query
service@example.com
client@browser
com.example.HelloQuery
15
{"search", "greeting"}
</example>

<p>The "result" is a response to a query request with the matching numeric
query identifier. Since there's no requirement of
ordering, several queries can be processing at the same time.</p>

<example title="Example: JMTP query result with qid=15">
result
client@browser
service@example.com
com.example.HelloResult
15
{"greeting", "hello"}
</example>

<p>The "query_error" is an error response to a query request
with the matching numeric query identifier. The receiver must always
return either a "response" or a "query_error", even if it does not
understand the query, because the sender will be waiting for a response.</p>

<p>The "query_error" returns the original "query" request, plus a JSON
map with the error information.</p>

<example title="Example: JMTP query error with qid=15">
query_error
client@browser
service@example.com
com.example.HelloQuery
15
{"greeting", "hello"}
{"group":"internal-server-error","text":"my-error","type":"cancel"}
</example>

</s2>

</s1>

<s1 title="WebSocket Protocol Overview">

<s2 title="Handshake">

<example title="WebSocket handshake">
GET /test HTTP/1.1
Upgrade: WebSocket
Connection: Upgrade
Sec-WebSocket-Extensions: sample-extension
Sec-WebSocket-Origin: http://example.com
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Protocol: my-protocol
Sec-WebSocket-Version: 6
Host: localhost
Content-Length: 0

...

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Server: Resin/1.1
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Sec-WebSocket-Protocol: my-protocol
Content-Length: 0
Date: Fri, 08 May 1998 09:51:31 GMT

...
</example>

</s2>

<s2 title="WebSocket frames">

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

<p>Each packet has a small frame header, giving the type and the length,
and allowing for fragmentation for large messages.</p>

<def title="WebSocket text packet">
x84 x0c hello, world
</def>

<def title="WebSocket binary packet">
x85 x06 hello!
</def>

</s2>

</s1>

  </body>
</document>
