Apache HttpClient threading - java

I'm using Apache HttpClient 4.3.6 and I'm having a hard time with it in one particular instance.
Normally, all of my HttpPost calls are in a single main thread and happen serially. However, there's one instance where once a particular type of HttpPost happens, I need to start a side thread to monitor it. This side thread periodically tries to connect to the server to see if it's still up. If the connection to the server drops, I need to abort() the connection back in main so that it doesn't just get stuck until the timeout happens (I can legitimately have an operation where it's possible to take 45 minutes to complete).
I set up a PoolingHttpClientConnectionManager and a CloseableHttpClient at the beginning of main, and then I have a send method that main and the side thread both use to set up HttpPost objects that are local to the method. However, the client.execute(httpPost) local variable result from the side thread instance of the send method is somehow getting assigned to the local variable result in the main thread instance of the send method. They're getting crossed. I've searched around for the last few hours and I haven't found any solutions to this.
EDIT: Added example code. Had to obfuscated company stuff by changing various things to basic variables where classes would be used, so forgive some typos/whatever during that.
Class variables:
CloseableHttpClient client;
HttpPost longHttpPost;
boolean diePlz = false;
In main:
clientPool = new PoolingHttpClientConnectionManager();
clientPool.setMaxTotal(20);
clientPool.setDefaultMaxPerRoute(20);
client = HttpClients.custom().setConnectionManager(clientPool).build();
//Lots of logic here to set up things to be 'send()'ed
Send method:
private String send(String message, boolean longCall){
RequestConfig.Builder requestConfig = RequestConfig.custom();
requestConfig.setConnectTimeout(10000);
String url = "http://" + ip + ":" + port + "/connector";
HttpPost httpPost;
if(longCall){
httpPost = longHttpPost = new HttpPost(url);
} else {
httpPost = new HttpPost(url);
}
httpPost.setConfig(requestConfig.build());
httpPost.setHeader("Content-Type", "application/xml");
httpPost.setHeader("charset", "UTF-8");
httpPost.setEntity(getEntity(message)); //getEntity() is a local method that overrides AbstractHttpEntity
try {
if(longCall && !threadRunning){
diePlz = false;
ConnectionCheck watcher = new ConnectionCheck();
watcher.start();
}
//httpReponse is what seems to get crossed between invocations of send()
CloseableHttpResponse httpResponse = client.execute(longCall ? longHttpPost : httpPost);
//more stuff here to work with response
} catch (Exception e) {
LOG.error(e, e);
return null;
} finally {
if(longCall){
longHttpPost.releaseConnection();
} else {
httpPost.releaseConnection();
}
}
}
Nested thread class inside main class:
private class ConnectionCheck extends Thread implements Runnable, Serializable {
#Override
public void run(){
threadRunning = true;
try{Thread.sleep(5000);}catch(Exception e){LOG.error(e, e);}
boolean registerReturn = register(false); //this calls send()
if(registerReturn){
String response = checkStatus(); //this calls send()
if(response == null){ //if the connection we're watching drops...
if(longHttpPost != null){
longHttpPost.abort(); //...then kill it
}
} else {
while(response != null && !diePlz){
try {
Thread.sleep(5000);
} catch (Exception e){
LOG.error(e, e);
register(true);
threadRunning = false;
return;
}
response = checkStatus();
if(response == null){
if(longHttpPost != null){
longHttpPost.abort();
}
}
}
register(true); //this calls send()
threadRunning = false;
}
} else {
register(true); //this calls send()
threadRunning = false;
}
}
}

Related

Get result from php in android studio using simple runnable threads without any external libraries

