package com.limegroup.gnutella.lws.server;
import java.io.IOException;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.nio.protocol.NHttpRequestHandler;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.limewire.core.settings.LWSSettings;
import org.limewire.inject.EagerSingleton;
import org.limewire.lws.server.AbstractReceivesCommandsFromDispatcher;
import org.limewire.lws.server.LWSConnectionListener;
import org.limewire.lws.server.LWSDispatcher;
import org.limewire.lws.server.LWSDispatcherFactory;
import org.limewire.lws.server.LWSDispatcherFactoryImpl;
import org.limewire.lws.server.LWSDispatcherSupport;
import org.limewire.lws.server.LWSReceivesCommandsFromDispatcher;
import org.limewire.lws.server.LWSSenderOfMessagesToServer;
import org.limewire.lws.server.StringCallback;
import org.limewire.lws.server.LWSDispatcherSupport.Responses;
import com.google.inject.Inject;
import com.limegroup.gnutella.http.HttpExecutor;
import com.limegroup.gnutella.util.EncodingUtils;
import com.limegroup.gnutella.util.LimeWireUtils;
/**
* Encapsulates a {@link LWSDispatcher} and {@link LWSReceivesCommandsFromDispatcher}.
*/
@EagerSingleton
public final class LWSManagerImpl implements LWSManager, LWSSenderOfMessagesToServer {
private final static Log LOG = LogFactory.getLog(LWSManagerImpl.class);
/** The page for making commands to The LimeWire Store server. */
final static String COMMAND_PAGE_WITH_LEADING_AND_TRAILING_SLASHES
= "/store/app/pages/client/ClientCom/command/";
private final LWSDispatcher dispatcher;
private final Map<String, LWSManagerCommandResponseHandler> commands2handlers = new HashMap<String, LWSManagerCommandResponseHandler>();
/** This is provided by {@link LWSSettings}. */
private final String hostNameAndPort;
private final HttpExecutor exe;
private boolean isConnected;
@Inject
public LWSManagerImpl(HttpExecutor exe) {
this(exe, new LWSDispatcherFactoryImpl()); //TODO: inject
}
//todo @Inject
public LWSManagerImpl(HttpExecutor exe, LWSDispatcherFactory lwsDispatcherFactory) {
this(exe, LWSSettings.LWS_AUTHENTICATION_HOSTNAME.get(),
LWSSettings.LWS_AUTHENTICATION_PORT.getValue(), lwsDispatcherFactory);
}
public LWSManagerImpl(HttpExecutor exe, String host, int port, LWSDispatcherFactory lwsDispatcherFactory) {
this.exe = exe;
this.dispatcher = lwsDispatcherFactory.createDispatcher(this, new AbstractReceivesCommandsFromDispatcher() {
public String receiveCommand(String cmd, Map<String, String> args) {
return LWSManagerImpl.this.dispatch(cmd, args);
}
});
// Construct the hostname and port to which we connect for authentication
// from remote settings
StringBuilder hostNameAndPortBuffer = new StringBuilder(host);
if (port > 0) hostNameAndPortBuffer.append(":").append(port);
this.hostNameAndPort = hostNameAndPortBuffer.toString();
if (LOG.isDebugEnabled()) {
LOG.debug("hostname and port: " + hostNameAndPort);
}
//
// remember when we're connected
//
dispatcher.addConnectionListener(new LWSConnectionListener() {
public void connectionChanged(boolean isConnected) {
LWSManagerImpl.this.isConnected = isConnected;
}
});
//
// Add handler to check if we are still connected
//
registerHandler("IsConnected", new LWSManagerCommandResponseHandlerWithCallback("IsConnected") {
@Override
protected String handleRest(Map<String, String> args) {
//
// If we're connected with the correct private key this will be
// fine
//
return LWSDispatcherSupport.Responses.OK;
}
});
}
public final boolean addConnectionListener(LWSConnectionListener lis) {
return dispatcher.addConnectionListener(lis);
}
public final boolean removeConnectionListener(LWSConnectionListener lis) {
return dispatcher.removeConnectionListener(lis);
}
// -----------------------------------------------------------------
// Implementation of LWSManager
// -----------------------------------------------------------------
public final NHttpRequestHandler getHandler() {
return dispatcher;
}
public boolean isConnected() {
return isConnected;
}
public final boolean registerHandler(String cmd, LWSManagerCommandResponseHandler lis) {
if (lis == null) throw new NullPointerException("Handlers can't be null");
String hash = hash(cmd);
commands2handlers.put(hash, lis);
return true;
}
public final boolean unregisterHandler(String cmd) {
String hash = hash(cmd);
return commands2handlers.remove(hash) != null;
}
public final void clearHandlers() {
commands2handlers.clear();
}
public final void sendMessageToServer(final String msg,
final Map<String, String> args,
final StringCallback cb) throws IOException {
String url = constructURL(msg, args);
if (LOG.isDebugEnabled()) {
LOG.debug("sending URL " + url);
}
final HttpGet get = new HttpGet(url);
if(get.getURI().getHost() == null) {
LOG.error("null host!");
throw new IOException("null host!");
}
get.addHeader("User-Agent", LimeWireUtils.getHttpServer());
//
// we don't care what this response is, because we are
// always talking to the remote web server, so process it
// right away so we don't block
//
//
cb.process(Responses.OK);
HttpParams params = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(params, 1000);
HttpConnectionParams.setSoTimeout(params, 1000);
exe.execute(get, params);
}
// ---------------------------------------------------------------------------------
// Private
// ---------------------------------------------------------------------------------
private String constructURL(final String msg, final Map<String, String> args) {
StringBuilder url = new StringBuilder("http");
if (LWSSettings.LWS_USE_SSL.getValue()) {
url.append("s");
}
url.append("://")
.append(hostNameAndPort)
.append(COMMAND_PAGE_WITH_LEADING_AND_TRAILING_SLASHES);
url.append(msg);
for (Map.Entry<String, String> e : args.entrySet()) {
url.append("/");
url.append(e.getKey()).append("/").append(EncodingUtils.encode(e.getValue()));
}
return url.toString();
}
private String hash(String cmd) {
return cmd.toLowerCase(Locale.US);
}
private String dispatch(String command, Map<String, String> arguments) {
String hash = hash(command);
String result = null;
LWSManagerCommandResponseHandler handler = commands2handlers.get(hash);
if (handler != null) {
result = handler.handle(arguments);
if (result == null) {
// does this ever happen? could just assert.
result = "OK";
}
}
return result;
}
}