A content handler is an instance of a subclass of java.net.ContentHandler :
public abstract class ContentHandler extends Object
| || |
The SAX2 API for XML parsing defines a completely separate interface named ContentHandler . This has nothing to do with the content handlers we're discussing in this chapter.
This class knows how to take a URLConnection and a MIME type and turn the data coming from the URLConnection into a Java object of an appropriate type. Thus, a content handler allows a program to understand new kinds of data. Since Java lowers the bar for writing code below what's needed to write a browser or a Netscape plug-in, the theory is that many different web sites can write custom handlers, rather than having to rely on the overworked browser manufacturers.
Java can already download classes from the Internet. Thus, there isn't much magic to getting it to download a class that can understand a new content type. A content handler is just a .class file like any other. The magic is all inside the browser, which knows when and where to request a .class file to view a new content type. Of course, some browsers are more magical than others. Currently, the only way to make this work in a browser is in conjunction with an applet that knows how to request the content handler explicitly. It can also be usedin fact, more easilyin a standalone application that ignores browsers completely.
Specifically, a content handler reads data from a URLConnection and constructs an object appropriate for the content type from the data. Each subclass of ContentHandler handles a specific MIME type and subtype, such as text/plain or image/gif . Thus, an image/gif content handler returns a URLImageSource object (a class that implements the ImageProducer interface), while a text/plain content handler returns a String . A database content handler might return a java.sql.ResultSet object. An application/x-macbinhex40 content handler might return a BinhexDecoder object written by the same programmer who wrote the application/x-macbinhex40 content handler.
Content handlers are intimately tied to protocol handlers. In the previous chapter, the getContent() method of the URLConnection class returned an InputStream that fed the data from the server to the client. This works for simple protocols that only return ASCII text, such as finger, whois, and daytime. However, returning an input stream doesn't work well for protocols such as FTP, gopher, and HTTP, which can return a lot of different content types, many of which can't be understood as a stream of ASCII text. For protocols like these, getContent( ) needs to check the MIME type and use the createContentHandler() method of the application's ContentHandlerFactory to produce a matching content handler. Once a ContentHandler exists, the URLConnection 's getContent( ) method calls the ContentHandler 's getContent( ) method, which creates the Java object to be returned. Outside of the getContent() method of a URLConnection , you rarely, if ever, call any ContentHandler method. Applications should never call the methods of a ContentHandler directly. Instead, they should use the getContent( ) method of URL or URLConnection .
An object that implements the ContentHandlerFactory interface is responsible for choosing the right ContentHandler to go with a MIME type. The static URLConnection.setContentHandlerFactory( ) method installs a ContentHandlerFactory in a program. Only one ContentHandlerFactory may be chosen during the lifetime of an application. When a program starts running, there is no ContentHandlerFactory ; that is, the ContentHandlerFactory is null .
When there is no factory, Java looks for content handler classes with the name type . subtype , where type is the MIME type of the content (e.g., text ) and subtype is the MIME subtype (e.g., html ). It looks for these classes first in any packages named by the java.content.handler.pkgs property, then in the sun.net.www.content package. The java.content.handler.pkgs property should contain a list of package prefixes separated from each other by a vertical bar (). This is similar to how Java finds protocol handlers. For example, if the java.content.handler.pkgs property has the value com.macfaq.net.www.contentorg.cafeaulait.content and a program needs a content handler for application/xml files, it first tries to instantiate com.macfaq.net.www.content.application.xml . If that fails, it next tries to instantiate org.cafeaulait.content.application.xml . If that fails, as a last resort, it tries to instantiate sun.net.www.content.application.xml . These conventions are also used to search for a content handler if a ContentHandlerFactory is installed but the createContentHandler( ) method returns null .
To summarize, here's the sequence of events:
A URL object is created that points at some Internet resource.
The URL 's getContent() method is invoked.
The getContent( ) method of the URL calls the getContent( ) method of its underlying URLConnection .
The URLConnection.getContent( ) method calls the nonpublic method getContentHandler( ) to find a content handler for the MIME type and subtype.
getContentHandler( ) checks to see whether it already has a handler for this type in its cache. If it does, that handler is returned to getContent( ) . Thus, browsers won't download content handlers for common types such as text/html every time the user goes to a new web page.
If there wasn't an appropriate ContentHandler in the cache and the ContentHandlerFactory isn't null , getContentHandler( ) calls the ContentHandlerFactory 's createContentHandler( ) method to instantiate a new ContentHandler . If this is successful, the ContentHandler object is returned to getContent( ) .
If the ContentHandlerFactory is null or createContentHandler( ) fails to instantiate a new ContentHandler , Java looks for a content handler class named type . subtype , where type is the MIME type of the content and subtype is the MIME subtype in one of the packages named in the java.content.handler.pkgs system property. If a content handler is found, it is returned. Otherwise...
Java looks for a content handler class named sun.net.www.content . type . subtype . If it's found, it's returned. Otherwise, createContentHandler( ) returns null .
If the ContentHandler object is not null , the ContentHandler 's getContent( ) method is called. This method returns an object appropriate for the content type. If the ContentHandler is null , an IOException is thrown.
Either the returned object or the exception is passed up the call chain, eventually reaching the method that invoked getContent( ) .
You can affect this chain of events in three ways: first, by constructing a URL and calling its getContent( ) method; second, by creating a new ContentHandler subclass that getContent() can use; and third, by installing a ContentHandlerFactory with URLConnection.setContentHandlerFactory( ) , changing the way the application looks for content handlers.