So, I know this might seems like a repeated question, but bear with me for a moment. In Android Studio, instead of using any external libraries (i.e., no JSON, no Volley, no Retrofit, nothing external), I plan to use simple runnable threads. These will fetch data using PHP stored on the localhost through the IP address of the WiFi which my system is using.
I know how to send a PHP update (the actual update codes are in PHP script), it's done like this:
Runnable runnableToUpdateDb = new Runnable() {
#Override
public void run() {
Log.d("DEBUG","RUNNING RUNNABLE");
try {
URL url = new URL("http://192.168.43.242/myapi/php_name.php");
HttpURLConnection httpURLConnection = (HttpURLConnection)url.openConnection();
httpURLConnection.setRequestMethod("POST");
httpURLConnection.connect();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream()));
String response = bufferedReader.readLine();
Log.d("DEBUG", response);
httpURLConnection.disconnect();
}catch (Exception e){
Log.d("DEBUG",e.toString());
}
}
};
And then simply running the PHP using thread upon the press of the button by:
Thread threadToUpdateDb = new Thread(runnableToUpdateDb);
threadToUpdateDb.start();
Now, the problem is in setting up a TextView that shows the updated/new data from the database though a different PHP.
The id I've described for this TextView in the layout is:
android:id="#+id/getdata"
I need help for implementing it in MainActivity.
The output for PHP is in the form of:
<br>8<br>
Here's how you perform a HTTP GET to an URL using plain Android. In this case I choose an AsyncTask so it would run the request aside from the Main Thread:
private class TareaGetFromDB extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... params) {
String URL = params[0];
String response = null;
try {
// Create an HTTP client
HttpClient client = new DefaultHttpClient();
HttpGet post = new HttpGet(URL);
// Perform the request and check the status code
HttpResponse response = client.execute(post);
StatusLine statusLine = response.getStatusLine();
if(statusLine.getStatusCode() == 200) {
// code 200 equals HTTP OK
HttpEntity entity = response.getEntity();
InputStream content = entity.getContent();
try {
response = IOUtils.toString(content, "utf-8");
} catch (Exception ex) {
// TODO handle exception
}
}
} catch(Exception ex) {
// TODO handle exception
}
return response;
}
#Override
protected void onPostExecute(String response) {
TextView myTextView = findViewById(R.id.getdata);
myTextView.setText(response);
}
}
This AsyncTask takes a String (the URL) as argument and returns a String (the response).
So you'll need to call it like this:
new TareaGetFromDB().execute("http://url.to/get/data");
You may need additional work before setting the text to the TextView to remove the surronding <br>, or you can remove them from the server response

Apache HttpClient - Out Of Memory Issue

