package org.limewire.lws.server;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.util.EntityUtils;
import org.limewire.http.httpclient.SimpleLimeHttpClient;
import org.limewire.net.SocketsManager;
import org.limewire.service.ErrorService;
/**
* This class defines instances of {@link LWSSenderOfMessagesToServer} that
* simply communicate to a another server running on a given host and port. For
* the purpose of testing it's used to talk to another server running on
* <code>localhost</code>.
*/
public final class LocalServerDelegate {
private final int port;
private final SocketsManager socketsManager;
private final String host;
/**
* @param host host name to which we communicate
* @param port port to which we communicate
* @param openner openner that will create a socket from <code>host</code>
* and <code>port</code>
*/
public LocalServerDelegate(SocketsManager openner, String host, int port) {
this.socketsManager = openner;
this.host = host;
this.port = port;
}
/**
* This defines an interface to construct a URL based on a message and
* arguments. This is used becaused when we're sending a URL to a server on
* the client we encode the arguments as normal CGI parameters; when sending
* to a mock remote server, we use a Wicket-style encoding. See
* {@link #constructURL(String msg, Map<String, String> args)} for examples.
*/
public interface URLConstructor {
/**
* Returns a URL based on the base message, <code>msg</code> and
* arguments. Examples, for a message <code>"Foo"</code> and arguments
* <code>{ "a" => "A", "b" => "B" }</code> would be:
*
* <p>
*
* <table>
* <tr>
* <th>Type</th>
* <th>URL</th>
* </tr>
* <tr>
* <td>Normal</td>
* <td><code>Foo?a=A&b=B</code></td>
* </tr>
* <tr>
* <td>Wicket</td>
* <td><code>store/app/pages/client/ClientCom/command/Foo/a/A/b/B</code></td>
* </tr>
* </table>
*
* @param msg base message
* @param args arguments
* @return a URL based on the base message, <code>msg</code> and
* arguments
*/
String constructURL(String msg, Map<String, String> args);
}
/**
* An implementation of {@link URLConstructor} using Wicket-style URLs. An
* example, for a message <code>"Foo"</code> and arguments
* <code>{ "a" => "A", "b" => "B" }</code> would be:
* <code>store/app/pages/client/ClientCom/command/Foo/a/A/b/B</code>.
*/
public static class WicketStyleURLConstructor implements URLConstructor {
public final static WicketStyleURLConstructor INSTANCE = new WicketStyleURLConstructor();
private WicketStyleURLConstructor() {}
public String constructURL(String msg, Map<String, String> args) {
StringBuffer sb = new StringBuffer("store/app/pages/client/ClientCom/command");
sb.append("/").append(msg);
for (String key : args.keySet()) {
sb.append("/")
.append(key)
.append("/")
.append(args.get(key));
}
return sb.toString();
}
}
/**
* An implementation of {@link URLConstructor} using normal CGI
* parameter-encoding. An example, for a message <code>"Foo"</code> and
* arguments <code>{ "a" => "A", "b" => "B" }</code> would be
* <code>Foo?a=A&b=B</code>.
*/
public static class NormalStyleURLConstructor implements URLConstructor {
public final static NormalStyleURLConstructor INSTANCE = new NormalStyleURLConstructor();
private NormalStyleURLConstructor() {}
public String constructURL(String msg, Map<String, String> args) {
StringBuffer sb = new StringBuffer(msg);
boolean first = true;
for (String key : args.keySet()) {
sb.append(first ? "?" : "&")
.append(key)
.append("=")
.append(args.get(key));
first = false;
}
return sb.toString();
}
}
public void sendMessageToServer(String msg, Map<String, String> args, StringCallback cb, URLConstructor ctor) {
try {
int tmpPort = port;
for (; tmpPort < port + 10; tmpPort++) {
Socket tmpSock;
try {
tmpSock = socketsManager.connect(new InetSocketAddress(host, port), 5000);
tmpSock.close();
break;
} catch (IOException e) { /* skip */ }
}
//
// We'll always be adding this from the web page
// to ensure a new script is loaded
//
Map<String, String> newArgs = new HashMap<String, String>(args);
newArgs.put("_f", String.valueOf(System.currentTimeMillis()));
String request = ctor.constructURL(msg, newArgs);
HttpClient client = new SimpleLimeHttpClient();
String requestLine = "http://" + host + ":" + port + "/" + request;
HttpGet get = new HttpGet(requestLine);
HttpProtocolParams.setVersion(client.getParams(), HttpVersion.HTTP_1_1);
HttpResponse response = client.execute(get);
String res = "";
if (response.getEntity() != null) {
String result;
if (response.getEntity() != null) {
result = EntityUtils.toString(response.getEntity());
} else {
result = null;
}
res = result;
}
cb.process(res);
} catch (IOException e) {
fail(e);
}
}
private void fail(Exception e) {
ErrorService.error(e, "trying to connect on " + host + ":" + port);
}
}