custom protocol handling
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. 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 protocol server on the Hogwart's public web server. The protocol is at the same level as or , it sit's directly on top of TCP/IP.
Implementation of a protocol at the level that 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.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 com.caucho.server.port.Protocol and one which implements the interface com.caucho.server.port.ServerRequest. A custom class derived from com.caucho.server.port.Protocol is a factory that produces custom Request objects. The Protocol passes a
com.caucho.server.connection.Connection
object to the Request object it creates. The Request object uses the
The example in this tutorial is simple, it's main purpose is to override the
... /** * Create a Magic8BallRequest object for the new thread. */ public ServerRequest createRequest(Connection conn) { return new Magic8BallRequest(this, conn); } ... It also stores and returns the protocol name. private String _protocolName = "magic8ball"; ... /** * Return the protocol name. */ public String getProtocolName() { return _protocolName; } /** * Set the protocol name. */ public void setProtocolName(String name) { _protocolName = name; } 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. The method This means that any member variables must be initialized at the
beginning of the code in The first step in handleRequest() is usually to obtain a com.caucho.vfs.ReadStream and a 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. 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. ... /** * 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; } The protocol is handled at the server 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
The use of the Protocol class is configured with port and protocol. <server> ... <!-- The magic8ball port --> <port id='' host='*' port='8888'> <protocol resin:type="example.Magic8BallProtocol"/> </port> This tutorial has to be deployed by hand in your installation of Resin. 2. add the entry to resin.conf<server> ... <!-- The magic8ball port --> <port id='' host='*' port='8888'> <protocol resin:type="example.Magic8BallProtocol"/> </port> 3. build and deploy the libraryTo run the demo, you can find the An 4. start Resin or wait for a restartStart 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. 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 ... 5. test using telnetThe simplest way to test a protocol like the $ telnet localhost 8888 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. ASK RESULT: trelawney says "The future for you is very dire" ASK RESULT: trelawney says "You must not leave the room" SET-PROPHET classic RESULT: prophet set to `classic' ASK RESULT: classic says "It is certain" SET-PROPHET kingwu RESULT: prophet set to `kingwu' ASK RESULT: kingwu says "THE CREATIVE works sublime success, Furthering through perseverance." SET-PROPHET xxxxx RESULT: prophet set to `xxxxx' ASK RESULT: xxxxx says "a false prophet is never wise" QUIT ERROR: Unknown command `QUIT' Connection closed by foreign host. The com.caucho.server.port.Protocol and com.caucho.server.port.ServerRequest classes are of course Resin specific. The com.caucho.vfs.ReadStream and com.caucho.vfs.ReadStream are as well. If portability is a concern, implement a class that is similar in
functionality to com.caucho.server.port.ServerRequest.
Code that class to get passed a java.io.InputStream and a
java.io.OutputStream. A bare-bones Resin-specific
|