/** Java IO, 2nd edition */

import java.net.*;
import java.io.*;
import java.nio.*;
import java.nio.channels.*;
import java.util.*;

public class NewDataStuffer {
  private static byte[] data = new byte[255];

  public static void main(String[] args) throws IOException {
    // initialize data buffer
    for (int i = 0; i < data.length; i++) 
	data[i] = (byte) i;
    // Create the server socket channel bound to port 9876
    ServerSocketChannel server = ServerSocketChannel.open( );
    server.configureBlocking(false);
    server.socket( ).bind(new InetSocketAddress(9876));
    // Create the selector
    Selector selector = Selector.open( );
    // Register the server socket channel with the selector
    // waiting on an accept operation. In this case it is not necessary
    // to define the SelectionKey key0. I introduced key0 to streas that
    // the act of registering a channel with a selector procuces a 
    // SelectionKey.
    SelectionKey key0 = server.register(selector, SelectionKey.OP_ACCEPT);
    // process connections
    while (true) {
      // wait for an event to occur on the selector
      selector.select( );
      // obtain the set of ready keys (i.e for which operations are ready)
      Set<SelectionKey> readyKeys = selector.selectedKeys( );
      // iterate on the ready keys
      Iterator<SelectionKey> iterator = readyKeys.iterator( );
      while (iterator.hasNext( )) {
	// process the selected key
        SelectionKey key = iterator.next( );
        iterator.remove( ); // take out key from the set being iterated
        try {
          if (key.isAcceptable( )) { // event is accept
	    // accept connection, set the connected SocketChannel
	    // to non blocking, register it for a write event,
	    // and associate to the resulting key a buffer that wraps 
	    // the data array
            SocketChannel client = server.accept( );
            System.out.println("Accepted connection from " + client);
            client.configureBlocking(false);
            ByteBuffer source = ByteBuffer.wrap(data);
            SelectionKey key2 = client.register(selector, 
		SelectionKey.OP_WRITE);
            key2.attach(source);
	    // If we were planning to use the connected socket
	    // both for reading and writing, here we would have
	    // registered the client also for OP_READ.
          }
          else if (key.isWritable( )) { // event is write
	    // Obtain the SocketChannel and the buffer associated
	    // to this write key and write from the buffer to the socket 
            SocketChannel client = (SocketChannel) key.channel( );
            ByteBuffer output = (ByteBuffer) key.attachment( );
            if (!output.hasRemaining( )) {
              output.rewind( );
            }
            client.write(output);
          }
        }
        catch (IOException ex) {
          key.cancel( ); // de-register this key from the selector
          try {
            key.channel().close( );
          }
          catch (IOException cex) {}
        }
      }
    }
  }
}




