package mining; import java.io.IOException; import java.io.InputStream; import java.io.StringWriter; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLConnection; import java.util.logging.Logger; import org.apache.commons.io.Charsets; import org.apache.commons.io.IOUtils; import org.json.JSONException; import org.json.JSONObject; /** * Performs an API Request. * * @author Peter Wu */ public abstract class AbstractRequester implements Requester { private static final Logger LOGGER = Logger.getLogger(AbstractRequester.class.getName()); private static final String API_URL = "https://api.twitter.com/"; @Override public JSONObject getJSON(String resource) throws IOException { return getJSON(resource, true); } @Override public JSONObject getJSONRelax(String resource) throws IOException { return getJSON(resource, false); } private JSONObject getJSON(String resource, boolean checkStatusCode) throws IOException { HttpURLConnection conn = open(buildUrl(resource)); preconnect(conn); JSONObject resp = getResponseAsJson(conn); /* print response to stderr for debugging */ if (resp.has("errors")) { try { String errors = resp.get("errors").toString(); getLogger().fine("Request failed: " + errors); } catch (JSONException ex) { } } if (checkStatusCode && conn.getResponseCode() != 200) { // TODO: print more helpful details throw new IOException("Unexpected response code"); } return resp; } protected final URL buildUrl(String resource) throws IOException { String spec = API_URL; if (!resource.startsWith("oauth/") && !resource.startsWith("oauth2/")) { // manual inspection shows that at least oauth/ and oauth2/ do not // have a version prefixed. spec += "1.1/"; } spec += resource; spec += ".json"; return new URL(spec); } /** * Opens a connection to the URL. * * @param url The URL to open a connection to. * @return a connection that can be used for sending requests. * @throws java.io.IOException on failure to open a connection. */ protected final HttpURLConnection open(URL url) throws IOException { getLogger().fine("Opening: " + url); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); // set default param: fail if no response within 5 seconds conn.setReadTimeout(5000); return conn; } /** * Reads the response body from a connection (in JSON format). * * @param conn An open connection to which a request was already made. * @return A JSON object as parsed from the response. * @throws java.io.IOException if the response cannot be retrieved or if the * response does not contain well-formed JSON. */ protected final JSONObject getResponseAsJson(HttpURLConnection conn) throws IOException { StringWriter writer = new StringWriter(); InputStream is; try { is = conn.getInputStream(); } catch (IOException ex) { /* 404 (FileNotFoundException) */ is = conn.getErrorStream(); } IOUtils.copy(is, writer, Charsets.UTF_8); try { return new JSONObject(writer.toString()); } catch (JSONException ex) { // treat JSON errors as if an I/O error occurred throw new IOException(ex); } } /** * Prepare the request before it gets send. * * @param conn A connection for the request. * @throws java.io.IOException on failing to prepare the request. */ protected abstract void preconnect(URLConnection conn) throws IOException; private Logger getLogger() { return Logger.getLogger(getClass().getName()); } }