/*
* JLibs: Common Utilities for Java
* Copyright (C) 2009 Santhosh Kumar T <santhosh.tekuri@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
package jlibs.nio;
import java.io.IOException;
import java.net.ConnectException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel;
import static java.nio.channels.SelectionKey.OP_CONNECT;
import static jlibs.nio.Debugger.DEBUG;
import static jlibs.nio.Debugger.println;
/**
* @author Santhosh Kumar Tekuri
*/
public class TCPConnector extends NBChannel<SocketChannel>{
public final long id;
private final SelectionKey selectionKey;
public TCPConnector() throws IOException{
super(SocketChannel.open());
selectionKey = selectable.register(reactor.selector, 0, this);
id = ++reactor.lastConnectID;
++reactor.connectionPending;
uniqueID = "c"+id;
}
private Listener listener;
public static interface Listener{
public void process(TCPConnector connector);
}
private SocketAddress address;
public void connect(SocketAddress address, Listener listener){
this.address = address;
this.listener = listener;
if(DEBUG)
println(this+".connect()");
boolean notify;
try{
notify = selectable.connect(address);
if(DEBUG && notify)
println("connected");
}catch(IOException ex){
if(DEBUG)
println("connectFailed: "+ex);
connectError = ex;
notify = true;
}
if(notify){
try{
listener.process(this);
}catch(Throwable thr){
reactor.handleException(thr);
}
}else{
selectionKey.interestOps(OP_CONNECT);
if(SO_TIMEOUT>0)
reactor.startTimer(this, SO_TIMEOUT);
}
}
private IOException connectError;
public TCPConnection getTCPConnection() throws IOException{
if(connectError!=null)
throw connectError;
return new TCPConnection(id, selectable, selectionKey);
}
@Override
protected void process(boolean timeout){
boolean notify;
try{
if(timeout)
throw new ConnectException("timed out");
notify = selectable.finishConnect();
if(DEBUG)
println("finishConnect = "+notify);
if(notify)
selectionKey.interestOps(0);
}catch(IOException ex){
if(DEBUG)
println("connectFailed: "+ex);
connectError = ex;
notify = true;
}
if(notify){
try{
listener.process(this);
}catch(Throwable thr){
reactor.handleException(thr);
}
}
}
@Override
public void shutdown(){
if(isOpen()){
--reactor.connectionPending;
super.shutdown();
}
}
@Override
public String toString(){
StringBuilder buf = new StringBuilder();
buf.append("TCPConnector").append(id).append("[");
InetSocketAddress address = (InetSocketAddress)this.address;
if(selectable.isConnected())
buf.append("c:");
else
buf.append("?:");
if(address==null)
buf.append("?");
else
buf.append(address.getHostString()).append(":").append(address.getPort());
buf.append("]");
return buf.toString();
}
/*-------------------------------------------------[ Options ]---------------------------------------------------*/
public static long SO_TIMEOUT;
}