Package com.davfx.ninio.common

Source Code of com.davfx.ninio.common.SocketReady

package com.davfx.ninio.common;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedSelectorException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.LinkedList;

public final class SocketReady implements Ready {
  private final Selector selector;
  private final ByteBufferAllocator byteBufferAllocator;
 
  public SocketReady(Selector selector, ByteBufferAllocator byteBufferAllocator) {
    this.selector = selector;
    this.byteBufferAllocator = byteBufferAllocator;
  }
 
  @Override
  public void connect(final Address address, final ReadyConnection connection) {
    try {
      final SocketChannel channel = SocketChannel.open();
      try {
        channel.configureBlocking(false);
        SelectionKey inboundKey = channel.register(selector, SelectionKey.OP_CONNECT);
        inboundKey.attach(new SelectionKeyVisitor() {
          @Override
          public void visit(SelectionKey key) {
            if (!key.isConnectable()) {
              return;
            }
   
            try {
              channel.finishConnect();
              final SelectionKey selectionKey = channel.register(selector, 0);
             
              final LinkedList<ByteBuffer> toWriteQueue = new LinkedList<ByteBuffer>();
 
              selectionKey.attach(new SelectionKeyVisitor() {
                @Override
                public void visit(SelectionKey key) {
                  if (!channel.isOpen()) {
                    return;
                  }
                  if (key.isReadable()) {
                    ByteBuffer readBuffer = byteBufferAllocator.allocate();
                    try {
                      if (channel.read(readBuffer) < 0) {
                        try {
                          channel.close();
                        } catch (IOException ee) {
                        }
                        connection.close();
                      } else {
                        readBuffer.flip();
                        connection.handle(address, readBuffer);
                      }
                    } catch (IOException e) {
                      try {
                        channel.close();
                      } catch (IOException ee) {
                      }
                      connection.close();
                    }
                  } else if (key.isWritable()) {
                    while (!toWriteQueue.isEmpty()) {
                      ByteBuffer b = toWriteQueue.getFirst();
                      if (b == null) {
                        try {
                          channel.close();
                        } catch (IOException ee) {
                        }
                        return;
                      } else {
                        try {
                          channel.write(b);
                        } catch (IOException e) {
                          try {
                            channel.close();
                          } catch (IOException ee) {
                          }
                          connection.close();
                          return;
                        }
                       
                        if (b.hasRemaining()) {
                          return;
                        }
                       
                        toWriteQueue.removeFirst();
                      }
                    }
                    if (!selector.isOpen()) {
                      return;
                    }
                    if (!channel.isOpen()) {
                      return;
                    }
                    if (!selectionKey.isValid()) {
                      return;
                    }
                    selectionKey.interestOps(selectionKey.interestOps() & ~SelectionKey.OP_WRITE);
                  }
                }
              });
   
              selectionKey.interestOps(selectionKey.interestOps() | SelectionKey.OP_READ);
             
              connection.connected(new FailableCloseableByteBufferHandler() {
                @Override
                public void handle(Address address, ByteBuffer buffer) {
                  if (!selector.isOpen()) {
                    return;
                  }
                  if (!channel.isOpen()) {
                    return;
                  }
                  if (!selectionKey.isValid()) {
                    return;
                  }
                  toWriteQueue.addLast(buffer);
                  selectionKey.interestOps(selectionKey.interestOps() | SelectionKey.OP_WRITE);
                }
                @Override
                public void close() {
                  if (!selector.isOpen()) {
                    return;
                  }
                  if (!channel.isOpen()) {
                    return;
                  }
                  if (!selectionKey.isValid()) {
                    return;
                  }
                  toWriteQueue.addLast(null);
                  selectionKey.interestOps(selectionKey.interestOps() | SelectionKey.OP_WRITE);
                }
                @Override
                public void failed(IOException e) {
                  close();
                }
              });
   
            } catch (IOException e) {
              try {
                channel.close();
              } catch (IOException ee) {
              }
              connection.failed(e);
            }
          }
        });
       
        try {
          InetSocketAddress a = AddressUtils.toConnectableInetSocketAddress(address);
          if (a == null) {
            throw new IOException("Invalid address");
          }
          channel.connect(a);
        } catch (IOException e) {
          inboundKey.cancel();
          throw e;
        }
      } catch (IOException e) {
        try {
          channel.close();
        } catch (IOException ee) {
        }
        throw e;
      }

    } catch (ClosedSelectorException e) {
      connection.failed(new IOException(e));
    } catch (IOException e) {
      connection.failed(e);
    }
  }
}
TOP

Related Classes of com.davfx.ninio.common.SocketReady

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.