views:

70

answers:

2

I will be making multiple HTTP calls concurrently and want to allow the user to selectively cancel certain tasks if they take too long. A typical scenario: 1 task pulls twitter feed and another pulls facebook wall posts. The number of tasks is obviously variable, so the idea of a queue comes naturally. I've looked at ExecutorCompletionService but it's mostly used to wait for tasks to complete in a blocking fashion.

There's an ObjectiveC framework which seems to do what I want. Does anybody know of a simple framework that achieves my goals or do I have to write one for myself ?

+1  A: 

It looks like HttpClient will work for this. Note that the HttpUriRequest interface has an "abort()" method. Therefore, you can call abort on your HttpGet or whatever method you are using (post, etc).

joeslice
Have you used the abort() method before ?
Jacques René Mesrine
+1  A: 

The usual pattern of doing this is -

  • Create an interface that is implemented by classes which contain the logic to understand the API of different services like Twitter, Facebook etc. (say ISocialServiceAPI)
  • Create a class that implements Callable (say HttpTask) and pass in an object which implements ISocialServiceAPI
  • Create an ExecutorService to which you will submit tasks
  • Create a Collection of callables that you want to execute
  • Use the invokeAll method provided by the ExecutorService along with the time out you need. It returns a List of futures
  • Timed out tasks are cancelled by the ExecutorService. Catch the CancellationException and handle it

//Generate a list callables
List<HttpTask> httpTaskList= new ArrayList<HttpTask>();
httpTaskList.add(new TwitterAPIRequest());
httpTaskList.add(new FacebookAPIRequest());

List<Future<ApiResponse>> futures = null;
try {
    //Submit the list of callable objects
    futures = exec.invokeAll(httpTaskList,
      timeout, TimeUnit.SECONDS);
} catch (InterruptedException iex) {
    //Handle
}

if(null != futures) {
    finalResponse = new ArrayList<ApiResponse>( httpTaskList.size() );
    Iterator<HttpTask> httpTaskIter = httpTaskList.iterator();

    for (Future<ApiResponse> f : futures) {
     HttpTask httpTask = httpTaskIter.next();

     try {
      finalResponse.add( f.get() );
     } catch(InterruptedException iex) {
      //Handle
     } catch (ExecutionException eex) {
      finalResponse.add( httpTask.getFailureResponse() );
     } catch (CancellationException cex) {
      finalResponse.add( httpTask.getTimeoutResponse() );
     }
    }           

} else {            
    //Handle
}

If you have access to it, refer to Chapter 6 of Java Concurrency in Practice.

thejo
Remember to cancel() the task in a finally block, just to keep things tidy
skaffman
Not sure I understand. If invokeAll returns, each task that was added has either completed or been cancelled by the ExecutorService.
thejo