16.3 Writing a Protocol Handler
To
demonstrate a complete protocol handler, let's write
one for the finger protocol defined in RFC 1288 and
introduced in Chapter 9. Finger is a relatively
simple protocol compared to JDK-supported protocols such as HTTP and
FTP. The client connects to port 79 on the server and sends a list of
usernames followed by a carriage return/linefeed pair. The server
responds with ASCII text containing information about each of the
named users or, if no names are listed, a list of the currently
logged in users. For example:
% telnet rama.poly.edu 79Or to request information about a specific user:
Trying 128.238.10.212...
Connected to rama.poly.edu.
Escape character is '^]'.
Login Name TTY Idle When Where
jacola Jane Colaginae *pts/7 Tue 08:01 208.34.37.104
marcus Marcus Tullius pts/15 13d Tue 17:33 farm-dialup11.poly.e
matewan Sepin Matewan *pts/17 17: Thu 15:32 128.238.10.177
hengpi Heng Pin *pts/10 Tue 10:36 128.238.18.119
nadats Nabeel Datsun pts/12 56 Mon 10:38 128.238.213.227
matewan Sepin Matewan *pts/8 4 Sun 18:39 128.238.10.177
Connection closed by foreign host.
% telnet rama.poly.edu 79Since there's no standard for the format of a finger
Trying 128.238.10.212...
Connected to rama.poly.edu.
Escape character is '^]'.
marcus
Login Name TTY Idle When Where
marcus Marcus Tullius pts/15 13d Tue 17:33 farm-dialup11.poly.e
URL, we will start by creating one. Ideally, this should look as much
like an http URL as possible. Therefore, we will
implement a finger URL like this:
finger://hostname:port/usernamesSecond, we need to determine the content type returned by the finger
protocol's getContentType() method. New protocols such as HTTP use MIME
headers to indicate the content type; in these cases, you do not need
to override the default getContentType( ) method
provided by the URLConnection class. However,
since most protocols precede MIME, you often need to specify the MIME
type explicitly or use the static methods
URLConnection.guessContentTypeFromName(String
name) and
URLConnection.guessContentTypeFromStream(InputStream
in) to make an educated guess. This example
doesn't need anything so complicated, however. A
finger server returns ASCII text, so the getContentType() method should return the string
text/plain. The text/plain MIME
type has the advantage that Java already understands it. In the next
chapter, you'll learn how to write content handlers
that let Java understand additional MIME types.Example 16-2 is a
FingerURLConnection class that subclasses
URLConnection. This class overrides the
getContentType( ) and getInputStream(
) methods of URLConnection and
implements connect( ). It also has a constructor
that builds a new URLConnection from a URL.
Example 16-2. The FingerURLConnection class
package com.macfaq.net.www.protocol.finger;This class has two fields. connection is a
import java.net.*;
import java.io.*;
public class FingerURLConnection extends URLConnection {
private Socket connection = null;
public final static int DEFAULT_PORT = 79;
public FingerURLConnection(URL u) {
super(u);
}
public synchronized InputStream getInputStream( ) throws IOException {
if (!connected) this.connect( );
InputStream in = this.connection.getInputStream( );
return in;
}
public String getContentType( ) {
return "text/plain";
}
public synchronized void connect( ) throws IOException {
if (!connected) {
int port = url.getPort( );
if ( port < 1 || port > 65535) {
port = DEFAULT_PORT;
}
this.connection = new Socket(url.getHost( ), port);
OutputStream out = this.connection.getOutputStream( );
String names = url.getFile( );
if (names != null && !names.equals(")) {
// delete initial /
names = names.substring(1);
names = URLDecoder.decode(names);
byte[] result;
try {
result = names.getBytes("ASCII");
}
catch (UnsupportedEncodingException ex) {
result = names.getBytes( );
}
out.write(result);
}
out.write('\r');
out.write('\n');
out.flush( );
this.connected = true;
}
}
}
Socket between the client and the server. Both the
getInputStream( ) method and the connect() method need access to this field, so it
can't be a local variable. The second field is
DEFAULT_PORT, a final
static int, which contains the
finger protocol's default port; this port is used if
the URL does not specify the port explicitly.The class's constructor holds no surprises. It just
calls the superclass's constructor with the same
argument, the URL u. The
connect( ) method opens a connection to the
specified server on the specified port or, if no port is specified,
to the default finger port, 79. It sends the necessary request to the
finger server. If any usernames were specified in the file part of
the URL, they're sent. Otherwise, a blank line is
sent. Assuming the connection is successfully opened (no exception is
thrown), it sets the boolean field
connected to true. Recall from
the previous chapter that connected is a protected
field in java.net.URLConnection, which is
inherited by this subclass. The Socket that
connect( ) opens is stored in the field
connection for later use by
getInputStream( ). The connect(
) and getInputStream( ) methods are
synchronized to avoid a possible race condition on the
connected variable.The getContentType( ) method returns a
String containing a MIME type for the data. This
is used by the getContent( ) method of
java.net.URLConnection to select the appropriate
content handler. The data returned by a finger server is almost
always ASCII text or some reasonable approximation thereof, so this
getContentType( ) method always returns
text/plain. The getInputStream(
) method returns an InputStream, which
it gets from the Socket that
connect created. If the connection has not already
been established when getInputStream( ) is called,
the method calls connect( ) itself. Once you have a URLConnection, you need a subclass
of URLStreamHandler that knows how to handle a
finger server. This class needs an openConnection() method that builds a new
FingerURLConnection from a URL. Since we defined
the finger URL as a hierarchical URL, we
don't need to implement a parseURL() method. Example 16-3 is a stream handler
for the finger protocol. For the moment, we're going
to use Sun's convention for naming protocol
handlers; we call this class Handler and place it
in the package com.macfaq.net.www.protocol.finger.
Example 16-3. The finger handler class
package com.macfaq.net.www.protocol.finger;You can use HotJava to test this protocol
import java.net.*;
import java.io.*;
public class Handler extends URLStreamHandler {
public int getDefaultPort( ) {
return 79;
}
protected URLConnection openConnection(URL u) throws IOException {
return new FingerURLConnection(u);
}
}
handler. Add the following line to your
.hotjava/properties file or some other place
from which HotJava will load it:
java.protocol.handler.pkgs=com.macfaq.net.www.protocolSome (but not all) versions of HotJava may also allow you to set the
property from the command line:
% hotjava -Djava.protocol.handler.pkgs=com.macfaq.net.www.protocolYou also need to make sure that your classes are somewhere in
HotJava's class path. HotJava does not normally use
the CLASSPATH environment variable to look for classes, so just
putting them someplace where the JDK or JRE can find them may not be
sufficient. Using HotJava 3.0 on Windows with the JDK 1.3, I was able
to put my classes in the jdk1.3/jre/lib/classes
folder. Your mileage may vary depending on the version of HotJava
you're using with which version of the JDK on which
platform.Run it and ask for a URL of a site running finger, such as
utopia.poly.edu. Figure 16-1
shows the result.
Figure 16-1. HotJava using the finger protocol handler

• Table of Contents• Index• Reviews• Reader Reviews• Errata• AcademicJava Network Programming, 3rd EditionBy
Elliotte Rusty Harold Publisher: O'ReillyPub Date: October 2004ISBN: 0-596-00721-3Pages: 706
Thoroughly revised to cover all the 100+ significant updates
to Java Developers Kit (JDK) 1.5, Java Network
Programming is a complete introduction to
developing network programs (both applets and applications)
using Java, covering everything from networking fundamentals
to remote method invocation (RMI). It includes chapters on
TCP and UDP sockets, multicasting protocol and content
handlers, servlets, and the new I/O API. This is the
essential resource for any serious Java developer.