15.4 Configuring the Connection

     

The URLConnection class has seven protected instance fields that define exactly how the client makes the request to the server. These are:

 protected URL     url; protected boolean doInput = true; protected boolean doOutput = false; protected boolean allowUserInteraction = defaultAllowUserInteraction; protected boolean useCaches = defaultUseCaches; protected long    ifModifiedSince = 0; protected boolean connected = false; 

For instance, if doOutput is true , you'll be able to write data to the server over this URLConnection as well as read data from it. If useCaches is false , the connection bypasses any local caching and downloads the file from the server afresh.

Since these fields are all protected, their values are accessed and modified via obviously named setter and getter methods :

 public URL     getURL( ) public void    setDoInput(boolean doInput) public boolean getDoInput( ) public void    setDoOutput(boolean doOutput) public boolean getDoOutput( ) public void    setAllowUserInteraction(boolean allowUserInteraction) public boolean getAllowUserInteraction( ) public void    setUseCaches(boolean useCaches) public boolean getUseCaches( ) public void    setIfModifiedSince(long ifModifiedSince) public long    getIfModifiedSince( ) 

You can modify these fields only before the URLConnection is connected (that is, before you try to read content or headers from the connection). Most of the methods that set fields throw an IllegalStateException if they are called while the connection is open . In general, you can set the properties of a URLConnection object only before the connection is opened.

In Java 1.3 and earlier, the setter methods throw an IllegalAccessError instead of an IllegalStateException . Throwing an error instead of an exception here is very unusual. An error generally indicates an unpredictable fault in the VM, which usually cannot be handled, whereas an exception indicates a predictable, manageable problem. More specifically , an IllegalAccessError is supposed to indicate that an application is trying to access a nonpublic field it doesn't have access to. According to the class library documentation, "Normally, this error is caught by the compiler; this error can only occur at runtime if the definition of a class has incompatibly changed." Clearly, that's not what's going on here. This was simply a mistake on the part of the programmer who wrote this class, which has been fixed as of Java 1.4.


There are also some getter and setter methods that define the default behavior for all instances of URLConnection . These are:

 public boolean            getDefaultUseCaches( ) public void               setDefaultUseCaches(boolean defaultUseCaches) public static void        setDefaultAllowUserInteraction(                        boolean defaultAllowUserInteraction) public static boolean     getDefaultAllowUserInteraction( ) public static FileNameMap getFileNameMap( ) public static void        setFileNameMap(FileNameMap map) 

Unlike the instance methods, these methods can be invoked at any time. The new defaults will apply only to URLConnection objects constructed after the new default values are set.

15.4.1 protected URL url

The url field specifies the URL that this URLConnection connects to. The constructor sets it when the URLConnection is created and it should not change thereafter. You can retrieve the value by calling the getURL( ) method. Example 15-6 opens a URLConnection to http://www.oreilly.com/, gets the URL of that connection, and prints it.

Example 15-6. Print the URL of a URLConnection to http://www.oreilly.com/
 import java.net.*; import java.io.*; public class URLPrinter {   public static void main(String args[]) {     try {       URL u = new URL("http://www.oreilly.com/");       URLConnection uc = u.openConnection( );       System.out.println(uc.getURL( ));     }     catch (IOException ex) {       System.err.println(ex);     }   } } 

Here's the result, which should be no great surprise. The URL that is printed is the one used to create the URLConnection .

 %  java URLPrinter  http://www.oreilly.com/ 

15.4.2 protected boolean connected

The boolean field connected is true if the connection is open and false if it's closed. Since the connection has not yet been opened when a new URLConnection object is created, its initial value is false . This variable can be accessed only by instances of java.net.URLConnection and its subclasses.

There are no methods that directly read or change the value of connected . However, any method that causes the URLConnection to connect should set this variable to true, including connect( ) , getInputStream( ) , and getOutputStream( ) . Any method that causes the URLConnection to disconnect should set this field to false. There are no such methods in java.net.URLConnection , but some of its subclasses, such as java.net.HttpURLConnection , have disconnect( ) methods.

