Chapter 29

Protocol Handlers


CONTENTS


In this chapter you'll learn how to write protocol handlers to support the use of custom protocols by Web browsers. You'll also learn how Web browsers implement protocols other than HTTP and how they are integrated with the browser's operation. You'll develop a simple protocol handler and integrate it with a Web client program. This chapter builds on the material presented in Chapter 17, "Network Programming with the java.net Package."

Using Protocol Handlers

Most popular Web browsers support protocols other than HTTP. These other protocols include FTP, gopher, e-mail, and application-specific protocols. Support for these protocols is usually built into the browser, causing the browser to become larger and slower to load.

Java supports additional protocols through the use of protocol handlers, also referred to as stream handlers. These protocol handlers are used to retrieve Web objects using application-specific protocols. The protocols are specified in the URL referencing the object.

Protocol handlers are implemented as subclasses of the URLStreamHandler class. The URLStreamHandler class defines four access methods that can be overridden by its subclasses, but only the openConnection() method is required to be overridden.

The openConnection() method takes an URL with its assigned protocol as a parameter and returns an object of class URLConnection. The URLConnection object can then be used to create input and output streams and to access the resource addressed by the URL.

The parseURL() and setURL() methods are used to implement custom URL syntax parsing. The toExternalForm() method is used to convert an URL of the protocol type to a String object.

The purpose of a protocol handler is to implement a custom protocol needed to access Web objects identified by URLs that require the custom protocol. Protocol handlers, like content handlers, are not directly instantiated or accessed. The methods of the URLConnection object that is returned by a protocol handler are invoked to access the resource referenced by the protocol.

A protocol is identified beginning with the first character of the URL and continuing to the first colon (:) contained in the URL. For example, the protocol of the URL http://www.jaworski.com is http and the protocol of the URL fortune://jaworski.com is fortune.

A protocol handler is associated with a specific protocol through the use of the URLStreamHandlerFactory interface. A class that implements the URLStreamHandlerFactory interface must implement the createURLStreamHandler() method. This method returns an URLStreamHandler object to be used for a specific protocol. An URLStreamHandlerFactory object is installed using the static setURLStreamHandlerFactory() method of the URL class.

Developing a Protocol Handler

The first step to implement a protocol handler is to define the protocol handler as a subclass of the URLStreamHandler class. The openConnection() method of the protocol handler creates an URLConnection object that can be used to access an URL designating the specified protocol.

A protocol handler is associated with a specific protocol type through the use of an URLStreamHandlerFactory object. The createURLStreamHandler() method of the URLStreamHandlerFactory interface is used to return a protocol handler for a specific protocol type.

The setURLStreamHandlerFactory() method of the URL class is used to set an URLStreamHandlerFactory as the default URLStreamHandlerFactory to be used with all protocol types.

A Simple Protocol Handler

This section presents an example of implementing a simple protocol handler. My ncSA server comes with a CGI program, named fortune, that returns a fortune cookie-type message when the program's URL is accessed. This section defines the fortune protocol to access the fortune program on my Web server and on other ncSA Web servers. The fortune protocol is not a real Internet protocol; I contrived it to illustrate the use of protocol handlers. The URL for the fortune protocol consists of fortune:// followed by the host name. For example, fortune://jaworski.com accesses the fortune protocol on my Web server.

The definition of the URLFortuneHandler class is shown in Listing 29.1.


Listing 29.1. The source code for the URLFortuneHandler class.

import java.net.*;
import java.io.*;

public class URLFortuneHandler extends URLStreamHandler {
 public URLConnection openConnection(URL url) throws IOException {
  String host=url.getHost();
  URL newURL = new URL("http://"+host+"/cgi-bin/fortune");
  return newURL.openConnection();
 }
}


The URLFortuneHandler class extends the URLStreamHandler class and provides a single method. The openConnection() method takes an URL object as a parameter and returns an object of the URLConnection class. It also throws the IOException exception.

The openConnection() method uses the getHost() method of the URL class to extract the host name contained in the URL. It then uses a new http URL by concatenating http:// with the host name and then the location of the fortune CGI program, /cgi-bin/fortune. The openConection() method of the URL class is used to return the URLConnection object associated with the new URL.

