By oleksiys on Apr 22, 2009
When you work with Grizzly 2.0, you'll most probably come to situation, when you need to read or write some data on network :))
Core Grizzly 2.0 I/O API is based on 3 main entities:
- Connection, which represents any kind of Transport connection. As example for TCP NIO Transport, one Connection represents one NIO SocketChannel.
- StreamReader represents Connection's input stream, using which it's possible to read data from Connection.
- StreamWriter represents Connection's output stream to write data to Connection.
So to read data from Connection, we need to read data from Connection's StreamReader: connection.getStreamReader().readXXX(); The similar step, but with StreamWriter, we need to make in order to write some data to Connection: connection.getStreamWriter().writeXXX(...);
StreamReader and StreamWriter API has a set of readXXX(), writeXXX() methods to work with Java primitives and arrays of primitives. For example to write float value to Connection we call corresponding StreamWriter write method: connection.getStreamWriter().writeFloat(0.3f);
How Streams could work in non-blocking?
In Grizzly 2.0 we can work with StreamReader and StreamWriter either in blocking or non-blocking mode. The mode could be checked and set using following methods: isBlocking(), setBlocking(boolean).
When Streams operate in blocking mode - all their methods, which may work asynchronously (return "Future") will work in blocking mode, and returned Future will always have ready result.
As for non-blocking mode, ok let's start from...
In order to use StreamReader in non-blocking mode - we may want to check if StreamReader has enough data to be read: streamReader.availableDataSize(); So once StreamReader has enough data - we can safely read it without blocking.
It is also possible to ask StreamReader to notify us once it will have enough data, or provide any other custom Condition, which StreamReader should check each time new data come - and notify us, once this Condition is met. For example:
Future<Integer> future = streamReader.notifyAvailable(10, completionHandler);
StreamReader returns Future object, which will mark as done, once StreamReader will have available 10 bytes for reading. At the same time we pass the CompletionHandler, which will be notified, once StreamReader will have 10 bytes available. So it's possible to have poll and push-like notifications with StreamReader.
We can ask StreamReader to get notification, when more complex conditions are met.
Future<Integer> future = streamReader.notifyCondition(customCondition, completionHandler);
This way we implemented SSL handshake mechanism, so SSLStreamReader notifies us, when handshake status becomes NEED_WRAP.
Non-blocking mode for StreamWriter means, that stream flushing will be done non-blocking. For example:
Future<Integer> future = streamWriter.flush();
where flush() operation returns Future<Integer>, which could be used to check if bytes were flushed and how may bytes were written on Connection. It is also possible to pass CompletionHandler to flush() operation, which will be notified by StreamWriter, once bytes will be flushed.