In iOS I can make an integration test like this
// Setup expecttation to prevent from test ending before all async tasks finish.
let expectation = expectationWithDescription("Sign in");
// call API method for signing in
PersonAPI.signIn("asdf#asdf.co", password: "Free Milk Lane", done:{(response: APIResponse)->Void in
// check response for errors
XCTAssertTrue(response.isSuccessful() == true, response.getMessage());
// mark async operation is completed
expectation.fulfill();
});
// wait until all async operations completed
waitForExpectationsWithTimeout(5.0, handler:nil);
But in Android its not so obvious. Right now I am trying to use Roboelectric & Retrofit but it just doesn't want to cooperate. I have tried lots of things and I think the issue is related to how the threads for are pooled. For example the following code will pass but waits 5 seconds no matter what, even though the API call may only take 1 second:
// Setup signal to prevent from test ending before all async tasks finish.
final CountDownLatch signal = new CountDownLatch(1);
// call API method for signing in
PersonAPI.signIn("asdf#asdf.co", "Free Milk Lane", new IAPICallback() {public void done(APIResponse response) {
// check response for errors
Assert.assertTrue(response.getMessage(), response.isSuccessful());
// mark async operation is completed
signal.countDown();
}});
// wait until all async operations completed
signal.await(5, TimeUnit.SECONDS);
At this point I'm willing to try anything (except mocking). Change out the retrofit, reoboelectric, whatever.
Thanks again
Here's how I made it work. I changed retrofit to do synchronous calls. Then I stored the response in a static variable and completed the assertions on the main thread.
public class PersonAPITest {
private static APIResponse _response = null;
#Test
public void testSignIn() {
// Setup signal to prevent from test ending before all async tasks finish.
final CountDownLatch signal = new CountDownLatch(1);
// call API method for signing in
PersonAPI.signIn("asdf#asdf.co", "Free Milk Lane", new IAPICallback() {public void done(APIResponse response) {
// check response for errors
PersonAPITest._response = response;
// mark async operation is completed
signal.countDown();
}});
// wait until all async operations completed
signal.await(5, TimeUnit.SECONDS);
Assert.assertTrue(PersonAPITest._response.getMessage(), PersonAPITest._response.isSuccessful());
}
}
An example of the retrofit code is below. Basically I just used native Java multi-threading to create the asynchronous method:
public static void getGoogle(final IAPICallback callback) {
new Thread(new Runnable() {
#Override
public void run() {
RestAdapter.Builder builder = new RestAdapter.Builder()
.setEndpoint("http://google.com")
.setClient(new OkClient(new OkHttpClient()));
RestAdapter adapter = builder.build();
ITaskAPI service = (ITaskAPI) adapter.create(ITaskAPI.class);
Response result = service.getGoogle();
APIResponse response;
if(result.getStatus() == 200) {
response = new APIResponse(true, "it worked!");
}else{
response = new APIResponse(false, "boo! bad dog!");
}
callback.done(response);
}
}).start();
}
Related
I have an application that makes dynamic requests by Retrofit and i want to detect if all have finished with the best practice like I know how to make in javascript with Promise.
In Retrofit today I'm doing like this, I receive an array from objects and i will make x request depending on the size of the array.
So when I start the function I pick the size from an array and every time my Retrofit makes a call I put in my variable successCounter++ and errorCounter++, when sum from this 2 variables is equal my array size, so this is the end of the asynchronous functions.
But I don't know if this is a good practice an example from my peace of code:
String filePath = system.getMp_user_name() + "/categorias/" + mpCategory.getImg();
downloadImage("category", filePath, mpCategory.getImg(),
new SynService.ApiImageCallback() {
public void onResponse(Boolean success, Integer requestCounter, Integer errorRequestCounter){
if(success){
categoryImgSuccessCounter++;
Log.d(TAG, "Imagem baixada e armazenada com sucesso");
if(categoryImgSuccessCounter.equals(arrayCategorySize)) {
HashMap<String, String> responseObj = new HashMap<>();
responseObj.put("success", "1");
responseObj.put("message", "Sincronização Completada com Sucesso");
callback.onResponse(responseObj);
}
} else {
categoryImgErrorCounter++;
Log.d(TAG, "Não foi possível fazer o download da imagem");
HashMap<String, String> responseObj = new HashMap<>();
responseObj.put("success", "0");
responseObj.put("message", "Houve um erro no download das imagens e o processo parou");
callback.onResponse(responseObj);
}
Integer total = categoryImgSuccessCounter + categoryImgErrorCounter;
if(total.equals(arrayCategorySize)) {
categoryImgFinished = true;
}
}
});
How can I detect when all the request from Retrofit is finished without a counter?
In javascript is just this:
async function foo(things) {
const results = [];
for (const thing of things) {
// Good: all asynchronous operations are immediately started.
results.push(bar(thing));
}
// Now that all the asynchronous operations are running, here we wait until they all complete.
return baz(await Promise.all(results));
}
Use the Interceptorof Retrofit to intercept each request and do the counter increment/decrement and shares the callback on the basis of that.
Interceptors are a powerful mechanism that can monitor, rewrite, and retry calls.
Interceptor - How to?
If it's okay to add one dependency then add RxJava and it has good number of operator which are useful for multithreading and it's callback.
To wait until all your requests will be done is to use Retrofit2 in conjunction with RxJava2with its zip function.
Zip combine the emissions of multiple Observables together via a specified function and emit single items for each combination based on the results of this function
Add RxJava2CallAdapterFactory as a Call adapter when building your Retrofit instance:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.example.com/")
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
Your service methods can now use any of the above types as their return type.
interface MyService {
#GET("/user")
Observable<User> getUser();
}
MyService retrofitApi = retrofit.create(MyService.class);
Use that service to create the collection of request and zip those requests.
// You need to use `Observable` type for the response.
List<Observable<?>> requests = new ArrayList<>();
// Make a collection of all requests
requests.add(retrofitApi.getUser());
requests.add(retrofitApi.getUser());
requests.add(retrofitApi.getUser());
// Zip all requests with the Function, which will receive the results.
Observable.zip(
requests,
new Function<Object[], Object>() {
#Override
public Object apply(Object[] objects) throws Exception {
// Objects[] is an array of combined results of completed requests
// do something with those results and emit new event
return new Object();
}
})
// After all requests had been performed the next observer will receive the Object, returned from Function
.subscribe(
// Will be triggered if all requests will end successfully (4xx and 5xx also are successful requests too)
new Consumer<Object>() {
#Override
public void accept(Object o) throws Exception {
//Do something on successful completion of all requests
}
},
// Will be triggered if any error during requests will happen
new Consumer<Throwable>() {
#Override
public void accept(Throwable e) throws Exception {
//Do something on error completion of requests
}
}
);
I need to send 4 http requests at same time and wait until all of them finished (i'm using volley)
I've tried to send them separately in 4 threads and use thread.join but it seems that onResponse and onError methods are running in main thread so the request threads finishes after call queue.add(jsonArrayRequest).
I can't use countdownlatch because as I know first it doesn't run threads at same time (it runs them in a queue) and second it blocks main thread.
what's your suggestion? let me know if there's better way to do this using Retrofit , OkHttp or other libraries.
To achieve it without using any patterns or other libraries, you can mark the request as finished if it responded, and call the method, in each of them, you want to execute if all the requests are finished. On that method, you just need to check if all the requests are done.
Example:
isRequest1Finished = false;
isRequest2Finished = false;
response1 = null;
response2 = null;
volleyRequest1(new Response.Listener<Something>() {
#Override
public void onResponse(Something response) {
isRequest1Finished = true;
response1 = response;
doSomething();
}
})
volleyRequest2(new Response.Listener<Something>() {
#Override
public void onResponse(Something response) {
isRequest2Finished = true;
response2 = response;
doSomething();
}
})
//....do on all of your requests
and in your doSomething() method:
void doSomething() {
if (isRequest1Finished && isRequest2Finished) {
// do something with the response1, response2, etc....
}
}
But my suggestion is using RxJava, where you can apply zip operator, in which it combines all of your asynchronous responses into one result:
Example:
Observable request1 = getRequest1();
Observable request2 = getRequest2();
Observable.zip(request1, request2,
new BiFunction<Something, Something, Pair<Something, Something>() {
#Override
public Pair<Something, Something> apply(Something response1, Something response2) {
return new Pair(response1, response2); // you can create a custom object to handle all of the responses
}
})
.map( // do something with your responses )
I am writing a Api that executes HTTP Request on a worker thread then call a method of a Callback-Handler when finish.
public class GriklyClient <E,T>{
private final IHttpRequest<E,T> request;
private final ResponseListener<T> response;
protected GriklyClient (IHttpRequest<E,T> request,ResponseListener<T> response)
{
this.request = request;
this.response = response;
}
/**
* Dispatch a thread to process
* HTTP Request.
*/
public void execute ()
{
Runnable thread = new Runnable()
{
public void run()
{
T result = (T) request.execute ();
response.response(result);
}
};
new Thread(thread).start();
}//end execute method
}
This is how a call to the ApI looks like:
Grikly grikly = new Grikly(developerKey);
grikly.addValidUserCredential(email,password);
grikly.fetchUser(1, new ResponseListener<User>() {
public void response(User result) {
// TODO Auto-generated method stub
System.out.println(result);
}
});
The problem I am having is Unit Testing. The Callback Handler is not being called in my Unit Test thus all my Test always pass even when they should fail.
private Grikly grikly = new Grikly (developerKey);
#Test
public void fetchUser ()
{
grikly.fetchUser(1, new ResponseListener<User>() {
public void response(User result) {
Assert.assertNotNull(result);
}
});
}//end fetchUser Test
How can I write a Unit test to test this Api?
Well, I guess your problem here is because your method fetchUser is an asynchonous method rather than a synchonous one which will not return until it have done its job.
So, the calling of grikly.fetchUser(... will return immediately(so does the test method fetchUser() w/o any sign of failure or success), while the 'lonely' thread you create in GriklyClient will keep running and finish its job by calling the callback method response in your new ResponseListener<User> and of course, nobody cares at that time.
IMO, either a CountdownLatch or a more general ReentrantLock with its Condition buddy can save your day. And tutorials talking about these two tools can be easily found using Google. Good luck with that.
EDIT:
On a second thought, if you wanna test the result that got passed to the callback method, it might be necessary to pass(or publish) it from the new thread you create to the test main thread(by save it to a lock guarded or volatile decorated field) and test it in the #Test annotated method, which in your case is the fetchUser().
I'm looking for an example of how to make an asynchronous request in Java using Thrift. Looking at the generated code this seems to be possible, but I can't find a single example of how.
Here is an example of generated code that suggest the existence of an Asynchronous interface:
...
AsyncIface {
public static class Factory implements org.apache.thrift.async.TAsyncClientFactory<AsyncClient> {
private org.apache.thrift.async.TAsyncClientManager clientManager;
private org.apache.thrift.protocol.TProtocolFactory protocolFactory;
public Factory(org.apache.thrift.async.TAsyncClientManager clientManager, org.apache.thrift.protocol.TProtocolFactory protocolFactory) {
this.clientManager = clientManager;
this.protocolFactory = protocolFactory;
}
public AsyncClient getAsyncClient(org.apache.thrift.transport.TNonblockingTransport transport) {
return new AsyncClient(protocolFactory, clientManager, transport);
}
}
...
Any pointer on how to use it?
Use the above interface to make the async call like this (The code mentions Cassandra but will easily generalize to your application):
TNonblockingTransport transport = new TNonblockingSocket("127.0.0.1", 9160);
TAsyncClientManager clientManager = new TAsyncClientManager();
TProtocolFactory protocolFactory = new TBinaryProtocol.Factory();
Cassandra.AsyncClient client = new Cassandra.AsyncClient(protocolFactory, clientManager, transport);
Cassandra.method_call(parameters, new Callback());
You haven't given any context, so I'll give you the basic parts you'll need:
To perform an asynchronous call, you'll need make it in a thread
To get the result, you'll need some kind of call back
The following represents a basic example of these elements in play:
final MyClient client; // Who will get a call back to the their sendResult() method when asynch call finished
ExecutorService executor = Executors.newSingleThreadExecutor(); // Handy way to run code in a thread
Runnable task = new Runnable() {
public void run() { // Where the "do the call" code sits
int result = someService.call(someParamter);
client.sendResult(result); // For example, expecting an int result
}
};
executor.submit(task); // This scheduled the runnable to be run
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 ?
}
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()).
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.
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();
}
}
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.
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