package learnositysdk.request; import org.apache.commons.io.IOUtils; import org.apache.http.client.utils.URLEncodedUtils; import org.apache.http.NameValuePair; import org.apache.http.message.BasicNameValuePair; 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.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.Header; import org.apache.http.client.config.RequestConfig; import java.util.Map; import java.util.HashMap; import java.util.ArrayList; import java.util.List; import java.io.InputStream; import java.io.StringWriter; /** *-------------------------------------------------------------------------- * Learnosity SDK - Remote *-------------------------------------------------------------------------- * * Used to execute a request to a public endpoint. Useful as a cross * domain proxy. * */ public class Remote { /** * Map to store the result of the requests */ private Map<String,String> result = null; /** * Helper class to build up a query string */ private StringBuilder sb; /** * Data to be used in a post request */ private Map<String,Object> postData; /** * Http client */ private CloseableHttpClient httpclient; /** * Array to store header information */ private Header[] headers; /** * Constructor */ public Remote() { result = new HashMap<String,String>(); sb = new StringBuilder(); this.setDefaultClient(); } /** * Alternate Constructor taking in requestConfig */ public Remote(RequestConfig requestConfig) { result = new HashMap<String,String>(); sb = new StringBuilder(); httpclient = HttpClients.custom().setDefaultRequestConfig(requestConfig).build(); } /** * Make a get request to the specified url * * @param url the url of the request */ public void get(String url) throws Exception { this.request(url, false); } /** * Make a get request to the specified url * * @param url Full URL of where to GET the request * @param data optional get arguments */ public void get(String url, Map<String,Object> data) throws Exception { sb.append(url); sb.append("?"); sb.append(this.makeQueryString(data)); this.request(sb.toString(), false); } /** * Make a post request to the specified url. * * @param url Full URL of where to POST the request * @param data post arguments */ public void post(String url, Map<String, Object> data) throws Exception { this.postData = data; this.request(url, true); } /** * Set some default values for timeouts, emulating what is in the php sdk. * Not setting redirects as that's enabled by default, with max redirects * set to 50. * Also not setting ssl verification as that is also enabled by default. */ private void setDefaultClient() { RequestConfig defaultRequestConfig = RequestConfig.custom() .setConnectTimeout(40000) .setSocketTimeout(40000) .setConnectionRequestTimeout(10000) .build(); this.httpclient = HttpClients.custom().setDefaultRequestConfig(defaultRequestConfig).build(); } /** * Makes the actual request * * @param url Full URL of the request * @param post Flag to indicate if this is a post request * @return void */ private void request(String url, boolean post) throws Exception { CloseableHttpResponse resp = null; long startTime = System.currentTimeMillis(); HttpUriRequest httpRequest; if (post) { HttpPost httpPost = new HttpPost(url); httpPost.setEntity(new UrlEncodedFormEntity(this.makeNameValueList(this.postData), "UTF-8")); httpRequest = httpPost; } else { httpRequest = new HttpGet(url); } resp = this.httpclient.execute(httpRequest); InputStream is = resp.getEntity().getContent(); StringWriter writer = new StringWriter(); IOUtils.copy(is, writer); this.result.put("body", writer.toString()); this.result.put("total_time", Long.toString(System.currentTimeMillis() - startTime)); this.result.put("statusCode", Integer.toString(resp.getStatusLine().getStatusCode())); this.headers = resp.getAllHeaders(); if (resp != null) { resp.close(); } } /** * Returns the body of the response payload as returned by the * URL endpoint * * @return the body of the response, typically a JSON string */ public String getBody() { if (this.result.containsKey("body")) { return this.result.get("body"); } return ""; } /** * Returns part of the response headers * * @param type Which key in the headers packet to return * @return Header from the response packet */ public String getHeader(String name) { if (this.headers == null) { return ""; } for (Header header : this.headers) { if (header.getName().equals(name)) { return header.getValue(); } } return ""; } /** * Returns the content type of the response * * @return The response's content type */ public String getContentType() { if (this.headers == null) { return ""; } for (Header header : this.headers) { if (header.getName().equals("content_type")) { return header.getValue(); } } return ""; } /** * The HTTP status code of the request response * * @return status code */ public int getStatusCode() { if (result.containsKey("statusCode")) { return Integer.parseInt(this.result.get("statusCode")); } return -1; } /** * Total transaction time in milliseconds for last transfer * * @return time in milliseconds */ public long getTimeTaken() { if (this.result.containsKey("total_time")) { return Long.parseLong(this.result.get("total_time")); } return -1; } /** * Create a query string for a http get request using a map as input * @return query String */ private String makeQueryString(Map<String,Object> values) { List<NameValuePair> parameters = makeNameValueList(values); return URLEncodedUtils.format(parameters, "UTF-8"); } /** * Create a List containing NameValuePairs out of a map * * @return List<NameValuePair> */ private List<NameValuePair> makeNameValueList(Map<String,Object> values) { List<NameValuePair> parameters = new ArrayList<NameValuePair>(); for(Map.Entry<String, Object> entry : values.entrySet()) { parameters.add(new BasicNameValuePair(entry.getKey(), entry.getValue().toString())); } return parameters; } }