I have the following java code with try with resources:
public static CloseableHttpResponse getHttpResponse()
{
try (CloseableHttpClient client = HttpClientBuilder.create().build()) {
try (CloseableHttpResponse response = client.execute(request)) {
return response;
}
}
}
in another method will use the response returned by getHttpResponse:
public void test() {
CloseableHttpResponse response = getHttpResponse();
if (response) {
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode == HttpStatus.SC_OK) {
// do something
}
}
}
Looks like after CloseableHttpResponse response = getHttpResponse();, the client and response already closed, and I can not put this two methods into one, are there any ways that still use the try with resources in another method?
The best approach is the Execute Around idiom. Instead of getHttpResponse returning a CloseableHttpResponse pass in a lambda (typically) to be executed. The resource can then be closed in a try-with-resource statement cleanly.
/*** NICE ***/
// Function instead of Consumer would allow the method to return a value.
private void httpResponse(
Consumer<CloseableHttpResponse> op
) /* throws IOException */ {
try (CloseableHttpClient client = HttpClientBuilder.create().build()) {
try (CloseableHttpResponse response = client.execute(request)) {
if (response != null) { // Really?
op.accept(response);
}
}
}
}
Used as:
httpResponse(response -> {
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode == HttpStatus.SC_OK) {
// do something
}
});
The hacky alternative is to include a try statement within getHttpResponse that only closed in error conditions.
/*** HACKY ***/
private CloseableHttpResponse httpResponse() /* throws IOException */ {
boolean success = false;
CloseableHttpClient client = HttpClientBuilder.create().build();
try {
CloseableHttpResponse response = client.execute(request);
try {
success = true;
return response;
} finally {
if (!success) {
response.close();
}
}
} finally {
if (!success) {
client.close();
}
}
}
client will be closed as soon as the program leaves the scope of the try-with-resources. Can you try building the try with resources around the getHttpResponse method? For example:
public static CloseableHttpResponse getHttpResponse() {
try (CloseableHttpClient client = HttpClientBuilder.create().build()) {
CloseableHttpResponse response = client.execute(request)
return response;
}
}
And then you can rewrite your test method() like this:
public void test() {
try(CloseableHttpResponse response = getHttpResponse()) {
if (response) {
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode == HttpStatus.SC_OK) {
// do something
}
}
}
}
Related
I'm new to mockito and junit5. I'm trying to test the below function:
public boolean checkFunction(String element) {
CloseableHttpClient client = HttpClients.createDefault();
String uri = "any url im hitting";
HttpPost httpPost = new HttpPost(uri);
String json = element;
StringEntity entity;
try {
entity = new StringEntity(json);
httpPost.setEntity(entity);
httpPost.setHeader("Accept", "application/json");
httpPost.setHeader("Authorization", "any token");
CloseableHttpResponse response = client.execute(httpPost);
String responseBody = EntityUtils.toString(response.getEntity());
client.close();
if (responseBody.contains("any string i wanna check"))
return true;
} catch (Exception e) {
return false;
}
return false;
}
I tried the below code but I'm unable to get entire code coverage. Also I don't think this is the right approach.
#Test
public void testCheckFunction() throws Exception {
when(mockClass.checkFunction(Mockito.anyString())).thenReturn(false);
assertEquals(false, mockclass.checkFunction("dummy"));
}
Can anyone help me with this?
Thanks!
First you have to refactor your code for better testability:
public class Checker {
private final CloseableHttpClient client;
public Checker(CloseableHttpClient client) {
this.client = client;
}
public boolean checkFunction(String element) {
String uri = "http://example.com";
HttpPost httpPost = new HttpPost(uri);
String json = element;
StringEntity entity;
try {
entity = new StringEntity(json);
httpPost.setEntity(entity);
httpPost.setHeader("Accept", "application/json");
httpPost.setHeader("Authorization", "any token");
CloseableHttpResponse response = client.execute(httpPost);
String responseBody = EntityUtils.toString(response.getEntity());
client.close();
if (responseBody.contains("any string i wanna check"))
return true;
} catch (Exception e) {
return false;
}
return false;
}
}
Note that the dependency (i.e. the thing that has to be mocked in tests) is now injected via the constructor. This way it can easily be replaced by a mock when unit testing this class:
class CheckerTest {
private final CloseableHttpClient clientMock = Mockito.mock(CloseableHttpClient.class);
private final Checker checker = new Checker(clientMock);
#Test
public void testCheckFunction() throws Exception {
when(clientMock.execute(any(HttpPost.class))).thenThrow(new RuntimeException("Oops!"));
assertFalse(checker.checkFunction("dummy"));
}
}
I have a simple http client that passes every request to ExecutorService and applies them with a delay.
protected static final int RETRY_ATTEMPTS = 5;
private static final int GROUP_REQUEST_DELAY_MS = 55;
private static final ScheduledExecutorService REQUEST_FROM_USER_EXECUTOR =
Executors.newSingleThreadScheduledExecutor();
public RequestResponse post(String url) throws IOException {
HttpPost httpPost = new HttpPost(url);
HttpResponse httpResponse = call(httpPost);
return new RequestResponse(
httpResponse.getStatusLine().getStatusCode(),
EntityUtils.toString(httpResponse.getEntity()),
headers(httpResponse.getAllHeaders())
);
}
private HttpResponse call(HttpRequestBase request) throws IOException {
int attempts = 0;
HttpResponse httpResponse = null;
SocketException socketException = null;
do {
try {
httpResponse = client.execute(request);
} catch(SocketException e) {
socketException = e;
}
if(httpResponse != null)
break;
attempts++;
log.debug("Attempt: {}, SocEx: {}", attempts, socketException != null);
}while(attempts < RETRY_ATTEMPTS);
if(httpResponse == null)
// TODO
if(socketException != null) {
log.error("Network problem");
logRequest(request, httpResponse);
throw socketException;
}
return httpResponse;
}
public synchronized Future<RequestResponse> sendAsGroup(String url) {
return REQUEST_FROM_GROUP_EXECUTOR.schedule(() -> post(url), GROUP_REQUEST_DELAY_MS, TimeUnit.MILLISECONDS);
}
Sometimes the server throws an http 504 error or so. I want to process this error and resubmit this request. How can I do this correctly without exceeding the limit for server requests?
You should be using HttpRequestRetryHandler to recover from transport level (TCP) errors and ServiceUnavailableRetryStrategy to retry the request execution in case of a protocol level (HTTP) error.
I have a method named getResponse() in my program:
public ClosableHTTPResponse getResponse()
{
RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(120 * 1000).build();
CloseableHttpClient httpClient = null;
CloseableHttpResponse response = null;
try {
httpClient = HttpClientBuilder.create().setDefaultRequestConfig(requestConfig).build();
HttpGet httpPostRequest = new HttpGet(getURL);
httpPostRequest.addHeader("Authorization", "Token " + APIKey);
httpPostRequest.setHeader("Content-type", "application/json");
response = httpClient.execute(httpPostRequest);
String statusLine = response.getStatusLine().toString();
System.out.println("Status Line Response: " + statusLine);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (response != null) response.close();
if (httpClient != null) httpClient.close();
}
return response;
}
}
When I call this method from external method in the following code:
public void analzyeReponseA()
{
CloseableHttpResponse response = null;
try {
response = getResponse("p1", "p2");
String OKResponse = "HTTP/1.1 200 OK";
String statusLine = response.getStatusLine().toString();
if (statusLine.contains(OKResponse)) {
HttpEntity entity = response.getEntity();
// java.net.SocketException: Socket is closed exception thrown on next line..
String responseString = EntityUtils.toString(entity, "UTF-8");
System.out.println("Response String:\n" + responseString);
}
}
I'm getting a java.net.SocketException: Socket is closed exception
on this line:
String responseString = EntityUtils.toString(entity, "UTF-8");
Based on this and this thread, presumably this is happening bec I call if (response != null) response.close(); in getResponse() method (correct?)
If so, my question now is how do I return a CloseableHttpResponse without the program throwing above exception? Is the only option to call String responseString = EntityUtils.toString(entity, "UTF-8"); in getReponse() method and return a responseString instead of CloseableHttpResponse? What if I still want to access the response object in caller code (like to check status line or something else)?
If I understood the question correctly, I'd first look to see if the code really needed to return an HttpResponse. If the method(s) that call getResponse() all only need, e.g, the contents, then return the contents rather than the response.
Otherwise, you should be able to do, using the try-with-resources approach:
public void callingMethod() {
try (CloseableHttpResponse resp = getResponse();) {
{
// example
HttpEntity entity = resp.getEntity();
}
}
And remove the close from the getResponse() method.
Also, you do not want to be opening/closing the HttpClient on each invocation. That class is designed to be used multiple times. There is more information at You're Using HttpClient wrong and it is destabilizing your software. Thus, you may wish to refactor the code to move the HttpClient elsewhere.
I would like to grab the HTML code of a webpage, and display it in an edittext control, but i end up with this error:
1482-1491/android.process.acore E/StrictMode﹕ A resource was acquired
at attached stack trace but never released. See java.io.Closeable for
information on avoiding resource leaks.
This is my code:
class GetResult implements Runnable {
private volatile String bodyHtml;
#Override
public void run() {
try {
String myUri = "http://www.google.com";
HttpClient httpClient = new DefaultHttpClient();
HttpGet get = new HttpGet(myUri);
HttpResponse response = httpClient.execute(get);
bodyHtml = EntityUtils.toString(response.getEntity());
//return bodyHtml;
} catch (IOException e) {
bodyHtml = "kapot";
}
}
public String getbodyHtml(){
return bodyHtml;
}
}
and
String rs = "";
GetResult foo = new GetResult();
new Thread(foo).start();
rs = foo.getbodyHtml();
What am i doing wrong?
You need to close httpClient in a finally block. Like so:
public void run() {
HttpClient httpClient = null
try {
String myUri = "http://www.google.com";
httpClient = new DefaultHttpClient();
HttpGet get = new HttpGet(myUri);
HttpResponse response = httpClient.execute(get);
bodyHtml = EntityUtils.toString(response.getEntity());
//return bodyHtml;
} catch (IOException e) {
bodyHtml = "kapot";
} finally {
if (httpClient != null) {
httpClient.close();
}
}
}
I am extremely new to C# And windows app programming.
I am trying to create an AsyncTask, like in java , where i can query a url and get its response back.
Here is the code i usually use in java, i want to implement the copy in C sharp.
public interface ResponseCallback
{
void onSuccess(String response);
void onFailure(String exception);
}
public class MyAsyncTask extends AsyncTask<String, Void, String>
{
private ResponseCallback myResponse = null;
private int type = 0;//POST
List<NameValuePair> nameValuePairs = null;
StringEntity entity = null;
private HttpResponse response = null;
public MyAsyncTask(String url,ResponseCallback myResponse)
{
this.myResponse = myResponse;
this.execute(url);
}
#Override
protected String doInBackground(String... param)
{
String url = param[0];
response = null;
HttpClient httpclient = new DefaultHttpClient();
httpclient.getParams().setParameter("http.connection-manager.timeout", 15000);
try {
if (type == 0)
{
HttpPost httppost = new HttpPost(url);
if (nameValuePairs != null)
httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
if (entity != null)
httppost.setEntity(entity);
response = httpclient.execute(httppost);
}
else
{
HttpGet httppost = new HttpGet(url);
response = httpclient.execute(httppost);
}
} catch (ClientProtocolException es)
{
} catch (IOException e)
{
}
String resp = null;
if (response != null)
{
try {
resp = Utilities.convertStreamToString(response.getEntity().getContent());
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return resp;
}
else
return null;
}
#Override
protected void onPostExecute(String resp)
{
if (resp != null)
{
if (response.getStatusLine().getStatusCode() == Constants.RESULT_OK )
{
try {
myResponse.onSuccess(resp.trim());
} catch (IllegalStateException e) {
}
}
else
myResponse.onFailure(resp);
}
else
myResponse.onFailure(resp);
}
}
I have tried this in C #. Anyone wanna help me fix few things in this code and give me some info, what to do next
namespace The_Vow.Global
{
class MyAsyncTask
{
public ResponseCallback callback;
static void queryUrl(String url)
{
RunAsync(url).Wait();
}
static async Task RunAsync(String url)
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("MY_IP");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
// HTTP GET
HttpResponseMessage response = await client.GetAsync(url);
//response = await client.PostAsJsonAsync("api/products", gizmo);
if (response.IsSuccessStatusCode)
{
String jsonStr = await response.Content.ReadAsStringAsync();
// callback variable is not being recognized????
callback.onSuccess(jsonStr);
//Console.WriteLine("{0}\t${1}\t{2}", product.Name, product.Price, product.Category);
}
}
}
}
}
namespace The_Vow.Global
{
public interface ResponseCallback
{
void onSuccess(String response);
void onFailure(String exception);
}
}
Your callback field is an instance field, so you can't access it from a static method, unless you make the field static.
Another alternative I would like to recommend though, is not using a field at all. Pass the callback variable as a method argument.
Or you can stop using static methods at all, make them instance methods.