package org.limewire.http.reactor;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.util.concurrent.Executor;
import org.apache.http.impl.nio.DefaultClientIOEventDispatch;
import org.apache.http.impl.nio.reactor.SessionRequestImpl;
import org.apache.http.nio.NHttpConnection;
import org.apache.http.nio.reactor.ConnectingIOReactor;
import org.apache.http.nio.reactor.IOEventDispatch;
import org.apache.http.nio.reactor.IOReactorStatus;
import org.apache.http.nio.reactor.IOSession;
import org.apache.http.nio.reactor.SessionRequest;
import org.apache.http.nio.reactor.SessionRequestCallback;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.protocol.ExecutionContext;
import org.limewire.net.SocketsManager;
import org.limewire.net.SocketsManager.ConnectType;
import org.limewire.nio.AbstractNBSocket;
import org.limewire.nio.NBSocket;
import org.limewire.nio.observer.ConnectObserver;
public class LimeConnectingIOReactor implements ConnectingIOReactor {
public static final String IO_SESSION_KEY = "org.limewire.iosession";
//private static final Log LOG = LogFactory.getLog(LimeConnectingIOReactor.class);
private final HttpParams params;
protected volatile IOEventDispatch eventDispatch = null;
private final Executor ioExecutor;
private final SocketsManager socketsManager;
private final HttpBandwidthTracker up, down;
public LimeConnectingIOReactor(final HttpParams params, final Executor ioExecutor,
SocketsManager socketsManager, HttpBandwidthTracker up, HttpBandwidthTracker down) {
if (params == null) {
throw new IllegalArgumentException();
}
this.params = params;
this.ioExecutor = ioExecutor;
this.socketsManager = socketsManager;
this.up = up;
this.down = down;
}
public LimeConnectingIOReactor(final HttpParams params, final Executor ioExecutor,
SocketsManager socketsManager) {
this(params, ioExecutor,socketsManager, new HttpBandwidthTracker(), new HttpBandwidthTracker());
}
public void execute(IOEventDispatch eventDispatch) throws IOException {
if (!(eventDispatch instanceof DefaultClientIOEventDispatch)) {
throw new IllegalArgumentException("Event dispatch must be of type DefaultClientIOEventDispatch");
}
this.eventDispatch = eventDispatch;
}
public float getMeasuredBandwidth(boolean downstream) {
if (downstream) {
down.measureBandwidth();
return down.getMeasuredBandwidth();
} else {
up.measureBandwidth();
return up.getMeasuredBandwidth();
}
}
public SessionRequest connect(SocketAddress remoteAddress,
SocketAddress localAddress,
final Object attachment,
SessionRequestCallback callback) {
// TODO: use custom impl that implements cancel & fails on setConnectionTimeout?
final SessionRequestImpl sessionRequest = new SessionRequestImpl(
remoteAddress, localAddress, attachment, callback);
sessionRequest.setConnectTimeout(HttpConnectionParams.getConnectionTimeout(this.params));
NBSocket socket;
try {
socket = (NBSocket) socketsManager.create(ConnectType.PLAIN);
socketsManager.connect(socket, (InetSocketAddress) localAddress,
(InetSocketAddress) remoteAddress, sessionRequest.getConnectTimeout(),
new ConnectObserver() {
public void handleConnect(Socket socket) throws IOException {
prepareSocket((AbstractNBSocket)socket, attachment, sessionRequest);
}
public void handleIOException(IOException iox) {
sessionRequest.failed(iox);
}
public void shutdown() {
sessionRequest.failed(new IOException("couldn't connect"));
}
}, ConnectType.PLAIN);
} catch (IOException iox) {
sessionRequest.failed(iox);
}
return sessionRequest;
}
/**
* Sets parameters of <code>socket</code> based on default {@link HttpParams},
* and attachs to the NIO layer.
*/
protected void prepareSocket(AbstractNBSocket socket, Object attachment, SessionRequestImpl sessionRequest) throws IOException {
socket.setTcpNoDelay(HttpConnectionParams.getTcpNoDelay(this.params));
int linger = HttpConnectionParams.getLinger(this.params);
if (linger >= 0) {
socket.setSoLinger(linger > 0, linger);
}
final HttpIOSession session = new HttpIOSession(socket, ioExecutor);
session.setAttribute(IOSession.ATTACHMENT_KEY, attachment);
session.setSocketTimeout(HttpConnectionParams.getSoTimeout(this.params));
HttpChannel channel = new HttpChannel(session, eventDispatch, null, up, down);
session.setHttpChannel(channel);
eventDispatch.connected(session);
sessionRequest.completed(session);
// need to enable access to the channel for throttling support
// TODO: necessary?
NHttpConnection conn = (NHttpConnection) session.getAttribute(ExecutionContext.HTTP_CONNECTION);
assert conn != null;
conn.getContext().setAttribute(IO_SESSION_KEY, session);
// TODO: do something about ThrottleReader
socket.setReadObserver(channel);
socket.setWriteObserver(channel);
}
/**
* Throws {@link UnsupportedOperationException}.
*/
public IOReactorStatus getStatus() {
throw new UnsupportedOperationException();
}
/**
*
*/
public void shutdown() throws IOException {
}
/**
* Throws {@link UnsupportedOperationException}.
*/
public void shutdown(long gracePeriod) throws IOException {
throw new UnsupportedOperationException();
}
}