If you subclass URLConnection to write a protocol handler, you are responsible for setting connected to true when you are connected and resetting it to false when the connection closes . Many methods in java.net.URLConnection read this variable to determine what they can do. If it's set incorrectly, your program will have severe bugs that are not easy to diagnose.

15.4.3 protected boolean allowUserInteraction

Some URLConnection s need to interact with a user. For example, a web browser may need to ask for a username and password. However, many applications cannot assume that a user is present to interact with it. For instance, a search engine robot is probably running in the background without any user to provide a username and password. As its name suggests, the allowUserInteraction field specifies whether user interaction is allowed. It is false by default.

This variable is protected, but the public getAllowUserInteraction() method can read its value and the public setAllowUserInteraction() method can change it:

 public void    setAllowUserInteraction(boolean allowUserInteraction) public boolean getAllowUserInteraction( ) 

The value true indicates that user interaction is allowed; false indicates that there is no user interaction. The value may be read at any time but may be set only before the URLConnection is connected. Calling setAllowUserInteraction( ) when the URLConnection is connected throws an IllegalStateException in Java 1.4 and later, and an IllegalAccessError in Java 1.3 and earlier.

For example, this code fragment opens a connection that could ask the user for authentication if it's required:

 URL u = new URL("http://www.example.com/passwordProtectedPage.html"); URLConnection uc = u.openConnection( ); uc.setAllowUserInteraction(true); InputStream in = uc.getInputStream( ); 

Java does not include a default GUI for asking the user for a username and password. If the request is made from an applet, the browser's usual authentication dialog can be relied on. In a standalone application, you first need to install an Authenticator , as discussed in Chapter 7.

Figure 15-1 shows the dialog box that pops up when you try to access a password-protected page. If you cancel this dialog, you'll get a 401 Authorization Required error and whatever text the server sends to unauthorized users. However, if you refuse to send authorization at allwhich you can do by pressing OK, then answering No when asked if you want to retry authorization getInputStream( ) will throw a ProtocolException .

Figure 15-1. An authentication dialog
figs/jnp3_1501.gif

The static getDefaultAllowUserInteraction() and setDefaultAllowUserInteraction( ) methods determine the default behavior for URLConnection objects that have not set allowUserInteraction explicitly. Since the allowUserInteraction field is static (i.e., a class variable instead of an instance variable), setting it changes the default behavior for all instances of the URLConnection class that are created after setDefaultAllowUserInteraction( ) is called.

For instance, the following code fragment checks to see whether user interaction is allowed by default with getDefaultAllowUserInteraction( ) . If user interaction is not allowed by default, the code uses setDefaultAllowUserInteraction( ) to make allowing user interaction the default behavior.

 if (!URLConnection.getDefaultAllowUserInteraction( )) {   URLConnection.setDefaultAllowUserInteraction(true); } 

15.4.4 protected boolean doInput

Most URLConnection objects provide input to a client program. For example, a connection to a web server with the GET method would produce input for the client. However, a connection to a web server with the POST method might not. A URLConnection can be used for input to the program, output from the program, or both. The protected boolean field doInput is true if the URLConnection can be used for input, false if it cannot be. The default is true . To access this protected variable, use the public getDoInput() and setDoInput() methods:

 public void    setDoInput(boolean doInput) public boolean getDoInput( ) 

