JBoss.orgCommunity Documentation

Chapter 2. NIO Buffers

2.1. Buffers Overview
2.2. Reading from and Writing to Buffers

XNIO, like NIO, is based on the usage of buffers as implemented by the NIO buffer classes in the java.nio package. The NIO documentation defines a java.nio.Buffer as "a linear, finite sequence of elements of a specific primitive type". There are buffer types corresponding to every primitive type; however, as a practical matter, networking software will rarely use a buffer type other than java.nio.ByteBuffer.

Buffers are mutable, meaning that the data in the buffer is subject to alteration, as are the buffer's properties. Buffers are also unsafe for use in multiple threads without some type of external synchronization.

There are three primary properties of a java.nio.Buffer:

In addition, there is one property which may be derived from these: the remaining size, which is equal to the difference between the position and the limit.

These properties are used to provide boundaries for data within a buffer; typically a buffer will have a larger capacity than limit (meaning that there is more space in the buffer than there is actual useful data). The position and limit properties allow the application to deal with data that is of a possibly smaller size than the buffer's total capacity.

Data can be read from or written to buffers in two ways: using absolute operations or relative operations. The absolute operations accept a parameter which represents the absolute position of the data to be read or written; the relative operations read or write at the current position, advancing the position by the size of the item being read or written.

When writing data to an empty buffer, either via the putXXX() operations or by reading from a channel into a buffer, the limit is generally set to be equal to the capacity, with the position advancing as the buffer is filled. For the sake of discussion, this state will be called the "filling" state.

Once the buffer is satisfactorily populated from the desired source, it may be flipped by invoking the flip() method on the buffer. This sets the limit to the position, and resets the position back to the start of the buffer, effectively allowing the data to be read out of the buffer again. This state will be referred to as the "flipped" state.

If a flipped buffer's data is not able to be fully consumed, the buffer may be restored to the filling state without losing any of its remaining data by way of the compact() method. This method effectively moves the remaining data to the beginning of the buffer, sets the position to be just after the end of this data, and resets the limit to be equal to the capacity.

A buffer may be cleared at any time by way of the clear() method. This method resets the position to zero, and sets the limit to be equal to the capacity. Thus the buffer is effectively emptied and restored to the filling state.

The rewind() method restarts the position back at zero. This allows a buffer in the flipped state which was read partially or completely to be reread in whole. A buffer in the filling state is effectively cleared by this method.