summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/io/AbstractRequester.java22
-rw-r--r--src/io/BearerRequester.java17
-rw-r--r--src/io/OAuthRequester.java11
-rw-r--r--src/io/RateLimitException.java18
-rw-r--r--src/io/Requester.java3
5 files changed, 54 insertions, 17 deletions
diff --git a/src/io/AbstractRequester.java b/src/io/AbstractRequester.java
index 239e75d..913e9bd 100644
--- a/src/io/AbstractRequester.java
+++ b/src/io/AbstractRequester.java
@@ -1,6 +1,8 @@
package io;
+import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import java.io.FileNotFoundException;
import java.io.IOException;
@@ -24,28 +26,35 @@ public abstract class AbstractRequester implements Requester {
private static final String API_URL = "https://api.twitter.com/";
@Override
- public Response getJSON(String resource) throws IOException {
+ public Response getJSON(String resource)
+ throws IOException, RateLimitException {
HttpURLConnection conn = open(buildUrl(resource));
try {
preconnect(conn);
JsonElement resp = getResponseAsJson(conn);
-
- if(resp.isJsonObject() && resp.getAsJsonObject().has("errors")) {
+
+ 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 (conn.getResponseCode() != 200) {
+ if (conn.getResponseCode() == 429) {
+ //TODO: wait for real time and not 15 minutes.
+ throw new RateLimitException(Integer.parseInt(conn.getHeaderField("X-Rate-Limit-Reset")));
+ }
// TODO: print more helpful details
throw new IOException("Unexpected response code");
- }
+ }
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();
@@ -116,11 +125,10 @@ public abstract class AbstractRequester implements Requester {
throw new IOException("Failed to fetch response");
}
IOUtils.copy(is, writer, Charsets.UTF_8);
-
+
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 11776fc..8af38f8 100644
--- a/src/io/BearerRequester.java
+++ b/src/io/BearerRequester.java
@@ -1,14 +1,13 @@
package io;
-import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import java.io.IOException;
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.json.JSONException;
-import org.json.JSONObject;
import support.ConsumerKeySecret;
/**
@@ -88,9 +87,13 @@ public class BearerRequester extends AbstractRequester {
@Override
public boolean isValid() throws IOException {
- // NOTE: this actually contributes to the ratelimit (12/minute)
- // TODO: find alternative that does not hit the ratelimit
- Response obj = getJSON("application/rate_limit_status");
- return !obj.getResp().getAsJsonObject().has("errors");
+ try {
+ // NOTE: this actually contributes to the ratelimit (12/minute)
+ // TODO: find alternative that does not hit the ratelimit
+ Response obj = getJSON("application/rate_limit_status");
+ return obj.getResp().getAsJsonObject().has("errors");
+ } catch (RateLimitException ex) {
+ return false;
+ }
}
}
diff --git a/src/io/OAuthRequester.java b/src/io/OAuthRequester.java
index 3621186..9cde429 100644
--- a/src/io/OAuthRequester.java
+++ b/src/io/OAuthRequester.java
@@ -3,6 +3,8 @@ package io;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URLConnection;
+import java.util.logging.Level;
+import java.util.logging.Logger;
import oauth.signpost.OAuth;
import oauth.signpost.OAuthConsumer;
import oauth.signpost.basic.DefaultOAuthConsumer;
@@ -136,7 +138,12 @@ public class OAuthRequester 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
- Response obj = getJSON("application/rate_limit_status");
- return !obj.getResp().getAsJsonObject().has("errors");
+ Response obj;
+ try {
+ obj = getJSON("application/rate_limit_status");
+ return !obj.getResp().getAsJsonObject().has("errors");
+ } catch (RateLimitException ex) {
+ return false;
+ }
}
}
diff --git a/src/io/RateLimitException.java b/src/io/RateLimitException.java
new file mode 100644
index 0000000..2bb2624
--- /dev/null
+++ b/src/io/RateLimitException.java
@@ -0,0 +1,18 @@
+package io;
+
+/**
+ * The exception that will be thrown when a ratelimit has been hit.
+ *
+ * @author Maurice Laveaux
+ */
+public class RateLimitException extends Exception {
+ private final long rateLimitReset;
+
+ public RateLimitException(long resetTime) {
+ rateLimitReset = resetTime;
+ }
+
+ public long getResetTime() {
+ return rateLimitReset;
+ }
+}
diff --git a/src/io/Requester.java b/src/io/Requester.java
index 3dd09f3..11e0bb1 100644
--- a/src/io/Requester.java
+++ b/src/io/Requester.java
@@ -20,8 +20,9 @@ public interface Requester {
* @param resource The REST resource.
* @return A JSON object resulting from the request.
* @throws java.io.IOException on error fetching the resource.
+ * @throws io.RateLimitException on ratelimit errors.
*/
- public Response getJSON(String resource) throws IOException;
+ public Response getJSON(String resource) throws IOException, RateLimitException;
/**
* Tests whether this instance can dispatch requests.