package org.simpleframework.demo.rest;
import static org.apache.http.conn.params.ConnRoutePNames.DEFAULT_PROXY;
import static org.apache.http.params.CoreConnectionPNames.CONNECTION_TIMEOUT;
import static org.apache.http.params.CoreConnectionPNames.SO_TIMEOUT;
import java.io.InputStream;
import java.net.URI;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import org.apache.http.ConnectionReuseStrategy;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.Credentials;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.NoConnectionReuseStrategy;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.BasicClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.HttpParams;
import org.apache.http.util.EntityUtils;
public class RequestBuilder {
private final AtomicReference<String> override;
private final AtomicReference<String> body;
private final Map<String, String> parameters;
private final Map<String, String> headers;
private final Map<String, String> cookies;
private final ClientConnectionManager manager;
private final ConnectionReuseStrategy strategy;
private final ResponseConverter converter;
private final AtomicBoolean post;
private final DefaultHttpClient client;
private final String address;
private final URI template;
public RequestBuilder(String address) throws Exception {
this.parameters = new HashMap<String, String>();
this.headers = new HashMap<String, String>();
this.cookies = new HashMap<String, String>();
this.override = new AtomicReference<String>();
this.body = new AtomicReference<String>();
this.manager = new BasicClientConnectionManager();
this.strategy = new NoConnectionReuseStrategy();
this.converter = new ResponseConverter();
this.client = new DefaultHttpClient(manager);
this.template = new URI(address);
this.post = new AtomicBoolean();
this.address = address;
}
public String getAddress() {
return address;
}
public RequestBuilder setBody(String value) {
if (body != null) {
body.set(value);
}
return this;
}
public RequestBuilder setPath(String path) {
if (path != null) {
override.set(path);
}
return this;
}
public RequestBuilder addCookie(String name, String value) {
if (value != null) {
cookies.put(name, value);
}
return this;
}
public RequestBuilder addHeader(String name, String value) {
if (value != null) {
headers.put(name, value);
}
return this;
}
public RequestBuilder addParameter(String name, String value) {
if (value != null) {
parameters.put(name, value);
}
return this;
}
public RequestBuilder setMethod(String method) {
if (method.equals(HttpPost.METHOD_NAME)) {
post.set(true);
return this;
}
if (method.equals(HttpGet.METHOD_NAME)) {
post.set(false);
return this;
}
throw new IllegalStateException("Method '" + method + "' is not supported");
}
public RequestBuilder setAuthorization(String name, String password) {
Credentials credentials = createCredentials(name, password);
CredentialsProvider provider = client.getCredentialsProvider();
if (provider != null) {
provider.setCredentials(AuthScope.ANY, credentials);
}
return this;
}
public RequestBuilder setConnectTimeout(int duration) throws Exception {
HttpParams parameters = client.getParams();
parameters.setParameter(CONNECTION_TIMEOUT, duration);
return this;
}
public RequestBuilder setReadTimeout(int duration) throws Exception {
HttpParams parameters = client.getParams();
parameters.setParameter(SO_TIMEOUT, duration);
return this;
}
public RequestBuilder setProxy(String address) throws Exception {
HttpHost proxy = createHost(address);
HttpParams parameters = client.getParams();
parameters.setParameter(DEFAULT_PROXY, proxy);
return this;
}
public <T> T execute(Class<T> type) throws Exception {
try {
if (post.get()) {
return executePost(type);
}
return executeGet(type);
} finally {
manager.shutdown();
}
}
private <T> T executeGet(Class<T> type) throws Exception {
HttpResponse response = executeGet();
if (converter.accept(type)) {
return convertResponse(response, type);
}
return createResponse(response, type);
}
private <T> T executePost(Class<T> type) throws Exception {
HttpResponse response = executePost();
if (converter.accept(type)) {
return convertResponse(response, type);
}
return createResponse(response, type);
}
private <T> T createResponse(HttpResponse response, Class type) throws Exception {
HttpEntity entity = response.getEntity();
if (type == HttpResponse.class) {
return (T) response;
}
if (type == byte[].class) {
return (T) EntityUtils.toByteArray(entity);
}
if (type == InputStream.class) {
return (T) entity.getContent();
}
throw new IllegalStateException("Cannot convert response to " + type);
}
private <T> T convertResponse(HttpResponse response, Class type) throws Exception {
HttpEntity entity = response.getEntity();
String body = EntityUtils.toString(entity);
if (body != null) {
return (T) converter.convert(type, body);
}
return null;
}
private HttpResponse executePost() throws Exception {
HttpPost message = createPost();
HttpEntity entity = createEntity();
URI target = createURI(message);
client.setReuseStrategy(strategy);
message.setURI(target);
message.setEntity(entity);
return client.execute(message);
}
private HttpResponse executeGet() throws Exception {
HttpGet message = createGet();
URI target = createURI(message);
client.setReuseStrategy(strategy);
message.setURI(target);
return client.execute(message);
}
private HttpGet createGet() throws Exception {
HttpGet get = new HttpGet(address);
if (!headers.isEmpty()) {
Set<String> names = headers.keySet();
for (String name : names) {
String value = headers.get(name);
get.addHeader(name, value);
}
}
if (!cookies.isEmpty()) {
Set<String> names = cookies.keySet();
for (String name : names) {
String value = cookies.get(name);
String cookie = String.format("%s=%s", name, value);
get.addHeader("Cookie", cookie);
}
}
return get;
}
private HttpPost createPost() throws Exception {
HttpPost post = new HttpPost(address);
if (!headers.isEmpty()) {
Set<String> names = headers.keySet();
for (String name : names) {
String value = headers.get(name);
post.addHeader(name, value);
}
}
if (!cookies.isEmpty()) {
Set<String> names = cookies.keySet();
for (String name : names) {
String value = cookies.get(name);
String cookie = String.format("%s=%s", name, value);
post.addHeader("Cookie", cookie);
}
}
return post;
}
private HttpHost createHost(String address) throws Exception {
URI target = URI.create(address);
String scheme = target.getScheme();
String host = target.getHost();
int port = target.getPort();
return new HttpHost(host, port, scheme);
}
private URI createURI(HttpPost message) throws Exception {
URI target = message.getURI();
String query = target.getQuery();
return createURI(message, query);
}
private URI createURI(HttpGet message) throws Exception {
String query = createQuery(message);
return createURI(message, query);
}
private URI createURI(HttpUriRequest message, String query) throws Exception {
URI target = message.getURI();
String fragment = target.getFragment();
String info = target.getUserInfo();
String path = extractPath(target);
String scheme = extractScheme(target);
String host = extractHost(target);
int port = extractPort(target);
return new URI(scheme, info, host, port, path, query, fragment);
}
private String createQuery(HttpGet message) throws Exception {
List<NameValuePair> parameters = createParameters();
URI target = message.getURI();
String query = target.getQuery();
if (!parameters.isEmpty()) {
if (query != null) {
query += "&";
} else {
query = "";
}
for (NameValuePair parameter : parameters) {
String name = parameter.getName();
String value = parameter.getValue();
query += String.format("%s=%s&", name, value);
}
}
return query;
}
private String extractPath(URI target) throws Exception {
String pathOverride = override.get();
if (pathOverride == null) {
String targetPath = target.getPath();
if (targetPath != null) {
return targetPath;
}
return template.getPath();
}
return pathOverride;
}
private int extractPort(URI target) throws Exception {
String targetHost = target.getHost();
int targetPort = target.getPort();
if (targetHost != null) {
return targetPort;
}
return template.getPort();
}
private String extractHost(URI target) throws Exception {
String targetHost = target.getHost();
if (targetHost != null) {
return targetHost;
}
return template.getHost();
}
private String extractScheme(URI target) throws Exception {
String targetScheme = target.getScheme();
if (targetScheme != null) {
return targetScheme;
}
return template.getScheme();
}
private HttpEntity createEntity() throws Exception {
List<NameValuePair> parameters = createParameters();
if(parameters.isEmpty()) {
String content = body.get();
return new StringEntity(content, "UTF-8");
}
return new UrlEncodedFormEntity(parameters, "UTF-8");
}
private List<NameValuePair> createParameters() throws Exception {
List<NameValuePair> list = new LinkedList<NameValuePair>();
if (!parameters.isEmpty()) {
Set<String> names = parameters.keySet();
for (String name : names) {
String value = parameters.get(name);
NameValuePair pair = createAttribute(name, value);
list.add(pair);
}
}
return list;
}
private NameValuePair createAttribute(String name, String value) {
return new BasicNameValuePair(name, value);
}
private Credentials createCredentials(String user, String password) {
return new UsernamePasswordCredentials(user, password);
}
}