I have a processor that reads messages from Apache Kafka and sends the data to a REST Endpoint.
The server only has 4 cores and 4 GB ram, out of which a max of 2GB is allocated to the java process
Messages are produced and consumed at the rate of 4k/second.
After running couple of minutes, the program goes out of memory.
What is the best way to call http rest end-points asynchronously and not wait for response
How to manage the httpClient connection? I was under the impression that I need to start the client an never close it so I can reuse the connection
Do you see any issues with the below code
public class SomeProcesor implements BProcessor {
private ThreadPoolExecutor exec = (ThreadPoolExecutor) Executors.newFixedThreadPool(4);
private CompletionService<Boolean> pool = new ExecutorCompletionService<Boolean>(exec);
CloseableHttpAsyncClient httpclient = null ;
#Override
public void begin() {
httpclient = HttpAsyncClients.createDefault();
RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(5000).setConnectTimeout(5000).setSocketTimeout(5000).build();
HttpAsyncClients.custom().setDefaultRequestConfig(requestConfig).build();
// Start the client
httpclient.start();
}
#Override
public void process(MessageAndMetadata<?, ?> mMData, List<Map> events) {
List<Map<String, Object>> listMap = new ArrayList<>();
// loop and extract the data from events into the above List
//..
//..
// submit to seperate thread to post to HTTP
pool.submit(new HttpThread(listMap);
}
private class HttpThread implements Callable<Boolean> {
List<Map<String, Object>> listMap = null;
public HttpThread(List<Map<String, Object>> listMap) {
this.listMap = listMap;
}
#Override
public Boolean call() throws Exception {
return postToHttp(listMap);
}
}
private Boolean postToHttp(List<Map<String, Object>> listMap) throws UnsupportedEncodingException {
for (Map<String, Object> map : listMap) {
try {
HttpPost postRequest = new HttpPost("https://myserver:8080/services/collector");
postRequest.addHeader(HttpHeaders.ACCEPT, "application/json");
postRequest.addHeader(HttpHeaders.CONTENT_TYPE, "application/json");
postRequest.addHeader(HttpHeaders.CONNECTION, "keep-alive");
StringEntity input = new StringEntity(methodToConvertMapToJSON(map));
input.setContentType("application/json");
postRequest.setEntity(input);
httpclient.execute(postRequest, null);
} catch (Exception e) {
return false;
} catch (Throwable th) {
return false;
}
}
return true;
}
}
need consume the http response or release connection, otherwise the connection will consume resources.
change
httpclient.execute(postRequest, null);
to
HttpResponse response = httpclient.execute(postRequest, null).get();
if(response.getStatusLine().getStatusCode() != 200) {
// do something
}
// release the connection, better add to a finally clause
postRequest.releaseConnection();

variable returns null outside asynctask android

I have an asynctask which gets its data through php. The asynctask works fine, it passes the values to a global arraylist. However, when i try to call the variable on onCreate after .execute(), it returns a null size/value(s). I would like to know why this global variable returns a null when its supposed to have a value. Thanks in advance!
this is the code for asyntask:
private class get_pendingreq extends AsyncTask<String, Integer, String>
{
#Override
protected String doInBackground(String... arg0)
{
InputStream is = null;
String result = "";
try
{
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost(url+"pending_requests.php");
List<NameValuePair> parameter = new ArrayList<NameValuePair>();
parameter.add(new BasicNameValuePair("email", globalVariables.accountemail));
httppost.setEntity(new UrlEncodedFormEntity(parameter));
HttpResponse response = httpclient.execute(httppost);
HttpEntity entity = response.getEntity();
is = entity.getContent();
} catch (Exception e)
{
Log.e("log_tag", "Error in http connection " + e.toString());
}
try
{
BufferedReader reader = new BufferedReader(
new InputStreamReader(is, "iso-8859-1"), 8);
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null)
{
sb.append(line + "\n");
}
is.close();
result = sb.toString();
} catch (Exception e)
{
Log.e("log_tag", "Error converting result " + e.toString());
}
return result;
}
#Override
protected void onPostExecute(String result)
{
super.onPostExecute(result);
try
{
/* JSON parsing starts here */
JSONObject jArray = new JSONObject(result);
/*globalVariables.pendingdate = new ArrayList<String>();*/
JSONArray request = jArray.getJSONArray("request");
for (int i = 0; i < request.length(); i++)
{
JSONObject e = request.getJSONObject(i);
/* puts values to arraylist<String> */
globalVariables.pendingdate.add(e.getString("date"));
}
Log.d("striiing", globalVariables.pendingdate.toString());
} catch (JSONException e)
{
e.printStackTrace();
}
}
}
Main activity:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.calendar);
new get_pendingreq().execute();
System.out.print("alalala" + globalVariables.pendingdate.size());
}//this returns null
Global Variable:
public static ArrayList<String> pendingdate = new ArrayList<String>;
Because AsyncTask not finished. Put System.out.print("finish"); in onPostExcute() and see who is printed first.
The idea behind an AsyncTask is that it runs asynchronously from the main thread, thus on a background thread. That way it doesn't block the execution of any code on the main thread.
Knowing that, the following lines will execute right after each other:
new get_pendingreq().execute();
System.out.print("alalala" + globalVariables.pendingdate.size());
Your get_pendingreq class will not do any actual work until after a small delay, meaning that after calling the first lines in above snippet, nothing has really happened. You've only instructed the platform to start the async task somewhere in the near future.
Now, the globalVariables.pendingdate field you're accessing on the second line will not have any values until the async task finishes its work. That doesn't happen until onPostExecute() is executed. In other words: you're trying to print the values at the wrong moment in time.
Simply move that print to the end of the async task's onPostExectute() method (but obviously before the return - why's that even there at all?).
I highly recommend you have a read through the AsyncTask class documentation and the Processes and Threads article.
It is clear form the name indeed AsyncTask runs Asynchronously ...
Let me explain taking your code into consideration:
new get_pendingreq().execute();
This line will create a new thread for execution and it will run
asynchronously and so the next line(i.e.System.out.print("alalala" +
globalVariables.pendingdate.size());) gets executed immidiatly after this line without waiting the async task to get executed completly.so put this system.print line inside
the post execute method...
Are u sure, that globalVariables.pendingdate.add(e.getString("date")); realy have field "data" ?

