Recommended: Sing it, brah! 5 fabulous songs for developers
JW's Top 5
Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs
Page 5 of 7
ByteBuffers, two related problems crop up: byte ordering and character conversion. ByteBuffer handles byte ordering internally using the ByteOrder class. It does not deal with character conversion, however. In fact, ByteBuffer doesn't even have methods for reading or writing strings. Character conversion is a complicated topic, subject to many international
standards, including the Internet Engineering Task Force's requests for comments, the Unicode Standard, and the Internet Assigned
Numbers Authority (IANA). However, almost every time you deal with character conversion, you must convert Unicode strings
to either ASCII or UTF-8. Fortunately, these are easy cases to handle. ASCII and UTF-8 are examples of character sets. A character set defines a mapping from Unicode to bytes and back again. Character sets are named according to IANA standards.
In Java, a character set is represented by an instance of java.nio.charset.Charset. As with most internationalization classes, you do not construct Charsets directly. Instead, you use the static factory method Charset.forName() to acquire an appropriate instance. Charset.availableCharsets() gives you a map of supported character set names and their Charset instances. The J2SE 1.4 beta includes eight character sets: US-ASCII, ISO-8859-1, ISO-8859-15, UTF-8, UTF-16, UTF-16BE (big
endian), UTF-16LE (little endian), and Windows-1252.Charset constructs CharsetEncoders and CharsetDecoders to convert character sequences into bytes and back again. Take another look at ReadWriteThread below. The encoder shows up twice for converting an entire CharBuffer into a ByteBuffer. readRequest, on the other hand, uses the decoder on the incoming request.
class ReadWriteThread extends Thread {
...
private Charset ascii;
...
public ReadWriteThread(Selector readSelector,
ConnectionList acceptedConnections,
File dir)
throws Exception
{
super("Reader-Writer");
...
ascii = Charset.forName("US-ASCII");
responseBuffers[0] = initializeResponseHeader();
...
}
...
protected ByteBuffer initializeResponseHeader() throws Exception {
...
// Translate the Unicode characters into ASCII bytes.
ByteBuffer buffer = ascii.newEncoder().encode(chars);
...
}
...
protected String readRequest(SelectionKey key) throws Exception {
SocketChannel incomingChannel = (SocketChannel)key.channel();
Socket incomingSocket = incomingChannel.socket();
...
int bytesRead = incomingChannel.read(readBuffer);
readBuffer.flip();
String result = asciiDecoder.decode(readBuffer).toString();
readBuffer.clear();
StringBuffer requestString = (StringBuffer)key.attachment();
requestString.append(result);
...
}
...
protected void sendError(SocketChannel channel,
RequestException error) throws Exception {
...
// Translate the Unicode characters into ASCII bytes.
buffer = ascii.newEncoder().encode(chars);
errorBufferCache.put(error, buffer);
...
}
}
You might notice that none of the existing java.io classes know how to read or write Buffers. In Merlin, Channels read data into Buffers and send data from Buffers. Channels join Streams and Readers as a key I/O construct. A channel might be thought of as a connection to some device, program, or network. At the top level,
the java.nio.channels.Channel interface just knows whether it is open or closed. A nifty feature of Channel is that one thread can be blocked on an operation, and another thread can close the channel. When the channel closes, the
blocked thread awakens with an exception indicating that the channel closed. There are several Channel classes, as shown in Figure 9.