com.clarifai.api.ClarifaiRequester Maven / Gradle / Ivy
package com.clarifai.api;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.net.HttpURLConnection;
import com.clarifai.api.exception.ClarifaiBadRequestException;
import com.clarifai.api.exception.ClarifaiException;
import com.clarifai.api.exception.ClarifaiNotAuthorizedException;
import com.clarifai.api.exception.ClarifaiThrottledException;
import com.google.gson.JsonParseException;
/** Manages a single request to the Clarifai API. */
class ClarifaiRequester {
static enum Method {
GET, POST
}
private final ConnectionFactory connectionFactory;
private final CredentialManager credentialManager;
private final Method method;
private final String path;
private final Class resultClass;
private final int maxAttempts;
ClarifaiRequester(ConnectionFactory connectionFactory, CredentialManager credentialManager,
Method method, String path, Class resultClass, int maxAttempts) {
this.connectionFactory = connectionFactory;
this.credentialManager = credentialManager;
this.method = method;
this.path = path;
this.resultClass = resultClass;
this.maxAttempts = maxAttempts;
}
T execute(ClarifaiRequest request) throws ClarifaiException {
for (int i = maxAttempts - 1; i >= 0; i--) {
try {
return executeOnce(request);
} catch (ClarifaiNotAuthorizedException e) {
credentialManager.invalidateCredential();
if (i == 0) throw e;
} catch (ClarifaiThrottledException e) {
if (i == 0) throw e;
waitForSeconds(e.getWaitSeconds());
} catch (ClarifaiBadRequestException e) {
throw e; // Retrying will not help.
} catch (ClarifaiException e) {
if (i == 0) throw e;
}
}
throw new IllegalStateException();
}
T executeOnce(ClarifaiRequest request) throws ClarifaiException {
try {
// Send request:
HttpURLConnection conn;
if (method == Method.POST) {
conn = connectionFactory.newPost(path, credentialManager.getCredential());
} else {
conn = connectionFactory.newGet(path, credentialManager.getCredential());
}
if (request != null) {
conn.setRequestProperty("Content-Type", request.getContentType());
BufferedOutputStream out = new BufferedOutputStream(conn.getOutputStream());
try {
request.writeContent(out);
} finally {
out.close();
}
}
// Parse result:
boolean isSuccess = (conn.getResponseCode() >= 200 && conn.getResponseCode() < 300);
BaseResponse response;
if (isSuccess) {
response = ResponseUtil.parseJsonAndClose(conn.getInputStream(), BaseResponse.class);
} else {
response = ResponseUtil.parseJsonAndClose(conn.getErrorStream(), BaseResponse.class);
// The API returns a 400 when all images in a recognition request are bad. However, we
// want to communicate this back in the RecognitionResults rather than throwing an
// exception for consistency with the partial error and non-error cases.
if (conn.getResponseCode() == HttpURLConnection.HTTP_BAD_REQUEST &&
resultClass == RecognitionResult[].class &&
response.results != null && response.results.isJsonArray()) {
isSuccess = true;
} else {
ResponseUtil.throwExceptionForErrorResponse(conn, response);
}
}
if (resultClass == Void.class) {
return null;
} else {
return ResponseUtil.GSON.fromJson(response.results, resultClass);
}
} catch (IOException e) {
throw new ClarifaiException("IOException", e);
} catch (JsonParseException e) {
throw new ClarifaiException("Server returned an unparsable response", e);
}
}
private static void waitForSeconds(int seconds) {
try {
Thread.sleep(seconds * 1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new ClarifaiException("Interrupted", e);
}
}
}