package com.capra.integration.asana.http;
import com.capra.integration.asana.AsanaException;
import com.google.api.client.http.*;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.http.json.JsonHttpContent;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.JsonObjectParser;
import com.google.api.client.json.jackson2.JacksonFactory;
//import com.google.api.client.json.jackson.JacksonFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.capra.integration.asana.AsanaConfiguration;
import com.capra.integration.asana.model.AsanaData;
import com.capra.integration.asana.model.AsanaDataType;
import com.capra.integration.asana.model.AsanaJsonData;
import java.io.IOException;
import java.net.UnknownHostException;
/**
* Wrapper around google http-client which adds asana specific stuff.
*
* @author lka@capraconsulting.no
* @since 13-09-2013 11:15
*/
public class AsanaGoogleHttpClient implements AsanaHttpClient {
final Logger logger = LoggerFactory.getLogger(getClass());
/** Asana configuration on which this client rely. */
private final AsanaConfiguration asanaConfiguration;
private final HttpTransport HTTP_TRANSPORT = new NetHttpTransport();
private final JsonFactory JSON_FACTORY = new JacksonFactory();
/**
* Best for production usage.
*
* @param asanaConfiguration configuration for asana.
*/
public AsanaGoogleHttpClient(AsanaConfiguration asanaConfiguration) {
this.asanaConfiguration = asanaConfiguration;
}
/**
* Get configuration which is used inside this http client.
*
* @return asana configuration.
*/
public AsanaConfiguration getAsanaConfiguration() {
return asanaConfiguration;
}
/**
* GET http with result.
*
* @param expectedResult class which is expected as a result.
* @param genericUrl url for get request.
* @param <O> output result type from http
*
* @return if request end with success it will return expected object, otherwise runtime exception will be thrown.
*/
@Override
public <O> O get(Class<O> expectedResult, GenericUrl genericUrl) {
O result = null;
HttpRequestFactory requestFactory = createRequestFactory();
HttpRequest httpRequest;
Class typeOfTeResult = findTypeOfResult(expectedResult);
try {
httpRequest = requestFactory.buildGetRequest(genericUrl);
} catch (IOException e) {
String errorMessage = String.format("Build GET Request for URL <%s> fails, with following message <%s>", genericUrl.build(), e.getMessage());
logger.error(errorMessage, e);
throw new AsanaException(errorMessage, e);
}
HttpResponse execute = null;
try {
execute = httpRequest.execute();
} catch (UnknownHostException unknownHostException) {
String errorMessage = String.format("Executing GET Request <%s> for unknown host. Possible reasons: 1. Typo in URL, 2. Not working internet connections", genericUrl.build());
logger.error(errorMessage, unknownHostException);
throw new AsanaException(errorMessage, unknownHostException);
} catch (HttpResponseException httpResponseException) {
int statusCode = httpResponseException.getStatusCode();
String errorMessage = String.format("Executing GET Request <%s> fails with response status code <%s> and following message <%s>",
genericUrl.build(), String.valueOf(statusCode), httpResponseException.getMessage());
// not found
if (statusCode == 404) {
return null;
}
logger.error(errorMessage, httpResponseException);
throw new AsanaException(errorMessage, httpResponseException);
} catch (IOException e) {
String errorMessage = String.format("Executing GET Request <%s> fails, with following message <%s>", genericUrl.build(), e.getMessage());
logger.error(errorMessage, e);
throw new AsanaException(errorMessage, e);
}
Object resultObject = null;
try {
resultObject = execute.parseAs(typeOfTeResult);
} catch (IOException e) {
String errorMessage = String.format("Parsing Response from GET Request <%s> fails, with following message <%s>", genericUrl.build(), e.getMessage());
logger.error(errorMessage, e);
throw new AsanaException(errorMessage, e);
}
return prepareResult(resultObject, expectedResult);
}
/**
* PUT http with result.
*
* @param expectedResult
* @param input
* @param genericUrl
* @param <I>
* @param <O>
* @return
*/
public <I, O> O post(Class<O> expectedResult, I input, GenericUrl genericUrl) {
AsanaJsonData<I> inputData = new AsanaJsonData<I>(input);
HttpRequestFactory requestFactory = createRequestFactory();
JsonHttpContent jsonHttpContent = new JsonHttpContent(JSON_FACTORY, inputData);
Class typeOfTeResult = findTypeOfResult(expectedResult);
HttpRequest httpRequest;
try {
httpRequest = requestFactory.buildPostRequest(genericUrl, jsonHttpContent);
} catch (IOException e) {
String errorMessage = String.format("Building POST Request <%s> fails, with following message <%s>", genericUrl.build(), e.getMessage());
logger.error(errorMessage, e);
throw new AsanaException(errorMessage, e);
}
HttpResponse response;
try {
response = httpRequest.execute();
} catch (UnknownHostException unknownHostException) {
String errorMessage = String.format("Executing POST Request <%s> for unknown host. Possible reasons: 1. Typo in URL, 2. Not working internet connections", genericUrl.build());
logger.error(errorMessage, unknownHostException);
throw new AsanaException(errorMessage, unknownHostException);
} catch (IOException e) {
String errorMessage = String.format("Executing POST Request <%s> fails, with following message <%s>", genericUrl.build(), e.getMessage());
logger.error(errorMessage, e);
throw new AsanaException(errorMessage, e);
}
Object result;
try {
result = response.parseAs(typeOfTeResult);
} catch (IOException e) {
String errorMessage = String.format("Parsing Response from POST Request <%s> fails, with following message <%s>", genericUrl.build(), e.getMessage());
logger.error(errorMessage, e);
throw new AsanaException(errorMessage, e);
}
return prepareResult(result, expectedResult);
}
public <I, O> O put(Class<O> expectedResult, I input, GenericUrl genericUrl) {
AsanaJsonData<I> inputData = new AsanaJsonData<I>(input);
HttpRequestFactory requestFactory = createRequestFactory();
JsonHttpContent jsonHttpContent = new JsonHttpContent(JSON_FACTORY, inputData);
Class typeOfTeResult = findTypeOfResult(expectedResult);
HttpRequest httpRequest;
try {
httpRequest = requestFactory.buildPutRequest(genericUrl, jsonHttpContent);
} catch (IOException e) {
String errorMessage = String.format("Building PUT Request <%s> fails, with following message <%s>", genericUrl.build(), e.getMessage());
logger.error(errorMessage, e);
throw new AsanaException(errorMessage, e);
}
HttpResponse response;
try {
response = httpRequest.execute();
} catch (UnknownHostException unknownHostException) {
String errorMessage = String.format("Executing PUT Request <%s> for unknown host. Possible reasons: 1. Typo in URL, 2. Not working internet connections", genericUrl.build());
logger.error(errorMessage, unknownHostException);
throw new AsanaException(errorMessage, unknownHostException);
} catch (IOException e) {
String errorMessage = String.format("Executing PUT Request <%s> fails, with following message <%s>", genericUrl.build(), e.getMessage());
logger.error(errorMessage, e);
throw new AsanaException(errorMessage, e);
}
Object result;
try {
result = response.parseAs(typeOfTeResult);
} catch (IOException e) {
String errorMessage = String.format("Parsing Response from PUT Request <%s> fails, with following message <%s>", genericUrl.build(), e.getMessage());
logger.error(errorMessage, e);
throw new AsanaException(errorMessage, e);
}
return prepareResult(result, expectedResult);
}
/**
* Post without result.
*
* @param input
* @param genericUrl
* @param <I>
*/
public <I> void post(I input, GenericUrl genericUrl) {
//
Object inputData = null;
// if (input.getClass().getName().endsWith("Operation")) {
// inputData = input;
// } else {
inputData = new AsanaJsonData<I>(input);
// }
HttpRequestFactory requestFactory = createRequestFactory();
JsonHttpContent jsonHttpContent = new JsonHttpContent(JSON_FACTORY, inputData);
HttpRequest httpRequest;
try {
httpRequest = requestFactory.buildPostRequest(genericUrl, jsonHttpContent);
} catch (IOException e) {
String errorMessage = String.format("Building POST Request <%s> fails, with following message <%s>", genericUrl.build(), e.getMessage());
logger.error(errorMessage, e);
throw new AsanaException(errorMessage, e);
}
try {
httpRequest.execute();
} catch (UnknownHostException unknownHostException) {
String errorMessage = String.format("Executing POST Request <%s> for unknown host. Possible reasons: 1. Typo in URL, 2. Not working internet connections", genericUrl.build());
logger.error(errorMessage, unknownHostException);
throw new AsanaException(errorMessage, unknownHostException);
} catch (IOException e) {
String errorMessage = String.format("Executing POST Request <%s> fails, with following message <%s>", genericUrl.build(), e.getMessage());
logger.error(errorMessage, e);
throw new AsanaException(errorMessage, e);
}
}
public void delete(GenericUrl genericUrl) {
HttpRequestFactory requestFactory = createRequestFactory();
HttpRequest httpRequest = null;
try {
httpRequest = requestFactory.buildDeleteRequest(genericUrl);
} catch (IOException e) {
String errorMessage = String.format("Building DELETE Request <%s> fails, with following message <%s>", genericUrl.build(), e.getMessage());
logger.error(errorMessage, e);
throw new AsanaException(errorMessage, e);
}
try {
httpRequest.execute();
} catch (UnknownHostException unknownHostException) {
String errorMessage = String.format("Executing DELETE Request <%s> for unknown host. Possible reasons: 1. Typo in URL, 2. Not working internet connections", genericUrl.build());
logger.error(errorMessage, unknownHostException);
throw new AsanaException(errorMessage, unknownHostException);
} catch (IOException e) {
String errorMessage = String.format("Executing DELETE Request <%s> fails, with following message <%s>", genericUrl.build(), e.getMessage());
logger.error(errorMessage, e);
throw new AsanaException(errorMessage, e);
}
}
private HttpRequestFactory createRequestFactory() {
return HTTP_TRANSPORT.createRequestFactory(new HttpRequestInitializer() {
@Override
public void initialize(HttpRequest request) {
request.setParser(new JsonObjectParser(JSON_FACTORY));
request.getHeaders().setBasicAuthentication(asanaConfiguration.getUserApiKey(), " ");
}
});
}
private <O> Class findTypeOfResult(Class<O> expectedResult) {
if (expectedResult == null) {
throw new IllegalArgumentException("Expected result type can not be NULL");
}
Class typeOfTeResult = null;
if (AsanaData.class.isAssignableFrom(expectedResult)) {
typeOfTeResult = expectedResult;
} else {
AsanaDataType asanaDataType = expectedResult.getAnnotation(AsanaDataType.class);
if (asanaDataType != null) {
typeOfTeResult = asanaDataType.value();
}
}
if (typeOfTeResult == null) {
throw new IllegalArgumentException(String.format("Can not get expected type of result <%s>, you need to use implementation of <%s> and provide annotation <%s> on data object",
expectedResult.getName(), AsanaData.class.getName(), AsanaDataType.class.getName()));
}
return typeOfTeResult;
}
private <O> O prepareResult(Object resultObject, Class<O> expectedResult) {
if (resultObject instanceof AsanaData) {
if (resultObject.getClass().equals(expectedResult)) {
return (O) resultObject;
} else {
AsanaData<O> asanaData = (AsanaData) resultObject;
return (O) asanaData.getData();
}
} else {
throw new IllegalStateException();
}
}
}