Java Network Programming (3rd ed) [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Java Network Programming (3rd ed) [Electronic resources] - نسخه متنی

Harold, Elliotte Rusty

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید








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 URLConnections
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/passwordProtectedPagel");
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
authorizationgetInputStream( ) will throw a
ProtocolException.


Figure 15-1. An authentication dialog

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,
URLConnections 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);


/ 164