This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package edu.sjsu.amigo.http.client; | |
import com.fasterxml.jackson.core.JsonProcessingException; | |
import com.mashape.unirest.http.HttpResponse; | |
import com.mashape.unirest.http.JsonNode; | |
import com.mashape.unirest.http.ObjectMapper; | |
import com.mashape.unirest.http.Unirest; | |
import com.mashape.unirest.http.exceptions.UnirestException; | |
import com.mashape.unirest.request.GetRequest; | |
import com.mashape.unirest.request.HttpRequestWithBody; | |
import java.io.*; | |
import java.util.Map; | |
import java.util.logging.Logger; | |
/** | |
* Wrapper over http methods with basic auth. | |
* | |
* Below methods are synchronous. | |
* | |
* For asynch methods use the unirest-java library directly. | |
* | |
* @author rwatsh on 2/27/17. | |
* @see "http://unirest.io/java.html" | |
*/ | |
public class HttpClient implements AutoCloseable { | |
private static final Logger LOGGER = Logger.getLogger(HttpClient.class.getName()); | |
private String user; | |
private String password; | |
/** | |
* Create a http client with no auth (user anonymous). | |
*/ | |
public HttpClient() { | |
init(); | |
} | |
/** | |
* Create a http client with basic auth. | |
* | |
* @param user | |
* @param passwd | |
*/ | |
public HttpClient(String user, String passwd) { | |
init(); | |
this.user = user; | |
this.password = passwd; | |
} | |
/** | |
* Initialize the instance. | |
*/ | |
private void init() { | |
// setup to serialize Json from\to Object using jackson object mapper | |
Unirest.setObjectMapper(new ObjectMapper() { | |
private com.fasterxml.jackson.databind.ObjectMapper jacksonObjectMapper | |
= new com.fasterxml.jackson.databind.ObjectMapper(); | |
public <T> T readValue(String value, Class<T> valueType) { | |
try { | |
return jacksonObjectMapper.readValue(value, valueType); | |
} catch (IOException e) { | |
throw new RuntimeException(e); | |
} | |
} | |
public String writeValue(Object value) { | |
try { | |
return jacksonObjectMapper.writeValueAsString(value); | |
} catch (JsonProcessingException e) { | |
throw new RuntimeException(e); | |
} | |
} | |
}); | |
} | |
public <T> Response<T> get(String url, Class<T> clazz) throws HttpClientException { | |
return get(url, null, null, null, clazz); | |
} | |
public <T> Response<T> get(String url, | |
Map<String, String> routeParamsMap, | |
Map<String, String> queryStringMap, | |
Map<String, String> headersMap, | |
Class<T> clazz) throws HttpClientException { | |
GetRequest request = Unirest.get(url); | |
return executeGetRequest(routeParamsMap, queryStringMap, headersMap, clazz, request); | |
} | |
public <T> Response<T> head(String url, Class<T> clazz) throws HttpClientException { | |
return head(url, null, null, null, clazz); | |
} | |
public <T> Response<T> head(String url, | |
Map<String, String> routeParamsMap, | |
Map<String, String> queryStringMap, | |
Map<String, String> headersMap, | |
Class<T> clazz) throws HttpClientException { | |
GetRequest request = Unirest.head(url); | |
return executeGetRequest(routeParamsMap, queryStringMap, headersMap, clazz, request); | |
} | |
public Response<Object> post(String url, Object bodyObject) throws HttpClientException { | |
return post(url, null, null, null, bodyObject); | |
} | |
public Response<Object> post(String url, | |
Map<String, String> routeParamsMap, | |
Map<String, String> queryStringMap, | |
Map<String, String> headersMap, | |
Object bodyObject) throws HttpClientException { | |
HttpRequestWithBody request = Unirest.post(url); | |
return executeHttpRequestWithBody(routeParamsMap, queryStringMap, headersMap, bodyObject, request); | |
} | |
public Response<Object> put(String url, Object bodyObject) throws HttpClientException { | |
return put(url, null, null, null, bodyObject); | |
} | |
public Response<Object> put(String url, | |
Map<String, String> routeParamsMap, | |
Map<String, String> queryStringMap, | |
Map<String, String> headersMap, | |
Object bodyObject) throws HttpClientException { | |
HttpRequestWithBody request = Unirest.post(url); | |
return executeHttpRequestWithBody(routeParamsMap, queryStringMap, headersMap, bodyObject, request); | |
} | |
public Response<Object> delete(String url, Object bodyObject) throws HttpClientException { | |
return delete(url, null, null, null, bodyObject); | |
} | |
public Response<Object> delete(String url, | |
Map<String, String> routeParamsMap, | |
Map<String, String> queryStringMap, | |
Map<String, String> headersMap, | |
Object bodyObject) throws HttpClientException { | |
HttpRequestWithBody request = Unirest.delete(url); | |
return executeHttpRequestWithBody(routeParamsMap, queryStringMap, headersMap, bodyObject, request); | |
} | |
private <T> Response executeGetRequest(Map<String, String> routeParamsMap, Map<String, String> queryStringMap, Map<String, String> headersMap, Class<T> clazz, GetRequest request) throws HttpClientException { | |
request.basicAuth(user, password); | |
if(routeParamsMap != null) { | |
for (Map.Entry<String, String> entry : routeParamsMap.entrySet()) { | |
request.routeParam(entry.getKey(), entry.getValue()); | |
} | |
} | |
if (queryStringMap != null) { | |
for (Map.Entry<String, String> entry : queryStringMap.entrySet()) { | |
request.queryString(entry.getKey(), entry.getValue()); | |
} | |
} | |
if (headersMap != null) { | |
for (Map.Entry<String, String> entry : headersMap.entrySet()) { | |
request.header(entry.getKey(), entry.getValue()); | |
} | |
} | |
try { | |
HttpResponse<T> response = request.asObject(clazz); | |
Response<T> r = new Response(); | |
r.setStatusCode(response.getStatus()); | |
r.setStatusText(response.getStatusText()); | |
r.setRawBody(getStringFromInputStream(response.getRawBody())); | |
r.setParsedObject(response.getBody()); | |
return r; | |
} catch (UnirestException e) { | |
throw new HttpClientException(e); | |
} | |
} | |
private Response executeHttpRequestWithBody(Map<String, String> routeParamsMap, Map<String, String> queryStringMap, Map<String, String> headersMap, Object bodyObject, HttpRequestWithBody request) throws HttpClientException { | |
request.basicAuth(user, password); | |
if(routeParamsMap != null) { | |
for (Map.Entry<String, String> entry : routeParamsMap.entrySet()) { | |
request.routeParam(entry.getKey(), entry.getValue()); | |
} | |
} | |
if (queryStringMap != null) { | |
for (Map.Entry<String, String> entry : queryStringMap.entrySet()) { | |
request.queryString(entry.getKey(), entry.getValue()); | |
} | |
} | |
if (headersMap != null) { | |
for (Map.Entry<String, String> entry : headersMap.entrySet()) { | |
request.header(entry.getKey(), entry.getValue()); | |
} | |
} | |
if(bodyObject != null) { | |
request.body(bodyObject); | |
} | |
try { | |
HttpResponse<JsonNode> response = request.asJson(); | |
Response<Object> r = new Response(); | |
r.setStatusCode(response.getStatus()); | |
r.setStatusText(response.getStatusText()); | |
r.setRawBody(getStringFromInputStream(response.getRawBody())); | |
r.setParsedObject(response.getBody().isArray() ? | |
response.getBody().getArray() : | |
response.getBody().getObject()); | |
return r; | |
} catch (UnirestException e) { | |
throw new HttpClientException(e); | |
} | |
} | |
// convert InputStream to String | |
private static String getStringFromInputStream(InputStream is) { | |
if (is == null) return ""; | |
BufferedReader br = null; | |
StringBuilder sb = new StringBuilder(); | |
String line; | |
try { | |
br = new BufferedReader(new InputStreamReader(is)); | |
while ((line = br.readLine()) != null) { | |
sb.append(line); | |
} | |
} catch (IOException e) { | |
e.printStackTrace(); | |
} finally { | |
if (br != null) { | |
try { | |
br.close(); | |
} catch (IOException e) { | |
e.printStackTrace(); | |
} | |
} | |
} | |
return sb.toString(); | |
} | |
/** | |
* Closes this resource, relinquishing any underlying resources. | |
* This method is invoked automatically on objects managed by the | |
* {@code try}-with-resources statement. | |
* <p> | |
* <p>While this interface method is declared to throw {@code | |
* Exception}, implementers are <em>strongly</em> encouraged to | |
* declare concrete implementations of the {@code close} method to | |
* throw more specific exceptions, or to throw no exception at all | |
* if the close operation cannot fail. | |
* <p> | |
* <p> Cases where the close operation may fail require careful | |
* attention by implementers. It is strongly advised to relinquish | |
* the underlying resources and to internally <em>mark</em> the | |
* resource as closed, prior to throwing the exception. The {@code | |
* close} method is unlikely to be invoked more than once and so | |
* this ensures that the resources are released in a timely manner. | |
* Furthermore it reduces problems that could arise when the resource | |
* wraps, or is wrapped, by another resource. | |
* <p> | |
* <p><em>Implementers of this interface are also strongly advised | |
* to not have the {@code close} method throw {@link | |
* InterruptedException}.</em> | |
* <p> | |
* This exception interacts with a thread's interrupted status, | |
* and runtime misbehavior is likely to occur if an {@code | |
* InterruptedException} is {@linkplain Throwable#addSuppressed | |
* suppressed}. | |
* <p> | |
* More generally, if it would cause problems for an | |
* exception to be suppressed, the {@code AutoCloseable.close} | |
* method should not throw it. | |
* <p> | |
* <p>Note that unlike the {@link Closeable#close close} | |
* method of {@link Closeable}, this {@code close} method | |
* is <em>not</em> required to be idempotent. In other words, | |
* calling this {@code close} method more than once may have some | |
* visible side effect, unlike {@code Closeable.close} which is | |
* required to have no effect if called more than once. | |
* <p> | |
* However, implementers of this interface are strongly encouraged | |
* to make their {@code close} methods idempotent. | |
* | |
* @throws Exception if this resource cannot be closed | |
*/ | |
@Override | |
public void close() throws Exception { | |
Unirest.shutdown(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package edu.sjsu.amigo.http.client; | |
/** | |
* A friendly http client exception. | |
* | |
* @author rwatsh on 2/27/17. | |
*/ | |
public class HttpClientException extends Exception { | |
public HttpClientException(String msg) { | |
super(msg); | |
} | |
public HttpClientException(Throwable throwable) { | |
super(throwable); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package edu.sjsu.amigo.http.client.test; | |
import edu.sjsu.amigo.http.client.HttpClient; | |
import edu.sjsu.amigo.http.client.Response; | |
import org.junit.Test; | |
import java.util.HashMap; | |
import java.util.Map; | |
/** | |
* Test against the http://httpbin.org service endpoints. | |
* | |
* @author rwatsh on 3/1/17. | |
*/ | |
public class HttpClientTest { | |
@Test | |
public void testGetRequest() throws Exception { | |
try(HttpClient c = new HttpClient()) { | |
Response<String> resp = c.get("http://httpbin.org/get", String.class); | |
System.out.println(resp); | |
} catch (Exception e) { | |
throw e; | |
} | |
} | |
@Test | |
public void testHeadRequest() throws Exception { | |
try (HttpClient c = new HttpClient()) { | |
Response<String> resp = c.head("http://httpbin.org/get", String.class); | |
System.out.println(resp); | |
} catch (Exception e) { | |
throw e; | |
} | |
} | |
@Test | |
public void testPostRequest() throws Exception { | |
try (HttpClient c = new HttpClient()) { | |
String data = "test"; | |
Response<Object> resp = c.post("http://httpbin.org/post", data); | |
System.out.println(resp); | |
} catch (Exception e) { | |
throw e; | |
} | |
} | |
@Test | |
public void testPutRequest() throws Exception { | |
try (HttpClient c = new HttpClient()) { | |
Map<String, String> data = new HashMap<>(); | |
data.put("isTest", "yes"); | |
Response<Object> resp = c.put("http://httpbin.org/put", null); | |
System.out.println(resp); | |
} catch (Exception e) { | |
throw e; | |
} | |
} | |
@Test | |
public void testDeleteRequest() throws Exception { | |
try (HttpClient c = new HttpClient()) { | |
String data = "test"; | |
Response<Object> resp = c.delete("http://httpbin.org/delete", data); | |
System.out.println(resp); | |
} catch (Exception e) { | |
throw e; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="UTF-8"?> | |
<project xmlns="http://maven.apache.org/POM/4.0.0" | |
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | |
<modelVersion>4.0.0</modelVersion> | |
<artifactId>httpclient-common</artifactId> | |
<dependencies> | |
<dependency> | |
<groupId>org.apache.httpcomponents</groupId> | |
<artifactId>httpclient</artifactId> | |
<version>${httpclient.version}</version> | |
</dependency> | |
<dependency> | |
<groupId>org.apache.httpcomponents</groupId> | |
<artifactId>httpasyncclient</artifactId> | |
<version>${httpasyncclient.version}</version> | |
</dependency> | |
<dependency> | |
<groupId>org.apache.httpcomponents</groupId> | |
<artifactId>httpmime</artifactId> | |
<version>${httpmime.version}</version> | |
</dependency> | |
<dependency> | |
<groupId>org.json</groupId> | |
<artifactId>json</artifactId> | |
<version>${json.version}</version> | |
</dependency> | |
<dependency> | |
<groupId>com.mashape.unirest</groupId> | |
<artifactId>unirest-java</artifactId> | |
<version>${unirest-java.version}</version> | |
</dependency> | |
<dependency> | |
<groupId>com.fasterxml.jackson.core</groupId> | |
<artifactId>jackson-core</artifactId> | |
<version>${jackson-core.version}</version> | |
</dependency> | |
<dependency> | |
<groupId>com.fasterxml.jackson.core</groupId> | |
<artifactId>jackson-annotations</artifactId> | |
<version>${jackson-core.version}</version> | |
</dependency> | |
<dependency> | |
<groupId>com.fasterxml.jackson.core</groupId> | |
<artifactId>jackson-databind</artifactId> | |
<version>${jackson-core.version}</version> | |
</dependency> | |
<dependency> | |
<groupId>org.projectlombok</groupId> | |
<artifactId>lombok</artifactId> | |
<version>${lombok.version}</version> | |
<scope>provided</scope> | |
</dependency> | |
<dependency> | |
<groupId>junit</groupId> | |
<artifactId>junit</artifactId> | |
<version>${junit.version}</version> | |
<scope>test</scope> | |
</dependency> | |
<dependency> | |
<groupId>commons-io</groupId> | |
<artifactId>commons-io</artifactId> | |
<version>${commons-io.version}</version> | |
<scope>test</scope> | |
</dependency> | |
</dependencies> | |
<properties> | |
<httpclient.version>4.3.6</httpclient.version> | |
<httpasyncclient.version>4.0.2</httpasyncclient.version> | |
<httpmime.version>4.3.6</httpmime.version> | |
<json.version>20140107</json.version> | |
<unirest-java.version>1.4.9</unirest-java.version> | |
<junit.version>4.11</junit.version> | |
<commons-io.version>2.4</commons-io.version> | |
<jackson-core.version>2.8.6</jackson-core.version> | |
<lombok.version>1.16.6</lombok.version> | |
</properties> | |
</project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package edu.sjsu.amigo.http.client; | |
import lombok.Data; | |
import java.util.Map; | |
/** | |
* Http response wrapper. | |
* | |
* @author rwatsh on 3/1/17. | |
*/ | |
@Data | |
public class Response<T> { | |
private int statusCode; | |
private String statusText; | |
private Map<String, String> headers; | |
private String rawBody; | |
private T parsedObject; | |
} |
No comments:
Post a Comment