package com.uservoice.uservoicesdk.rest; import android.net.Uri; import android.net.http.AndroidHttpClient; import android.os.AsyncTask; import com.uservoice.uservoicesdk.Session; import com.uservoice.uservoicesdk.UserVoice; import com.uservoice.uservoicesdk.model.AccessToken; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.StatusLine; import org.apache.http.client.entity.UrlEncodedFormEntity; 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.HttpPost; import org.apache.http.client.methods.HttpPut; import org.apache.http.client.methods.HttpRequestBase; import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.message.BasicNameValuePair; import org.apache.http.util.EntityUtils; import org.json.JSONException; import org.json.JSONObject; import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.Map; import oauth.signpost.OAuthConsumer; public class RestTask extends AsyncTask<String, String, RestResult> { private String urlPath; private RestMethod method; private List<BasicNameValuePair> params; private RestTaskCallback callback; private HttpUriRequest request; public RestTask(RestMethod method, String urlPath, Map<String, String> params, RestTaskCallback callback) { this(method, urlPath, params == null ? null : paramsToList(params), callback); } public RestTask(RestMethod method, String urlPath, List<BasicNameValuePair> params, RestTaskCallback callback) { this.method = method; this.urlPath = urlPath; this.callback = callback; this.params = params; } public static List<BasicNameValuePair> paramsToList(Map<String, String> params) { ArrayList<BasicNameValuePair> formList = new ArrayList<BasicNameValuePair>(params.size()); for (String key : params.keySet()) { String value = params.get(key); if (value != null) formList.add(new BasicNameValuePair(key, value)); } return formList; } @Override protected RestResult doInBackground(String... args) { try { request = createRequest(); if (isCancelled()) throw new InterruptedException(); OAuthConsumer consumer = Session.getInstance().getOAuthConsumer(); if (consumer != null) { AccessToken accessToken = Session.getInstance().getAccessToken(); if (accessToken != null) { consumer.setTokenWithSecret(accessToken.getKey(), accessToken.getSecret()); } consumer.sign(request); } request.setHeader("Accept-Language", Locale.getDefault().getLanguage()); request.setHeader("API-Client", String.format("uservoice-android-%s", UserVoice.getVersion())); AndroidHttpClient client = AndroidHttpClient.newInstance(String.format("uservoice-android-%s", UserVoice.getVersion()), Session.getInstance().getContext()); if (isCancelled()) throw new InterruptedException(); // TODO it would be nice to find a way to abort the request on cancellation HttpResponse response = client.execute(request); if (isCancelled()) throw new InterruptedException(); HttpEntity responseEntity = response.getEntity(); StatusLine responseStatus = response.getStatusLine(); int statusCode = responseStatus != null ? responseStatus.getStatusCode() : 0; String body = responseEntity != null ? EntityUtils.toString(responseEntity) : null; client.close(); if (isCancelled()) throw new InterruptedException(); return new RestResult(statusCode, new JSONObject(body)); } catch (Exception e) { return new RestResult(e); } } private HttpUriRequest createRequest() throws URISyntaxException, UnsupportedEncodingException { String host = Session.getInstance().getConfig().getSite(); Uri.Builder uriBuilder = new Uri.Builder(); uriBuilder.scheme(host.contains(".us.com") ? "http" : "https"); uriBuilder.encodedAuthority(host); uriBuilder.path(urlPath); if (method == RestMethod.GET) return requestWithQueryString(new HttpGet(), uriBuilder); else if (method == RestMethod.DELETE) return requestWithQueryString(new HttpDelete(), uriBuilder); else if (method == RestMethod.POST) return requestWithEntity(new HttpPost(), uriBuilder); else if (method == RestMethod.PUT) return requestWithEntity(new HttpPut(), uriBuilder); else throw new IllegalArgumentException("Method must be one of [GET, POST, PUT, DELETE], but was " + method); } @Override protected void onPostExecute(RestResult result) { if (result.isError()) { callback.onError(result); } else { try { callback.onComplete(result.getObject()); } catch (JSONException e) { callback.onError(new RestResult(e, result.getStatusCode(), result.getObject())); } } super.onPostExecute(result); } private HttpUriRequest requestWithQueryString(HttpRequestBase request, Uri.Builder uriBuilder) throws URISyntaxException { if (params != null) { for (BasicNameValuePair param : params) { uriBuilder.appendQueryParameter(param.getName(), param.getValue()); } } request.setURI(new URI(uriBuilder.build().toString())); return request; } private HttpUriRequest requestWithEntity(HttpEntityEnclosingRequestBase request, Uri.Builder uriBuilder) throws UnsupportedEncodingException, URISyntaxException { if (params != null) { request.setEntity(new UrlEncodedFormEntity(params, "UTF-8")); } request.setURI(new URI(uriBuilder.build().toString())); return request; } }