package dk.silverbullet.telemed.rest.client.lowlevel; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import dk.silverbullet.telemed.rest.client.RestException; import dk.silverbullet.telemed.rest.client.ServerInformation; import dk.silverbullet.telemed.rest.client.WrongHttpStatusCodeException; import dk.silverbullet.telemed.rest.httpclient.HttpClientFactory; import dk.silverbullet.telemed.utils.Json; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.StatusLine; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.StringEntity; import org.apache.http.params.HttpConnectionParams; import org.apache.http.params.HttpParams; import org.apache.http.util.EntityUtils; import java.io.*; import java.util.Locale; /** * Various helper methods for the RestClient. */ public class HttpHelper { // The time-out in milliseconds for the underlying HTTP client private static final int CONNECTION_TIMEOUT = 10000; private static final int SOCKET_TIMEOUT = 60000; public static HttpGet createHttpGetForPath(ServerInformation serverInformation, String path) { String url = urlForPath(serverInformation, path); HttpGet result = new HttpGet(url); new HttpHeaderBuilder(result, serverInformation) .withAuthentication() .withAcceptTypeJSON(); return result; } public static HttpGet createHttpGetForPathWithoutAuthentication(ServerInformation serverInformation, String path) { String url = urlForPath(serverInformation, path); HttpGet result = new HttpGet(url); new HttpHeaderBuilder(result, serverInformation) .withAcceptTypeJSON(); return result; } public static HttpPost createHttpPostForPathWithEntity(ServerInformation serverInformation, String path, HttpEntity entity) { String url = urlForPath(serverInformation, path); HttpPost result = new HttpPost(url); new HttpHeaderBuilder(result, serverInformation) .withContentTypeJSON() .withAcceptTypeJSON() .withAuthentication(); result.setEntity(entity); return result; } public static HttpResponse get(ServerInformation serverInformation, HttpGet httpGet) throws IOException, RestException { HttpClient httpClient = createHttpClient(serverInformation); HttpResponse response = httpClient.execute(httpGet); StatusLine statusLine = response.getStatusLine(); int statusCode = statusLine.getStatusCode(); if (statusCode != 200) { throw new WrongHttpStatusCodeException("Unexpected status code '" + statusCode + "' when GETting url '" + httpGet.getURI() + "'", response); } return response; } public static HttpResponse post(ServerInformation serverInformation, HttpPost httpPost) throws IOException, RestException { HttpClient httpClient = createHttpClient(serverInformation); HttpResponse response = httpClient.execute(httpPost); StatusLine statusLine = response.getStatusLine(); int statusCode = statusLine.getStatusCode(); if (statusCode != 200) { throw new WrongHttpStatusCodeException("Unexpected status code '" + statusCode + "' when POSTing to url '" + httpPost.getURI() + "'", response); } return response; } public static HttpEntity createHttpEntityFromSerializedObject(Object object) { String json = Json.print(object); try { return new StringEntity(json, "UTF-8"); } catch (UnsupportedEncodingException e) { // Never, ever happens throw new RuntimeException("Could not create HTTP entity", e); } } public static <T> T parseResponseAsJson(HttpResponse response, Class<T> resultClass) throws IOException { InputStreamReader reader = new InputStreamReader(response.getEntity().getContent(), "UTF-8"); try { return Json.parse(reader, resultClass); } finally { reader.close(); } } public static String parseResponseAsString(HttpResponse response) throws IOException { HttpEntity httpEntity = response.getEntity(); return EntityUtils.toString(httpEntity); } public static Bitmap parseResponseAsImage(HttpResponse response) throws IOException { HttpEntity httpEntity = response.getEntity(); if (httpEntity != null) { //Note: Don't try to use EntityUtils.toByteArray(httpEntity) here! It has memory //issues! InputStream inputStream = null; try { inputStream = httpEntity.getContent(); return BitmapFactory.decodeStream(new FlushedInputStream(inputStream)); } finally { if (inputStream != null) { inputStream.close(); } httpEntity.consumeContent(); } } return null; } //An InputStream that skips the exact number of bytes provided, unless it reaches EOF. //From http://android-developers.blogspot.dk/2010/07/multithreading-for-performance.html static class FlushedInputStream extends FilterInputStream { public FlushedInputStream(InputStream inputStream) { super(inputStream); } @Override public long skip(long n) throws IOException { long totalBytesSkipped = 0L; while (totalBytesSkipped < n) { long bytesSkipped = in.skip(n - totalBytesSkipped); if (bytesSkipped == 0L) { int b = read(); if (b < 0) { break; // we reached EOF } else { bytesSkipped = 1; // we read one byte } } totalBytesSkipped += bytesSkipped; } return totalBytesSkipped; } } private static String urlForPath(ServerInformation serverInformation, String path) { return serverInformation.getServerUrl() + path + "?lang=" + Locale.getDefault().getLanguage(); } private static HttpClient createHttpClient(ServerInformation serverInformation) { HttpClient httpClient = HttpClientFactory.createHttpClient(serverInformation.getContext()); HttpParams httpParameters = httpClient.getParams(); HttpConnectionParams.setConnectionTimeout(httpParameters, CONNECTION_TIMEOUT); HttpConnectionParams.setSoTimeout(httpParameters, SOCKET_TIMEOUT); return httpClient; } }