Exercise 6-1. The FileCopy3 program in Example 6-4 omits exception-handling and channel-closing
code for simplicity. Make this program more robust by adding that
code, using Example 6-2, or other examples, as a
Exercise 6-2. The ChannelToWriter.copy( ) method of Example 6-5 reads bytes from a
ReadableByteChannel, decodes them using a
CharsetDecoder, and writes the resulting
characters to a Writer. Write a method that does
the reverse: reads characters from a Reader, encodes them using a
CharsetEncoder, and writes the resulting bytes to
a WritableByteChannel. Use a low-level encoding
loop based on the decoding loop of Example 6-5.
Exercise 6-3. The BGrep class of Example 6-3 is
a block-oriented rather than line-oriented regular-expression
matcher. Modify the program to search a line at a time, rather than
searching an entire file at a time. The easiest way to do this is
probably to abandon the java.nio package and use
java.io.BufferedReader to read lines. An
alternative is to use the scan( ) method of the
ChannelTokenizer class (see Examples Example 6-8 and Example 2-8).
Exercise 6-4. The HttpGet program in Example 6-9 discards HTTP headers. Modify it with a
-h command-line option, which, when present,
causes it to print out the headers it receives.
Exercise 6-5. A shortcoming of the HttpGet program of Example 6-9 is that it does not understand and follow HTTP
redirects. Some servers use these HTTP response codes to distribute
load, and HttpGet is unable to download pages from
such servers. Modify the program so that if the response code is in
the 300-399 range, it parses the HTTP headers, looking for one that
begins "Location:". If it finds
such a header, it prints a message and attempts to fetch the URL that
follows it. If you don't want to write a
full-featured HTTP header parser, note that you can convert the
headers to a string, and then simply use string methods to search for
"\nLocation:" within that string.
Exercise 6-6. The PrintServiceWebInterface class of Example 6-13 uses the
GatheringByteChannel interface to send response
data from a ByteBuffer array. It divides its
response up into a set of fixed headers and a variable body. In fact,
however, the first part of the body is also fixed. Additionally, a
more robust implementation would include a
"Content-Length:" header that
specifies the (variable) length, in bytes, of the body. Modify the
program to address these two issues by using an array of four buffers
instead of two. The first buffer would hold the fixed part of the
headers. The second would hold the variable Content-Length header and
the header-terminating blank line. The third buffer would hold the
fixed part of the document body, and the fourth would hold the
variable part of the body. This fourth buffer would be filled, and
its length measured, before the second buffer was filled. If you
added a "print headers" option to
HttpGet in the previous exercise, you can use that
modified version to test your Content-Length implementation here.
Exercise 6-7. The PrintServiceWebInterface class of Example 6-13 demonstrated a simple framework for a
multiplexing server. Modify this framework to create a generic server
framework, like that of Example 5-10. With the New
I/O API, you should need only a single thread to do this.
You'll probably want to create a per-client state
object and associate it with each SelectionKey you
Exercise 6-8. Study the HttpDownloadManager class of Example 6-14. Analyze it for weaknesses, and remedy them.
The DownloadImpl.addData( ) method inefficiently
reallocates its array every time it is called.
The Listener interface provides notification only
when the download completes or aborts; it does not provide the
information a web browser would need to monitor the progress of a
download, such as notification of connection establishment and data
It does not parse HTTP response headers, so, for example, it cannot
follow redirects and cannot tell the caller how many bytes to expect
based on the Content-Length headers.