I need to send multiple requests to many different web services and receive the results. The problem is that, if I send the requests one by one it takes so long as I need to sen
You can ask your jax-ws
implementation to generate asynchronous bindings for the web service.
This has two advantages that I can see:
jax-ws
will generate well-tested (and possibly fancier) code for you, you need not instantiate the ExecutorService yourself. So less work for you! (but also less control over the threading implementation details)get()
ting all response lists on the thread calling retrieveAllLists()
. It allows for per-service-call error handling and will process the results in parallel, which is nice if processing is non-trivial.An example for Metro can be found on the Metro site. Note the contents of the custom bindings file custom-client.xml :
true
When you specify this bindings file to wsimport
, it'll generate a client which returns an object that implements javax.xml.ws.ResponseResponse
extends the Future
interface that others also suggest you use when rolling your own implementation.
So, unsurprisingly, if you go without the callbacks, the code will look similar to the other answers:
public void retrieveAllLists() throws ExecutionException{
// first fire all requests
Response> students1 = ws1.getStudents();
Response> students2 = ws2.getStudents();
Response> students3 = ws3.getStudents();
Response> doctors1 = ws4.getDoctors();
Response> doctors2 = ws5.getDoctors();
Response> doctors3 = ws6.getDoctors();
Response> patients1 = ws7.getPatients();
Response> patients2 = ws8.getPatients();
Response> patients3 = ws9.getPatients();
// then await and collect all the responses
studentsResults.addAll(students1.get());
studentsResults.addAll(students2.get());
studentsResults.addAll(students3.get());
doctorsResults.addAll(doctors1.get());
doctorsResults.addAll(doctors2.get());
doctorsResults.addAll(doctors3.get());
patientsResults.addAll(patients1.get());
patientsResults.addAll(patients2.get());
patientsResults.addAll(patients3.get());
}
If you create callback handers such as
private class StudentsCallbackHandler
implements AsyncHandler>> {
public void handleResponse(List response) {
try {
studentsResults.addAll(response.get());
} catch (ExecutionException e) {
errors.add(new CustomError("Failed to retrieve Students.", e.getCause()));
} catch (InterruptedException e) {
log.error("Interrupted", e);
}
}
}
you can use them like this:
public void retrieveAllLists() {
List> responses = new ArrayList>();
// fire all requests, specifying callback handlers
responses.add(ws1.getStudents(new StudentsCallbackHandler()));
responses.add(ws2.getStudents(new StudentsCallbackHandler()));
responses.add(ws3.getStudents(new StudentsCallbackHandler()));
...
// await completion
for( Future> response: responses ) {
response.get();
}
// or do some other work, and poll response.isDone()
}
Note that the studentResults collection needs to be thread safe now, since results will get added concurrently!