17

I read answers from similar Q&A

How do you create an asynchronous HTTP request in JAVA? | Asynchronous programming design pattern |
AsyncTask Android - Design Pattern and Return Values

I see a lot of solutions , but none really satifies me.

Listener way

Once the results are caught, the processing is implemented in onResult method.

public interface GeolocationListener {
public void onResult(Address[] addresses);
public void onError(Exception e);
}

This solution doesn't quite satify me , because I want to handle the results in the main method. I hate this interface because when the response is returned, it is processed in onResult resulting in chains of processing and no way to go back to the "main" method.

The servlet way

public class SignGuestbookServlet extends HttpServlet {

    public void doPost(HttpServletRequest req, HttpServletResponse resp)
                throws IOException {
        // ...
        resp.sendRedirect("/guestbook.jsp");
    }
}

There is no exposed Java code calling the servlet. All the configuration is done in the web.xml

The way I want

Wait for the response like this

Response a = getResponse();
// wait until the response is received, do not go further
// process
Response b = getResponse();
// wait until the response is received, do not go further
process(a,b);

Is there a design pattern to handle the async request and wait for the response like above ? Other way than the listener. Please no library or framework.

EDIT Thanks so far the responses. I didn't give you the full picture so I exposed the Geolocation class I started the implementation . I don't know how to implement the method . Can someone shows "how to" ? He (or she) must also implement the listener to retrieve the results

private Address getFullAddress (String text, AddressListener listener, ... ){

    // new Geolocation(text, listener, options).start() 
    // implements Geolocation.GeolocationListener   
    // how to return the Address from the onResult ?
}
Community
  • 1
  • 1
Raymond Chenon
  • 11,482
  • 15
  • 77
  • 110
  • What you ask in you edit is off-topic. And the tone is quite bossy. – toto2 Aug 03 '11 at 14:14
  • Sorry, I didn't intent to be bossy . Just provided more info on what the getResponse should return and implement the listener too . Your answer gives a new solution but is too short for me (not implemented with the listener) to mark it as the accepted answer . – Raymond Chenon Aug 03 '11 at 14:38
  • @raymondchenon Really, how to do something like this: private Address getFullAddress (String text, AddressListener listener, ... ){ --------- For another sample, when we using Volley library, when instancing JsonObjectRequest, it's have Overrides onResponse and onError. – Dr.jacky May 12 '15 at 04:54

5 Answers5

12

First, you should not reject the first two methods you discuss. There are very good reasons people are using those techniques and you should try to learn them instead of creating new ones.

Otherwise, you should look at java.util.concurrent:

ExecutorService es = Executors.newFixedThreadPool(2);
...
Future<Response> responseA = es.submit(responseGetter);
Future<Response> responseB = es.submit(responseGetter);

process(responseA.get(), responseB.get());

where responseGetter is of type Callable<Response> (you must implement the method public Response call()).

toto2
  • 5,306
  • 21
  • 24
10

Asynchronous code can always be made synchronous. The simplest/crudest way is to make the async call, then enter a while loop that just sleeps the current thread until the value comes back.

Edit: Code that turns an asynchronous callback into synchronous code--again, a crude implementation:

import java.util.concurrent.*;

public class MakeAsynchronousCodeSynchronous {
    public static void main(String[] args) throws Exception {
        final Listener listener = new Listener();
        Runnable delayedTask = new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    throw new IllegalStateException("Shouldn't be interrupted", e);
                }
                listener.onResult(123);

            }
        };
        System.out.println(System.currentTimeMillis() + ": Starting task");
        Executors.newSingleThreadExecutor().submit(delayedTask);
        System.out.println(System.currentTimeMillis() + ": Waiting for task to finish");
        while (!listener.isDone()) {
            Thread.sleep(100);
        }
        System.out.println(System.currentTimeMillis() + ": Task finished; result=" + listener.getResult());
    }

    private static class Listener {
        private Integer result;
        private boolean done;

        public void onResult(Integer result) {
            this.result = result;
            this.done = true;
        }

        public boolean isDone() {
            return done;
        }

        public Integer getResult() {
            return result;
        }
    }
}

You could also use a CountDownLatch as recommended by hakon's answer. It will do basically the same thing. I would also suggest you get familiar with the java.util.concurrent package for a better way to manage threads. Finally, just because you can do this doesn't make it a good idea. If you're working with a framework that's based on asynchronous callbacks, you're probably much better off learning how to use the framework effectively than trying to subvert it.

Ryan Stewart
  • 126,015
  • 21
  • 180
  • 199
6

Could CountDownLatch help you? In the main method, you call getResponse and then countDownLatch.await(). Pass a count down latch to the getResponse method and then count down once getResponse the result from getResponse is finished:

CountDownLatch latch = new CountDownLatch(1);
Response a = getResponse(latch);
latch.await();

latch = new CountDownLatch(1);
Response b = getResponse(latch);
latch.await();

process(a, b);

Your getResponse needs to call latch.countDown() once it's asynch parts return a result.

e.g.:

public Response getResponse(CountDownLatch latch) {
     someAsychBloc(final CountDownLatch latch) {
       do work
       latch.countDown();
    }
}
hakon
  • 354
  • 2
  • 5
1

Essentially you need a "listener" of sorts no matter what. This is because you do not know WHEN your return message will come back, if at all (that is one of the downsides of asynchronous processing...what to do if you do not get a return message).

So you either need to implement a listener that waits for events (ie, it is nudged by the returning message to be processed).

Or you could do a hybrid on that by having a separate thread that "polls" (or pulls) a response area on your service to see if the return message exists.

So it really comes down to whether you want more of a "pull" or "push" method of retrieving messages.

The SCA (Service Component Architecture) framework might be something to consider, but depending on what you are doing, it could be overkill too. But something to consider.

EDIT:

I just found this in the Java SE 6 Javadocs that may be helpful. The interface CompletionService which abstracts the very thing you care about --> asynchronous work. I suggest you take a look.

Chris Aldrich
  • 1,904
  • 1
  • 22
  • 37
0

If you want a page flow in a web application, you have to handle in the web way : storing some data either in the session, or cookies or hidden fields, etc.

The problem you're trying to tackle, as far as I understand it, doesn't come from asynchronousness but from the stateless http protocole.

Regards, Stéphane

Snicolas
  • 37,840
  • 15
  • 114
  • 173
  • Bonjour , I'm developing an Android app. The asynchronousness is for not ruinning UX on a long download. Nothing to do with stateless http protocol . Still I want to code the "get response" in synchronous way. – Raymond Chenon Aug 03 '11 at 12:40