public T execute() throws APIException, IOException {
if (radio != null && (node != null || nodes != null)) {
throw new RuntimeException("You set both and a Node and a Radio as target. This is not possible.");
}
final ClusterEntity target;
if (radio == null) {
if (node == null) {
if (nodes != null) {
LOG.error("Multiple nodes are set, but execute() was called. This is most likely a bug and you meant to call executeOnAll()!", new Throwable());
}
node(serverNodes.any());
}
target = node;
} else {
target = radio;
}
ensureAuthentication();
final URL url = prepareUrl(target);
final AsyncHttpClient.BoundRequestBuilder requestBuilder = requestBuilderForUrl(url);
requestBuilder.addHeader(Http.HeaderNames.ACCEPT, mediaType.toString());
final Request request = requestBuilder.build();
if (LOG.isDebugEnabled()) {
LOG.debug("API Request: {}", request.toString());
}
// Set 200 OK as standard if not defined.
if (expectedResponseCodes.isEmpty()) {
expectedResponseCodes.add(Http.Status.OK);
}
try {
// TODO implement streaming responses
Response response = requestBuilder.execute().get(timeoutValue, timeoutUnit);
target.touch();
// TODO this is wrong, shouldn't it accept some callback instead of throwing an exception?
if (!expectedResponseCodes.contains(response.getStatusCode())) {
throw new APIException(request, response);
}
// TODO: once we switch to jackson we can take the media type into account automatically
final MediaType responseContentType;
if (response.getContentType() == null) {
responseContentType = MediaType.JSON_UTF_8;
} else {
responseContentType = MediaType.parse(response.getContentType());
}
if (!responseContentType.is(mediaType.withoutParameters())) {
LOG.warn("We said we'd accept {} but got {} back, let's see how that's going to work out...", mediaType, responseContentType);
}
if (responseClass.equals(String.class)) {
return responseClass.cast(response.getResponseBody("UTF-8"));
}
if (expectedResponseCodes.contains(response.getStatusCode())
|| (response.getStatusCode() >= 200 && response.getStatusCode() < 300)) {
T result;
try {
if (response.getResponseBody().isEmpty()) {
return null;
}
if (responseContentType.is(MediaType.JSON_UTF_8.withoutParameters())) {
result = deserializeJson(response, responseClass);
} else {
LOG.error("Don't know how to deserialize objects with content in {}, expected {}, failing.", responseContentType, mediaType);
throw new APIException(request, response);
}
if (result == null) {
throw new APIException(request, response);
}
return result;
} catch (Exception e) {
LOG.error("Caught Exception while deserializing JSON request: ", e);
LOG.debug("Response from backend was: " + response.getResponseBody("UTF-8"));
throw new APIException(request, response, e);
}
} else {
return null;
}
} catch (InterruptedException e) {
// TODO
target.markFailure();
} catch (MalformedURLException e) {
LOG.error("Malformed URL", e);
throw new RuntimeException("Malformed URL.", e);
} catch (ExecutionException e) {
if (e.getCause() instanceof ConnectException) {
LOG.warn("Graylog2 server unavailable. Connection refused.");
target.markFailure();
throw new Graylog2ServerUnavailableException(e);
}
LOG.error("REST call failed", rootCause(e));
throw new APIException(request, e);
} catch (IOException e) {
// TODO
LOG.error("unhandled IOException", rootCause(e));
target.markFailure();
throw e;
} catch (TimeoutException e) {
LOG.warn("Timed out requesting {}", request);
target.markFailure();
}
throw new APIException(request, new IllegalStateException("Unhandled error condition in API client"));
}