Java Httpclient HttpRequestRetryHandler doesn't work. How to implement retrys?

I am trying to implement request retries after response isn't received.
I was reading about it in the Httpclient tutorial. the HttpRequestRetryHandler gets invoked only once and then it throw exception . what do I do wrong here?
updated
I added one if condition in the exception handling for SocketTimeoutException.
but what to do from there? how can I retry?
private void setRetry(int executionCount)
{
myRetryHandler = new HttpRequestRetryHandler() {
public boolean retryRequest(IOException exception,int executionCount,HttpContext context) {
if (executionCount >= 4) {
// Do not retry if over max retry count
System.out.println("retry count");
return false;
}
if (exception instanceof NoHttpResponseException) {
System.out.println("NoHttpResponseException exception");// Retry if the server dropped connection on us
return true;
}
if (exception instanceof SSLHandshakeException) {
// Do not retry on SSL handshake exception
System.out.println("SSLHandshakeException exception");
return false;
}
if (exception instanceof java.net.SocketTimeoutException) {
// Do not retry on SSL handshake exception
System.out.println("java.net.SocketTimeoutException exception");
return false;
}
HttpRequest request = (HttpRequest) context.getAttribute( ExecutionContext.HTTP_REQUEST);
boolean idempotent = !(request instanceof HttpEntityEnclosingRequest);
if (idempotent) {
System.out.println("idempotent exception");
// Retry if the request is considered idempotent
return true;
}
return false;
}
};
}
public String postHttpReqest(int retries,
int socketTimeoutMillis,
int isSSL,
String target,
String url,
String base_url,
int port,
LinkedHashMap<String, String> lHashMapParams) throws Exception
{
HttpParams httpParams = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(httpParams, 50000);
HttpConnectionParams.setSoTimeout(httpParams, socketTimeoutMillis);
defaulthttpclient = new DefaultHttpClient(httpParams);
setRetry(retries); // here i set the handler
defaulthttpclient.setHttpRequestRetryHandler(myRetryHandler);
String line = "";
List<BasicNameValuePair> params = new ArrayList<BasicNameValuePair>();
for (String key : lHashMapParams.keySet()) {
String val = lHashMapParams.get(key);
params.add(new BasicNameValuePair(key,val));
}
UrlEncodedFormEntity query = new UrlEncodedFormEntity(params);
HttpPost httppost = new HttpPost(url+":"+Integer.toString(port)+"//"+base_url);
httppost.setEntity(query);
HttpResponse response_ = defaulthttpclient.execute(httppost);
HttpEntity entity = response_.getEntity();
if (entity != null) {
line = EntityUtils.toString(entity);
System.out.println(line);
}
return line;
}
In the server, I set break point so it will hold the connection and will not return response.
The error I am getting in the Httpclient :
java.net.SocketTimeoutException: Read timed out
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(SocketInputStream.java:129)
at org.apache.http.impl.io.AbstractSessionInputBuffer.fillBuffer(AbstractSessionInputBuffer.java:149)
at org.apache.http.impl.io.SocketInputBuffer.fillBuffer(SocketInputBuffer.java:110)
at org.apache.http.impl.io.AbstractSessionInputBuffer.readLine(AbstractSessionInputBuffer.java:260)
at org.apache.http.impl.conn.LoggingSessionInputBuffer.readLine(LoggingSessionInputBuffer.java:115)
at org.apache.http.impl.conn.DefaultResponseParser.parseHead(DefaultResponseParser.java:98)
at org.apache.http.impl.io.AbstractMessageParser.parse(AbstractMessageParser.java:252)
at org.apache.http.impl.AbstractHttpClientConnection.receiveResponseHeader(AbstractHttpClientConnection.java:281)
at org.apache.http.impl.conn.DefaultClientConnection.receiveResponseHeader(DefaultClientConnection.java:247)
at org.apache.http.impl.conn.AbstractClientConnAdapter.receiveResponseHeader(AbstractClientConnAdapter.java:219)
at org.apache.http.protocol.HttpRequestExecutor.doReceiveResponse(HttpRequestExecutor.java:298)
at org.apache.http.protocol.HttpRequestExecutor.execute(HttpRequestExecutor.java:125)
at org.apache.http.impl.client.DefaultRequestDirector.tryExecute(DefaultRequestDirector.java:633)
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:454)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:820)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:754)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:732)
at com.fts.lb.connector.ut.HttpClientImpl.postHttpReqest(HttpClientImpl.java:183)
Um .. your RetryHandler is specifically returning false for a SocketTimeoutException.
So I would expect it to throw an Exception 100% of the time, which it is.
If you want the Request to be retried when the client times out before receiving a response, then you need to have your RetyrHandler return true for SocketTimeOutExceptions. You might also want to increase your SocketTimeOut before retrying.
Googlein a little bit I found this bug in the HttpClient 4.1 client (only on Windows).
For my problem I already use the latest 4.1.1, but maybe I have to implement the retryHandler.
I hope it will be helpful.

