From 0c07b1d1a83ab20b4c753c40ea8048f73b3e5745 Mon Sep 17 00:00:00 2001 From: Maurice Laveaux Date: Thu, 22 May 2014 09:02:50 +0200 Subject: Changed Request response to a new Response class. * Response contains the JsonElement, tickrate, reset and leftover data. * Removed getJsonRelaxed, because it was not used elsewhere. --- src/io/AbstractRequester.java | 56 +++++++++++++++++++------------------------ src/io/BearerRequester.java | 26 ++++++++++---------- src/io/OAuthRequester.java | 7 ++---- src/io/Requester.java | 14 ++--------- src/io/Response.java | 42 ++++++++++++++++++++++++++++++++ src/mining/TwitterApi.java | 5 ++-- 6 files changed, 86 insertions(+), 64 deletions(-) create mode 100644 src/io/Response.java diff --git a/src/io/AbstractRequester.java b/src/io/AbstractRequester.java index ac74533..239e75d 100644 --- a/src/io/AbstractRequester.java +++ b/src/io/AbstractRequester.java @@ -1,5 +1,7 @@ package io; +import com.google.gson.JsonElement; +import com.google.gson.JsonParser; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; @@ -7,11 +9,10 @@ import java.io.StringWriter; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLConnection; +import java.util.logging.Level; 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. @@ -23,36 +24,29 @@ public abstract class AbstractRequester implements Requester { 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 { + public Response getJSON(String resource) throws IOException { HttpURLConnection conn = open(buildUrl(resource)); try { preconnect(conn); - JSONObject resp = getResponseAsJson(conn); - /* print response to stderr for debugging */ - if (resp.has("errors")) { - try { - String errors = resp.get("errors").toString(); - getLogger().info("Request failed: " + errors); - } catch (JSONException ex) { - } + JsonElement resp = getResponseAsJson(conn); + + if(resp.isJsonObject() && resp.getAsJsonObject().has("errors")) { + /* print response to stderr for debugging */ + String errors = resp.getAsJsonObject().get("errors").toString(); + getLogger().log(Level.INFO, "Request failed: {0}", errors); } // TODO: what if there is an internal server error? Technically we // should always treat that as "don't know what the server thinks". - if (checkStatusCode && conn.getResponseCode() != 200) { + if (conn.getResponseCode() != 200) { // TODO: print more helpful details throw new IOException("Unexpected response code"); - } - return resp; + } + + int rateLimit = Integer.parseInt(conn.getHeaderField("X-Rate-Limit-Limit")); + int rateLimitRemaining = Integer.parseInt(conn.getHeaderField("X-Rate-Limit-Remaining")); + int rateLimitReset = Integer.parseInt(conn.getHeaderField("X-Rate-Limit-Reset")); + + return new Response(resp, rateLimit, rateLimitRemaining, rateLimitReset); } finally { conn.disconnect(); } @@ -92,7 +86,7 @@ public abstract class AbstractRequester implements Requester { * @throws java.io.IOException on failure to open a connection. */ protected final HttpURLConnection open(URL url) throws IOException { - getLogger().fine("Opening: " + url); + getLogger().log(Level.FINE, "Opening: {0}", url); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); // set default param: fail if no response within 5 seconds conn.setReadTimeout(5000); @@ -107,7 +101,7 @@ public abstract class AbstractRequester implements Requester { * @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) + protected final JsonElement getResponseAsJson(HttpURLConnection conn) throws IOException { StringWriter writer = new StringWriter(); InputStream is; @@ -122,13 +116,11 @@ public abstract class AbstractRequester implements Requester { throw new IOException("Failed to fetch response"); } 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); - } + + JsonParser parser = new JsonParser(); + return parser.parse(writer.toString()); } + /** * Prepare the request before it gets send. diff --git a/src/io/BearerRequester.java b/src/io/BearerRequester.java index 442f62a..11776fc 100644 --- a/src/io/BearerRequester.java +++ b/src/io/BearerRequester.java @@ -1,5 +1,7 @@ package io; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; import java.io.IOException; import java.net.HttpURLConnection; import java.net.URL; @@ -57,18 +59,16 @@ public class BearerRequester extends AbstractRequester { conn.setDoOutput(true); conn.getOutputStream().write(postData.getBytes(Charsets.UTF_8)); - try { - JSONObject resp = getResponseAsJson(conn); - // TODO: parse resp.errors - if (!resp.getString("token_type").equals("bearer")) { - throw new IOException("Expected bearer token type"); - } - access_token = resp.getString("access_token"); - } catch (JSONException ex) { - // treat JSON errors as if an I/O error occurred - throw new IOException(ex); + JsonObject resp = getResponseAsJson(conn).getAsJsonObject(); + if (!resp.getAsJsonObject().getAsJsonPrimitive("token_type").getAsString().equals("bearer")) { + throw new IOException("Expected bearer token type"); } - } finally { + access_token = resp.getAsJsonPrimitive("access_token").getAsString(); + } + catch (ClassCastException ex) { + throw new IOException("Response was not a JsonObject"); + } + finally { conn.disconnect(); } } @@ -90,7 +90,7 @@ public class BearerRequester extends AbstractRequester { public boolean isValid() throws IOException { // NOTE: this actually contributes to the ratelimit (12/minute) // TODO: find alternative that does not hit the ratelimit - JSONObject obj = getJSONRelax("application/rate_limit_status"); - return !obj.has("errors"); + Response obj = getJSON("application/rate_limit_status"); + return !obj.getResp().getAsJsonObject().has("errors"); } } diff --git a/src/io/OAuthRequester.java b/src/io/OAuthRequester.java index c3538ee..3621186 100644 --- a/src/io/OAuthRequester.java +++ b/src/io/OAuthRequester.java @@ -134,12 +134,9 @@ public class OAuthRequester extends AbstractRequester { @Override public boolean isValid() throws IOException { - if (consumer.getToken() == null) { - return false; - } // NOTE: this actually contributes to the ratelimit (12/minute) // TODO: find alternative that does not hit the ratelimit - JSONObject obj = getJSONRelax("application/rate_limit_status"); - return !obj.has("errors"); + Response obj = getJSON("application/rate_limit_status"); + return !obj.getResp().getAsJsonObject().has("errors"); } } diff --git a/src/io/Requester.java b/src/io/Requester.java index 7f09a48..3dd09f3 100644 --- a/src/io/Requester.java +++ b/src/io/Requester.java @@ -1,5 +1,6 @@ package io; +import com.google.gson.JsonElement; import java.io.IOException; import org.json.JSONObject; @@ -20,18 +21,7 @@ public interface Requester { * @return A JSON object resulting from the request. * @throws java.io.IOException on error fetching the resource. */ - public JSONObject getJSON(String resource) throws IOException; - - /** - * Almost equivalent to {@code getJSON(resource, true)}, except that an - * IOException is not thrown if the request reports an non-successful status - * code. - * - * @see Requester#getJSON(java.lang.String, boolean) - * @throws IOException on network errors or if the response could not be - * parsed into a valid JSONObject. - */ - public JSONObject getJSONRelax(String resource) throws IOException; + public Response getJSON(String resource) throws IOException; /** * Tests whether this instance can dispatch requests. diff --git a/src/io/Response.java b/src/io/Response.java new file mode 100644 index 0000000..5cc36e1 --- /dev/null +++ b/src/io/Response.java @@ -0,0 +1,42 @@ +package io; + +import com.google.gson.JsonElement; + +/** + * A response object with the Jsonelement and rate limit values. + * + * @author Maurice Laveaux + */ +public class Response { + + private final JsonElement element; + + private final int rateLimitReset; + + private final int rateLimitRemaining; + + private final int rateLimit; + + public Response(JsonElement resp, int rateLimit, int rateLimitRemaining, int rateLimitReset) { + this.element = resp; + this.rateLimit = rateLimit; + this.rateLimitRemaining = rateLimitRemaining; + this.rateLimitReset = rateLimitReset; + } + + public JsonElement getResp() { + return element; + } + + public int getRateLimit() { + return this.rateLimit; + } + + public int getRateLimitRemaining() { + return this.rateLimitRemaining; + } + + public int getRateLimitReset() { + return this.rateLimitReset; + } +} diff --git a/src/mining/TwitterApi.java b/src/mining/TwitterApi.java index 372aade..8889c2f 100644 --- a/src/mining/TwitterApi.java +++ b/src/mining/TwitterApi.java @@ -1,8 +1,9 @@ package mining; +import io.BearerRequester; import io.OAuthRequester; import io.Requester; -import io.BearerRequester; +import io.Response; import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -173,7 +174,7 @@ public class TwitterApi { return this.resource + "?" + URLEncodedUtils.format(params, Charsets.UTF_8); } - public JSONObject request() throws IOException { + public Response request() throws IOException { return TwitterApi.this.requester.getJSON(toString()); } } -- cgit v1.2.1