For example:

 try {   URL u = new URL("http://www.oreilly.com");   URLConnection uc = u.openConnection( );   if (!uc.getDoInput( )) {     uc.setDoInput(true);   }   // read from the connection... catch (IOException ex) {   System.err.println(ex); } 

15.4.5 protected boolean doOutput

Programs can use a URLConnection to send output back to the server. For example, a program that needs to send data to the server using the POST method could do so by getting an output stream from a URLConnection . The protected boolean field doOutput is true if the URLConnection can be used for output, false if it cannot be; it is false by default. To access this protected variable, use the getDoOutput( ) and setDoOutput( ) methods:

 public void    setDoOutput(boolean dooutput) public boolean getDoOutput( ) 

For example:

 try {   URL u = new URL("http://www.oreilly.com");   URLConnection uc = u.openConnection( );   if (!uc.getDoOutput( )) {     uc.setDoOutput(true);   }   // write to the connection... catch (IOException ex) {   System.err.println(ex); } 

When you set doOutput to true for an http URL, the request method is changed from GET to POST. In Chapter 7, you saw how to send data to server-side programs with GET. GET is straightforward to work with, but its use should be limited to "safe" operations: operations that don't commit the user or have obvious side effects. For instance, it would be inappropriate to use GET to complete a purchase or add an item to a shopping cart, but you could use GET to search for the items before placing them in the cart. Unsafe operations, which should not be bookmarked or cached, should use POST (or occasionally PUT or DELETE) instead. We'll explore this in more detail later in this chapter when we talk about writing data to a server.

In earlier editions of this book, I suggested using the POST method in preference to GET for long (greater than 255 characters ) URLs since some browsers had limits on the maximum length of a URL they could safely handle. In 2004, this is only really an issue with very old browsers no one is likely to be using anymore. I was planning not to even mention this issue in this chapter; but as I worked on an unrelated project during the revision of this chapter, I encountered a server-side limitation on URL size while writing a PHP script to process a form. I had over a thousand different fields in a form (a checklist of bird species found in New York City along with observation notes) and over 10K of data in each request. The browser handled the long URL with aplomb. However, faced with such an extreme case, the server refused to process the request until I switched from GET to POST. Thus for very long URLs, POST may still be necessary, even for safe operations. Alternately, you could fix the server so it doesn't object to long URLs; but for those of us who don't manage our own servers, this may not always be an option.


15.4.6 protected boolean ifModifiedSince

Many clients , especially web clients, keep caches of previously retrieved documents. If the user asks for the same document again, it can be retrieved from the cache. However, it may have changed on the server since it was last retrieved. The only way to tell is to ask the server. Clients can include an If-Modified-Since in the client request HTTP header. This header includes a date and time. If the document has changed since that time, the server should send it. Otherwise, it should not. Typically, this time is the last time the client fetched the document. For example, this client request says the document should be returned only if it has changed since 7:22:07 A.M., October 31, 2004, Greenwich Mean Time:

 GET / HTTP/1.1 User-Agent: Java/1.4.2_05 Host: login.metalab.unc.edu:56452 Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2 Connection: close If-Modified-Since: Sun, 31 Oct 2004 19:22:07 GMT 

If the document has changed since that time, the server will send it as usual. Otherwise, it replies with a 304 Not Modified message, like this:

 HTTP/1.0 304 Not Modified Server: WN/1.15.1 Date: Tue, 02 Nov 2004 16:26:16 GMT Last-modified: Fri, 29 Oct 2004 23:40:06 GMT 

The client then loads the document from its cache. Not all web servers respect the If-Modified-Since field. Some will send the document whether it's changed or not.

The ifModifiedSince field in the URLConnection class specifies the date (in milliseconds since midnight, Greenwich Mean Time, January 1, 1970), which will be placed in the If-Modified-Since header field. Because ifModifiedSince is protected , programs should call the getIfModifiedSince( ) and setIfModifiedSince( ) methods to read or modify it:

 public long getIfModifiedSince( ) public void setIfModifiedSince(long ifModifiedSince) 

Example 15-7 prints the default value of ifModifiedSince , sets its value to 24 hours ago, and prints the new value. It then downloads and displays the documentbut only if it's been modified in the last 24 hours.

Example 15-7. Set ifModifiedSince to 24 hours prior to now
 import java.net.*; import java.io.*; import java.util.*; public class Last24 {   public static void main (String[] args) {     // Initialize a Date object with the current date and time     Date today = new Date( );     long millisecondsPerDay = 24 * 60 * 60 * 1000;     for (int i = 0; i < args.length; i++) {       try {         URL u = new URL(args[i]);         URLConnection uc = u.openConnection( );         System.out.println("Will retrieve file if it's modified since "          + new Date(uc.getIfModifiedSince( )));         uc.setIfModifiedSince((new Date(today.getTime( )            - millisecondsPerDay)).getTime( ));         System.out.println("Will retrieve file if it's modified since "          + new Date(uc.getIfModifiedSince( )));         InputStream in = new BufferedInputStream(uc.getInputStream( ));         Reader r = new InputStreamReader(in);         int c;         while ((c = r.read( )) != -1) {           System.out.print((char) c);         }          System.out.println( );                }       catch (Exception ex) {         System.err.println(ex);       }     }   } } 

Here's the result. First, we see the default value: midnight, January 1, 1970, GMT, converted to Pacific Standard Time. Next , we see the new time, which we set to 24 hours prior to the current time:

 %  java Last24 http://www.oreilly.com  Will retrieve file if it's been modified since Wed Dec 31 16:00:00 PST 1969 Will retrieve file if it's been modified since Sun Oct 31 11:17:04 PST 2004 

Since this document hasn't changed in the last 24 hours, it is not reprinted.

15.4.7 protected boolean useCaches

Some clients, notably web browsers, can retrieve a document from a local cache, rather than retrieving it from a server. Applets may have access to the browser's cache. Starting in Java 1.5, standalone applications can use the java.net.ResponseCache class described later in this chapter. The useCaches variable determines whether a cache will be used if it's available. The default value is true , meaning that the cache will be used; false means the cache won't be used. Because useCaches is protected , programs access it using the getUseCaches( ) and setUseCaches() methods:

 public void    setUseCaches(boolean useCaches) public boolean getUseCaches( ) 

This code fragment disables caching to ensure that the most recent version of the document is retrieved:

 try {   URL u = new URL("http://www.sourcebot.com/");   URLConnection uc = u.openConnection( );   if (uc.getUseCaches( )) {     uc.setUseCaches(false);   } } catch (IOException ex) {   System.err.println(ex); } 

Two methods define the initial value of the useCaches field, getDefaultUseCaches() and setDefaultUseCaches( ) :

 public void    setDefaultUseCaches(boolean useCaches) public boolean getDefaultUseCaches( ) 

Although nonstatic, these methods do set and get a static field that determines the default behavior for all instances of the URLConnection class created after the change. The next code fragment disables caching by default; after this code runs, URLConnection s that want caching must enable it explicitly using setUseCaches(true) .

 if (uc.getDefaultUseCaches( )) {   uc.setDefaultUseCaches(false); } 

15.4.8 Timeouts

Java 1.5 adds four methods that allow you to query and modify the timeout values for connections; that is, how long the underlying socket will wait for a response from the remote end before throwing a SocketTimeoutException . These are:

 public void setConnectTimeout(int timeout)   // Java 1.5 public int  getConnectTimeout( )              // Java 1.5 public void setReadTimeout(int timeout)      // Java 1.5 public int  getReadTimeout( )                 // Java 1.5 

The setConnectTimeout() / getConnectTimeout( ) methods control how long the socket waits for the initial connection. The setReadTimeout() / getReadTimeout( ) methods control how long the input stream waits for data to arrive . All four methods measure timeouts in milliseconds. All four interpret as meaning never time out. Both setter methods throw an IllegalArgumentException if the timeout is negative. For example, this code fragment requests a 30-second connect timeout and a 45-second read timeout:

 URL u = new URL("http://www.example.org"); URLConnuction uc = u.openConnection( ); uc.setConnectTimeout(30000); uc.setReadTimeout(45000); 



Java Network Programming
Java Network Programming, Third Edition
ISBN: 0596007213
EAN: 2147483647
Year: 2003
Pages: 164

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net