/**
* Copyright (C) 2008 Progress Software, Inc. All rights reserved.
* http://fusesource.com
*
* The software in this package is published under the terms of the AGPL license
* a copy of which has been included with this distribution in the license.txt file.
*/
package org.fusesource.cloudmix.agent;
import javax.ws.rs.core.EntityTag;
import com.sun.jersey.api.NotFoundException;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* A helper class to wrap up retry logic.
*
* @version $Revision: 1.1 $
*/
public class RestTemplate {
private static final transient Log LOG = LogFactory.getLog(RestTemplate.class);
private int retryAttempts = 10;
private long delayBetweenAttempts = 100L;
private EntityTag pollETag;
public <T> T get(WebResource.Builder resource, Class<T> resultType) {
T answer = null;
for (int i = 0; i < retryAttempts && answer == null; i++) {
ClientResponse response = resource.get(ClientResponse.class);
if (response != null) {
if (response.getStatus() < 300) {
answer = response.getEntity(resultType);
} else if (response.getStatus() == 404) {
if (LOG.isDebugEnabled()) {
LOG.debug(resource + " bad response: " + response.getStatus() + "-" + response.getResponseStatus().getReasonPhrase() + "[attempt: " + i + "]");
}
break;
} else {
if (LOG.isWarnEnabled()) {
LOG.warn(resource + " bad response: " + response.getStatus() + "-" + response.getResponseStatus().getReasonPhrase() + "[attempt: " + i + "]");
}
}
}
}
return answer;
}
/**
* Polls the given resource only returning the value if its changed since
* the last time we asked for it
*/
public <T> T poll(WebResource.Builder request, Class<T> resultType) {
for (int i = 0; i < retryAttempts; i++) {
/*
* I think we should ignore the If-Modified-Since header... if
* (pollLastModifiedDate != null) { request =
* request.header("If-Modified-Since", pollLastModifiedDate); }
*/
if (pollETag != null) {
request = request.header("If-None-Match", pollETag);
}
ClientResponse response = request.get(ClientResponse.class);
int status = response.getStatus();
// is the response unmodified
if (status == 304) {
if (LOG.isDebugEnabled()) {
LOG.debug("Unmodified results for: " + request);
}
return null;
} else if (status == 200) {
EntityTag etag = response.getEntityTag();
if (etag != null) {
pollETag = etag;
}
T value = response.getEntity(resultType);
if (value != null) {
if (LOG.isDebugEnabled()) {
LOG.debug("New provisioning instructions: " + value);
}
return value;
} else {
LOG.error("Could not find an entity for the response: " + response);
}
} else {
LOG.warn("Unknown status code: " + status + " when polling: " + request);
throw new NotFoundException("Status: " + status);
}
}
return null;
}
public int put(final WebResource.Builder resource, final Object body) {
return retryLoop(new RestOperation() {
public ClientResponse invoke() {
return resource.put(ClientResponse.class, body);
}
});
}
public int put(final WebResource.Builder resource) {
return retryLoop(new RestOperation() {
public ClientResponse invoke() {
return resource.put(ClientResponse.class);
}
});
}
public int delete(final WebResource.Builder resource) {
return retryLoop(new RestOperation() {
public ClientResponse invoke() {
return resource.delete(ClientResponse.class);
}
});
}
public long getDelayBetweenAttempts() {
return delayBetweenAttempts;
}
public void setDelayBetweenAttempts(long delayBetweenAttempts) {
this.delayBetweenAttempts = delayBetweenAttempts;
}
public int getRetryAttempts() {
return retryAttempts;
}
public void setRetryAttempts(int retryAttempts) {
this.retryAttempts = retryAttempts;
}
/**
* Performs the given operation {@link #getRetryAttempts()} times returning
* the final error code
*/
protected int retryLoop(RestOperation operation) {
int status = -1;
for (int i = 0; i < retryAttempts; i++) {
ClientResponse response = operation.invoke();
if (response != null) {
status = response.getStatus();
if (status < 300) {
break;
}
}
}
return status;
}
}