<document>
<header>
<product>resin</product>
<type>tutorial</type>
<title>Custom Protocol Handling</title>

<description>
<p>This tutorial shows the usage of the Resin server architecture to handle a
custom protocol.  Resin handles the TCP connections, multi-threading,  and the
request object pooling.  The application implements a class that reads from a
stream and writes to a stream.</p>

<p>Professor Trelawny once got a student to make a Magic8Ball,
used for prophecy.  Originally it was used with a simple web interface.  Now
Trelawny wants to provide a <var/magic8ball/> protocol server on the Hogwart's
public web server.  The <var/magic8ball/> protocol is at the same level as
<var/http/> or <var/smtp/>, it sit's directly on top of TCP/IP.</p>

</description>

</header>
<body>

<summary/>

<section title="Files in this tutorial">
<deftable>
<tr><td><viewfile-link file="src/example/Magic8Ball.java"/>
    <td>The orignal Magic8Ball class, it knows nothing about the code that uses it.
<tr><td><viewfile-link file="src/example/Magic8BallProtocol.java"/>
    <td>The implementation of <a href="javadoc|com.caucho.server.port.Protocol|"/> that Resin uses to create a Request object.
<tr><td><viewfile-link file="src/example/Magic8BallRequest.java"/>
    <td>The implementation of interface <a href="javadoc|com.caucho.server.port.ServerRequest|"/> that represents a single request.
<tr><td><viewfile-link file="src/example/Parser.java"/>
    <td>protocol-specific parsing class to parse the ReadStream and determine commands.
<tr><td><viewfile-link file="src/example/AbstractCommand.java"/>
    <td>protocol-specific abstract base class for commands.
<tr><td><viewfile-link file="src/example/SetProphetCommand.java"/>
    <td>protocol-specific Command to set the prophet to use for the magic 8 ball.
<tr><td><viewfile-link file="src/example/AskCommand.java"/>
    <td>protocol-specific Command to ask the magic 8 ball for a prophecy.
<tr><td><viewfile-link file="build.xml"/>
    <td>Ant build file

</deftable>
</section>

<section title="The advantage of using Resin's server architecture">

<p>Implementation of a protocol at the level that <var/magic8ball/> is at
normally requires a large amount of bug-prone code, such as code
for handling tcp/ip connections, multi-threading, and request object reuse.
Resin provides a simple way to handle protocols without requiring the
implementation of that code. </p>

<p>Applications take advantage of Resin's highly tested and configurable server
architecture and only need to implement some simple objects.  Two classes are
required, one which extends the abstract class <a
href="javadoc|com.caucho.server.port.Protocol|"/> and one which implements the
interface <a href="javadoc|com.caucho.server.port.ServerRequest|"/></p>.
</section>

<section title="com.caucho.server.port.Protocol">

<p>A custom class derived from 
<a href="javadoc|com.caucho.server.port.Protocol|"/>
is a factory that produces custom Request objects.</p>

<p>The Protocol passes a 
<a href="javadoc|com.caucho.server.connection.Connection|"/> 
object to the Request object it creates.  The Request object uses the
<code/Connection/> to obtain a read stream and a write stream.</p>

<p>The example in this tutorial is simple, it's main purpose is to override the
<code>createRequest</code> method to return an instance of the
<code/example.Magic8BallRequest/> request handling object. </p>

<example file="src/example/Magic8BallProtocol.java">
  ...

  /**
   * Create a Magic8BallRequest object for the new thread.
   */
  public ServerRequest createRequest(Connection conn)
  {
    return new Magic8BallRequest(this, conn);
  }

  ...
</example>

<p>It also stores and returns the protocol name.</p>
<example file="src/example/Magic8BallProtocol.java">
  private String _protocolName = "magic8ball";

  ...

  /**
   * Return the protocol name.
   */
  public String getProtocolName()
  {
    return _protocolName;
  }
  
  /**
   * Set the protocol name.
   */
  public void setProtocolName(String name)
  {
    _protocolName = name;
  }
</example>

</section>

<section title="com.caucho.server.port.ServerRequest">

<p><a href="javadoc|com.caucho.server.port.ServerRequest|"/> is the interface
used for implementing the class that handles a request.  This is where the bulk
of the work is done.</p>
 
<p>The method <code>handleRequest()</code> is called for each request.
Implementations should <i>not</i> assume that a new request object is created
for each new connection from a client.  Resin may reuse a request object once
it has finished handling a request.  It is guaranteed, however, that the
<code>handleRequest()</code> method of a given instance will only be handling a
single request at a time.</p>

<p>This means that any member variables must be initialized at the
beginning of the code in <code>handleRequest()</code>.</p>

<p>The first step in handleRequest() is usually to obtain a <a
href="javadoc|com.caucho.vfs.ReadStream|"/> and a <a
href="javadoc|com.caucho.vfs.WriteStream|"/> from the Connection that was
stored with the constructor.  These streams are used to read raw data from the client and write raw data to the client.</p>

<p>This tutorial then goes on to initialize a parser and perform appropriate
commands, depending on what is submitted by the client.  The readStream is used
to determine what to do, and the writeStream is used to send the response.  The
implementation here depends on the protocol that is being supported.</p>