The URLFortuneHandler class wraps the fortune CGI program using the fortune protocol. This protocol is implemented through an HTTP connection to the CGI program.

The GetFortuneApp Program

The GetFortuneApp program illustrates the use of protocol handlers. It accesses the fortune CGI program on my Web server using the fortune protocol. The source code of the GetFortuneApp program is shown in Listing 29.2.


Listing 29.2. The source code for the GetFortuneApp program.

import java.net.*;
import java.io.*;

public class GetFortuneApp {
 public static void main(String args[]){
  try{
   FortuneFactory fortuneFactory = new FortuneFactory();
   URL.setURLStreamHandlerFactory(fortuneFactory);
   if(args.length!=1) error("Usage: java GetFortuneApp FortuneURL");
   System.out.println("Fetching URL: "+args[0]);
   URL url = new URL(args[0]);
   System.out.println((String) url.getContent());
  }catch (MalformedURLException ex){
   error("Bad URL");
  }catch (IOException ex){
   error("IOException occurred.");
  }
 }
 public static void error(String s){
  System.out.println(s);
  System.exit(1);
 }
}
class FortuneFactory implements URLStreamHandlerFactory {
 public FortuneFactory() {
 }
 public URLStreamHandler createURLStreamHandler(String protocol) {
  if(protocol.equals("fortune")){
   System.out.println("Requested protocol: "+protocol);
   return new URLFortuneHandler();
  }
  return null;
 }
}


When you invoke the GetFortuneApp program, provide it with the fortune://jaworski.com URL as a parameter. The GetFortuneApp program's output is as follows (you will get a different fortune each time you execute the program):

C:\java\jdg\ch29>java GetFortuneApp fortune://jaworski.com
Fetching URL: fortune://jaworski.com
Requested protocol: fortune
JACK AND THE BEANSTACK
by Mark Isaak
Long ago, in a finite state far away, there lived a JOVIAL

character named Jack. Jack and his relations were poor. Often their hash table was bare. One day Jack's parent said to him, "Our matrices are sparse. You must go to the market to exchange our RAM for some BASICs." She compiled a linked list of items to retrieve and passed it to him.

So Jack set out. But as he was walking along a Hamilton path, he met the traveling salesman.

"Whither dost thy flow chart take thou?" prompted the salesman in high-level language.

"I'm going to the market to exchange this RAM for some chips and Apples," commented Jack.

"I have a much better algorithm. You needn't join a queue there; I will swap your RAM for these magic kernels now."

Jack made the trade, then backtracked to his house. But when he told his busy-waiting parent of the deal, she became so angry she started thrashing.

"Don't you even have any artificial intelligence? All these kernels together hardly make up one byte," and she popped them out the window ...

C:\java\jdg\ch29>

GetFortuneApp connects to my Web server, invokes the fortune CGI program, and then displays the program's results.

The main() method creates an object of the FortuneFactory class that implements the URLStreamHandlerFactory interface. It then sets the object as the default protocol handler. An URL object is created using the URL string passed as the program's parameter. The getContent() method of the URL class is then used to extract the information generated by accessing the URL using the fortune protocol. The getContent() method results in the FortuneFactory object assigned to the fortuneFactory variable being invoked to retrieve an appropriate protocol handler. An object of class URLFortuneHandler is returned and its openConnection() method is invoked to extract the URLConnection object. This is performed behind the scenes as the result of invoking the URL class's getContent() method. The information returned from accessing the URL is then displayed.

The GetFortuneApp program defines the FortuneFactory class as implementing the URLStreamHandlerFactory interface. It implements the createURLStreamHandler() method and checks to see if the protocol type passed to it is fortune. If it is not, the null value is returned to signal that the Java-supplied protocol handler should be used. If the protocol type is fortune, the requested protocol is displayed and an URLFortuneHandler object is returned.

Summary

In this chapter you have learned how to write protocol handlers to access URLs via custom protocols. You have developed the URLFortuneHandler and integrated it with the GetFortuneApp program. This chapter marks the conclusion of the networking part of this book. Part VI, "Programming the Web with Applets and Scripts," shows you how to develop Java applets.