package br.com.caelum.restfulie.http.apache;
import java.io.IOException;
import java.io.StringWriter;
import java.net.URI;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpHead;
import org.apache.http.client.methods.HttpOptions;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpTrace;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.protocol.ClientContext;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;
import br.com.caelum.restfulie.Response;
import br.com.caelum.restfulie.RestClient;
import br.com.caelum.restfulie.RestfulieException;
import br.com.caelum.restfulie.http.Request;
import br.com.caelum.restfulie.mediatype.MediaType;
import br.com.caelum.restfulie.request.RequestDispatcher;
public class ApacheDispatcher implements RequestDispatcher {
private final HttpClient http = new DefaultHttpClient();
private final RestClient client;
private final HttpContext context;
private ApacheResponse lastExecuted;
public ApacheDispatcher(RestClient client) {
this.client = client;
this.context = new BasicHttpContext();
context.setAttribute(ClientContext.COOKIE_STORE, new BasicCookieStore());
}
public Response process(Request details, String method, URI uri,
final Object payload) {
if (payload == null) {
return access(details, method, uri);
}
final Map<String, String> headers = details.getHeaders();
if (!headers.containsKey("Content-type")) {
throw new RestfulieException(
"You should set a content type prior to sending some payload.");
}
StringWriter writer = new StringWriter();
String type = headers.get("Content-type");
try {
type = type.split(";")[0];
handlerFor(type).marshal(payload, writer, client);
writer.flush();
HttpEntityEnclosingRequestBase verb = (HttpEntityEnclosingRequestBase) verbFor(method, uri);
add(verb, headers);
String string = writer.getBuffer().toString();
verb.setEntity(new StringEntity(string));
return execute(details, verb);
} catch (IOException e) {
throw new RestfulieException("Unable to marshal entity.", e);
}
}
private HttpContext getContext() {
return this.context;
}
private MediaType handlerFor(String type) {
return client.getMediaTypes().forContentType(type);
}
private void add(HttpRequest method, Map<String, String> headers) {
for (Entry<String, String> header : headers.entrySet()) {
method.addHeader(header.getKey(), header.getValue());
}
}
private Response access(Request request, String method, URI uri) {
HttpUriRequest verb = verbFor(method, uri);
add(verb, request.getHeaders());
return execute(request, verb);
}
private HttpUriRequest verbFor(String method, URI uri) {
method = method.toUpperCase();
if(method.equals("GET")) {
return new HttpGet(uri);
} else if(method.equals("PUT")) {
return new HttpPut(uri);
} else if(method.equals("POST")) {
return new HttpPost(uri);
} else if(method.equals("DELETE")) {
return new HttpDelete(uri);
} else if(method.equals("TRACE")) {
return new HttpTrace(uri);
} else if(method.equals("OPTIONS")) {
return new HttpOptions(uri);
} else if(method.equals("HEAD")) {
return new HttpHead(uri);
}
throw new RestfulieException("You can not " + method + " to " + uri + ", there is no such verb in the apache http API.");
}
private ApacheResponse execute(Request details, HttpUriRequest method) {
try {
if (lastExecuted != null) {
lastExecuted.discard();
}
HttpResponse response = http.execute(method, getContext());
return responseFor(response, details);
} catch (ClientProtocolException e) {
throw new RestfulieException(
"Unable to execute " + method.getURI(), e);
} catch (IOException e) {
throw new RestfulieException(
"Unable to execute " + method.getURI(), e);
}
}
private ApacheResponse responseFor(HttpResponse response, Request details)
throws IOException {
this.lastExecuted = new ApacheResponse(response, client, details);
return lastExecuted;
}
}