<example file="src/example/Magic8BallRequest.java">
  ...

  /**
   * Handle a new connection.  The controlling Server may call
   * handleRequest again after the connection completes, so the
   * implementation must initialize any variables for each connection.
   */
  public boolean handleRequest() throws IOException
  {
    ReadStream readStream = _conn.getReadStream();
    WriteStream writeStream = _conn.getWriteStream();

    try {
      _parser.init(readStream);

    ...

        if (error != null) {
          writeStream.print("ERROR: ");
          writeStream.println(_parser.getError());
          break;
        }
        else if (result != null) {
          writeStream.print("RESULT: ");
          writeStream.println(result);
        }

    ...

    } catch (Throwable e) {
      log.log(Level.WARNING, e.toString(), e);
    }

    return false;
  }

</example>

</section>

<section title="Deployment and Configuration">

<p>The protocol is handled at the <i>server</i> level in the Resin Environment
hierarchy.  This means that the code has to be available to the appropriate
classloader.  A jar with your code in it can be placed in
<code>$RESIN_HOME/lib/</code>, for example
<code>$RESIN_HOME/lib/magic8ball.jar</code>.</p>

<p>The use of the Protocol class is configured with <a config-tag="port"/> and
<a config-tag="protocol"/>.</p>

<example title="Custom protocol configuration in resin.conf">
  &lt;server&gt;

    ...

    &lt;!-- The magic8ball port --&gt;
    &lt;port id='' host='*' port='8888'&gt;
      &lt;protocol resin:type="example.Magic8BallProtocol"/&gt;
    &lt;/port&gt;

</example>

</section>

<section title="Demo">

<p>This tutorial has to be deployed by hand in your installation of 
Resin.</p>

<section title="1. find the tutorial">
<p>The filesystem location of this tutorial is at the top of this page.</p>
</section>

<section title="2. add the entry to resin.conf">
<example title="Custom protocol configuration in resin.conf">
  &lt;server&gt;

    ...

    &lt;!-- The magic8ball port --&gt;
    &lt;port id='' host='*' port='8888'&gt;
      &lt;protocol resin:type="example.Magic8BallProtocol"/&gt;
    &lt;/port&gt;

</example>
</section>

<section title="3. build and deploy the library">

<p>To run the demo, you can find the <code>build/magic8ball.jar</code> file and
copy it to <code>$RESIN_HOME/lib/</code>.</p>

<p>An <code>ant</code> build file is provided.  Calling "ant deploy" will build the jar and deploy it in <code>$RESIN_HOME/lib/magic8ball.jar</code></p>

</section>

<section title="4. start Resin or wait for a restart">

<p>Start Resin, or if it is already running wait for it to notice the new
library and restart.  The default Resin configuration will notice the new jar
file (eventually) and restart itself.  If you are impatient you can stop and
start the server yourself.</p>

<example title="Example output from Resin showing the magic8ball protocol port">
Starting Resin on Tue, 23 Sep 2003 15:40:16 -0500 (GMT-05:00)
[15:40:17.920] Loaded Socket JNI library.
[15:40:38.871] http listening to *:8080
[15:40:59.831] magic8ball listening to *:8888
...
</example>

</section>

<section title="5. test using telnet">

<p>The simplest way to test a protocol like the <code/magic8ball/> is to use
telnet.</p>

<example title="Telnet test of the magic8ball protocol">
$ <b/telnet localhost 8888/>
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
<b/ASK/>
RESULT: trelawney says "The future for you is very dire"
<b/ASK/>
RESULT: trelawney says "You must not leave the room"
<b/SET-PROPHET classic/>
RESULT: prophet set to `classic'
<b/ASK/>
RESULT: classic says "It is certain"
<b/SET-PROPHET kingwu/>
RESULT: prophet set to `kingwu'
<b/ASK/>
RESULT: kingwu says "THE CREATIVE works sublime success, Furthering through perseverance."
<b/SET-PROPHET xxxxx/>
RESULT: prophet set to `xxxxx'
<b/ASK/>
RESULT: xxxxx says "a false prophet is never wise"
<b/QUIT/>
ERROR: Unknown command `QUIT'
Connection closed by foreign host.
</example>
</section>
</section>

<section title="Compatibility">

<p>The <a href="javadoc|com.caucho.server.port.Protocol|"/> and
<a href="javadoc|com.caucho.server.port.ServerRequest|"/> classes are of
course Resin specific.  The <a href="javadoc|com.caucho.vfs.ReadStream|"/> and
<a href="javadoc|com.caucho.vfs.ReadStream|"/> are as well.</p>

<p>If portability is a concern, implement a class that is similar in
functionality to <a href="javadoc|com.caucho.server.port.ServerRequest|"/>.
Code that class to get passed a <a href="javadoc|java.io.InputStream|"/> and a
<a href="javadoc|java.io.OutputStream|"/>.  A bare-bones Resin-specific
<code>Protocol</code> and <code>ServerRequest</code> can be used as a thin
wrapper to your custom <var/Request/> class, and the Resin's ReadStream and
WriteStream can be passed as the <code>InputStream</code> and
<code>OutputStream</code>.  When porting to another application server (if they
provide this kind of functionality) you can code a thin-wrapper specific to
that app-server that uses your custom Request class.</p> 

</section>
</body>
</document>