Set a Timeout to a Thread Class

Hy!!
I have a thread class and want to set a timeout inside after 10 sec.
How is this been made?
Class:
public class HttpConnection extends Thread{
List<NameValuePair> list;
String url;
Handler handler;
public HttpConnection(List<NameValuePair> params, String url, Handler handler) {
this.list = params;
this.url = url;
this.handler = handler;
}
#Override
public void run() {
try
{
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost(url);
String result;
BufferedReader in = null;
httppost.setEntity(new UrlEncodedFormEntity(this.list));
// Execute HTTP Post Request
HttpResponse response = httpclient.execute(httppost);
if(response != null){
in = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
StringBuffer sb = new StringBuffer("");
String line = "";
String NL = System.getProperty("line.separator");
while ((line = in.readLine()) != null) {
sb.append(line + NL);
}
in.close();
Message msg = Message.obtain();
if ((result = sb.toString()) != null)
{
msg.obj = result;
}
else
{
msg.obj = null;
throw new Exception("ERROR");
}
handler.sendMessage(msg);
}
}
catch (Exception e)
{
Log.e("XXX", e.getMessage());
}
super.run();
}
}
httpclient.getParams().setParameter("http.socket.timeout", 10000);//10 seconds
the httpconnection will timeout in 10 seconds, probably throwing some exception, in which case you can end your thread
In Java you should be able to use the ThreadPoolExecutor's awaitTermination method to set a timeout. Whichever class is creating and executing this thread should be able to call awaitTermination on the executor for 10 seconds. Is this what you are trying to do (set a timeout ON or WITHIN your thread)?
threadPoolExecutor.awaitTermination(10, TimeUnit.SECONDS);
i may not sure we can use thread handler for these kind of tasks,you better use Asynchronous task for this purpose because it depends up on internet strength availability,it may takes more time to get response from server, so go through developer.android.com for this topic.
super.run();
to
handler.postDelayed(this, 10000);
Hope it's help.

Categories

Resources