Skip to content

Commit

Permalink
Merge pull request #23 from gmaslowski/REMOVING_DRY_IN_HTTP_CLIENT
Browse files Browse the repository at this point in the history
Removing DRYs in JenkinsHttpClient.
  • Loading branch information
cosmin committed Jul 29, 2014
2 parents 2e65ff9 + 51a5148 commit 6551617
Show file tree
Hide file tree
Showing 3 changed files with 143 additions and 53 deletions.
94 changes: 41 additions & 53 deletions src/main/java/com/offbytwo/jenkins/client/JenkinsHttpClient.java
Expand Up @@ -8,22 +8,20 @@

import static org.apache.commons.lang.StringUtils.isNotBlank;

import com.offbytwo.jenkins.client.validator.HttpResponseValidator;
import com.offbytwo.jenkins.model.BaseModel;

import org.apache.http.HttpResponse;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.HttpClient;
import org.apache.http.client.HttpResponseException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.auth.BasicScheme;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.PoolingClientConnectionManager;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.util.EntityUtils;
import org.codehaus.jackson.map.DeserializationConfig;
Expand All @@ -35,27 +33,20 @@
import java.util.Scanner;

public class JenkinsHttpClient {

private URI uri;
private DefaultHttpClient client;
private BasicHttpContext localContext;
private HttpResponseValidator httpResponseValidator;

private ObjectMapper mapper;
private String context;

/**
* Create an unauthenticated Jenkins HTTP client
*
*
* @param uri Location of the jenkins server (ex. http://localhost:8080)
*/
public JenkinsHttpClient(URI uri) {
this(uri, new DefaultHttpClient());
}

/**
* Create an unauthenticated Jenkins HTTP client
*
* @param uri Location of the jenkins server (ex. http://localhost:8080)
* @param defaultHttpClient Configured DefaultHttpClient to be used
* @param defaultHttpClient Configured DefaultHttpClient to be used
*/
public JenkinsHttpClient(URI uri, DefaultHttpClient defaultHttpClient) {
this.context = uri.getPath();
Expand All @@ -65,12 +56,22 @@ public JenkinsHttpClient(URI uri, DefaultHttpClient defaultHttpClient) {
this.uri = uri;
this.mapper = getDefaultMapper();
this.client = defaultHttpClient;
this.httpResponseValidator = new HttpResponseValidator();
}

/**
* Create an unauthenticated Jenkins HTTP client
*
* @param uri Location of the jenkins server (ex. http://localhost:8080)
*/
public JenkinsHttpClient(URI uri) {
this(uri, new DefaultHttpClient());
}

/**
* Create an authenticated Jenkins HTTP client
*
* @param uri Location of the jenkins server (ex. http://localhost:8080)
*
* @param uri Location of the jenkins server (ex. http://localhost:8080)
* @param username Username to use when connecting
* @param password Password or auth token to use when connecting
*/
Expand All @@ -90,21 +91,18 @@ public JenkinsHttpClient(URI uri, String username, String password) {

/**
* Perform a GET request and parse the response to the given class
*
*
* @param path path to request, can be relative or absolute
* @param cls class of the response
* @param <T> type of the response
* @param cls class of the response
* @param <T> type of the response
* @return an instance of the supplied class
* @throws IOException, HttpResponseException
*/
public <T extends BaseModel> T get(String path, Class<T> cls) throws IOException {
HttpGet getMethod = new HttpGet(api(path));
HttpResponse response = client.execute(getMethod, localContext);
try {
int status = response.getStatusLine().getStatusCode();
if (status < 200 || status >= 300) {
throw new HttpResponseException(status, response.getStatusLine().getReasonPhrase());
}
httpResponseValidator.validateResponse(response);
return objectFromResponse(cls, response);
} finally {
EntityUtils.consume(response.getEntity());
Expand All @@ -114,7 +112,7 @@ public <T extends BaseModel> T get(String path, Class<T> cls) throws IOException

/**
* Perform a GET request and parse the response and return a simple string of the content
*
*
* @param path path to request, can be relative or absolute
* @return the entity text
* @throws IOException, HttpResponseException
Expand All @@ -123,10 +121,7 @@ public String get(String path) throws IOException {
HttpGet getMethod = new HttpGet(api(path));
HttpResponse response = client.execute(getMethod, localContext);
try {
int status = response.getStatusLine().getStatusCode();
if (status < 200 || status >= 300) {
throw new HttpResponseException(status, response.getStatusLine().getReasonPhrase());
}
httpResponseValidator.validateResponse(response);
Scanner s = new Scanner(response.getEntity().getContent());
s.useDelimiter("\\z");
StringBuffer sb = new StringBuffer();
Expand All @@ -138,10 +133,10 @@ public String get(String path) throws IOException {
releaseConnection(getMethod);
}
}

/**
* Perform a GET request and return the response as InputStream
*
*
* @param path path to request, can be relative or absolute
* @return the response stream
* @throws IOException, HttpResponseException
Expand All @@ -150,10 +145,7 @@ public InputStream getFile(URI path) throws IOException {
HttpGet getMethod = new HttpGet(path);
try {
HttpResponse response = client.execute(getMethod, localContext);
int status = response.getStatusLine().getStatusCode();
if (status < 200 || status >= 300) {
throw new HttpResponseException(status, response.getStatusLine().getReasonPhrase());
}
httpResponseValidator.validateResponse(response);
return response.getEntity().getContent();
} finally {
releaseConnection(getMethod);
Expand All @@ -162,12 +154,12 @@ public InputStream getFile(URI path) throws IOException {

/**
* Perform a POST request and parse the response to the given class
*
*
* @param path path to request, can be relative or absolute
* @param data data to post
* @param cls class of the response
* @param <R> type of the response
* @param <D> type of the data
* @param cls class of the response
* @param <R> type of the response
* @param <D> type of the data
* @return an instance of the supplied class
* @throws IOException, HttpResponseException
*/
Expand All @@ -178,13 +170,10 @@ public <R extends BaseModel, D> R post(String path, D data, Class<R> cls) throws
request.setEntity(stringEntity);
}
HttpResponse response = client.execute(request, localContext);
int status = response.getStatusLine().getStatusCode();


try {
if (status < 200 || status >= 300) {
throw new HttpResponseException(status, response.getStatusLine().getReasonPhrase());
}

httpResponseValidator.validateResponse(response);

if (cls != null) {
return objectFromResponse(cls, response);
} else {
Expand All @@ -197,8 +186,9 @@ public <R extends BaseModel, D> R post(String path, D data, Class<R> cls) throws
}

/**
* Perform a POST request of XML (instead of using json mapper) and return a string rendering of the response entity.
*
* Perform a POST request of XML (instead of using json mapper) and return a string rendering of the response
* entity.
*
* @param path path to request, can be relative or absolute
* @param xml_data data data to post
* @return A string containing the xml response (if present)
Expand All @@ -210,15 +200,12 @@ public String post_xml(String path, String xml_data) throws IOException {
request.setEntity(new StringEntity(xml_data, ContentType.APPLICATION_XML));
}
HttpResponse response = client.execute(request, localContext);
int status = response.getStatusLine().getStatusCode();
if (status < 200 || status >= 300) {
throw new HttpResponseException(status, response.getStatusLine().getReasonPhrase());
}
httpResponseValidator.validateResponse(response);
try {
InputStream content = response.getEntity().getContent();
Scanner s = new Scanner(content);
StringBuffer sb = new StringBuffer();
while(s.hasNext()) {
while (s.hasNext()) {
sb.append(s.next());
}
return sb.toString();
Expand All @@ -230,7 +217,7 @@ public String post_xml(String path, String xml_data) throws IOException {

/**
* Perform POST request that takes no parameters and returns no response
*
*
* @param path path to request
* @throws IOException, HttpResponseException
*/
Expand Down Expand Up @@ -271,7 +258,8 @@ private <T extends BaseModel> T objectFromResponse(Class<T> cls, HttpResponse re
private ObjectMapper getDefaultMapper() {
ObjectMapper mapper = new ObjectMapper();
DeserializationConfig deserializationConfig = mapper.getDeserializationConfig();
mapper.setDeserializationConfig(deserializationConfig.without(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES));
mapper.setDeserializationConfig(deserializationConfig
.without(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES));
return mapper;
}

Expand Down
@@ -0,0 +1,15 @@
package com.offbytwo.jenkins.client.validator;

import org.apache.http.HttpResponse;
import org.apache.http.client.HttpResponseException;

public class HttpResponseValidator {

public void validateResponse(HttpResponse response) throws HttpResponseException {
int status = response.getStatusLine().getStatusCode();
if (status < 200 || status >= 300) {
throw new HttpResponseException(status, response.getStatusLine().getReasonPhrase());
}
}

}
@@ -0,0 +1,87 @@
package com.offbytwo.jenkins.client.validator;

import static junit.framework.TestCase.assertFalse;
import static junit.framework.TestCase.assertTrue;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;

import org.apache.http.HttpResponse;
import org.apache.http.StatusLine;
import org.apache.http.client.HttpResponseException;
import org.junit.Test;

public class HttpRequestValidatorTest {

private boolean httpResponseExceptionThrown = false;
private HttpResponse httpResponse;

private HttpResponseValidator validator = new HttpResponseValidator();

@Test
public void shouldThrowHttpResponseExceptionWhenStatusIsLowerThan200() {
// given
httpResponse = givenResponseWithCode(170);

// when
httpResponseExceptionThrown = validateResponse(httpResponse);

// then
assertTrue(httpResponseExceptionThrown);
}

@Test
public void shouldThrowHttpResponseExceptionWhenStatusIsHigherThan300() {
// given
httpResponse = givenResponseWithCode(304);

// when
httpResponseExceptionThrown = validateResponse(httpResponse);

// then
assertTrue(httpResponseExceptionThrown);
}

@Test
public void shouldThrowHttpResponseExceptionWhenStatusIs300() {
// given
httpResponse = givenResponseWithCode(300);

// when
httpResponseExceptionThrown = validateResponse(httpResponse);

// then
assertTrue(httpResponseExceptionThrown);
}

@Test
public void shouldNotThrowHttpResponseExceptionWhenStatusIsBetween200and300() {
// given
httpResponse = givenResponseWithCode(220);

// when
httpResponseExceptionThrown = validateResponse(httpResponse);

// then
assertFalse(httpResponseExceptionThrown);
}

private HttpResponse givenResponseWithCode(Integer statusCode) {
HttpResponse httpResponse = mock(HttpResponse.class);
StatusLine statusLine = mock(StatusLine.class);

given(httpResponse.getStatusLine()).willReturn(statusLine);
given(statusLine.getStatusCode()).willReturn(statusCode);

return httpResponse;
}

private boolean validateResponse(HttpResponse httpResponse) {
boolean httpResponseExceptionThrown = false;
try {
validator.validateResponse(httpResponse);
} catch (HttpResponseException e) {
httpResponseExceptionThrown = true;
}
return httpResponseExceptionThrown;
}
}

0 comments on commit 6551617

Please sign in to comment.