Reputation: 2894
Sorry, I'm new to Play Framework.
I use it with Java API.
Let's say I want to have a controller action that runs some kind of import and displays result after import is finished.
Import requires expensive HTTP communication with the 3rd party service (fetching data from 3 URLs, processing data, updating database after all 3 resources were processed).
So I'd like to implement an import itself as a Promise in controller (Controller shouldn't be aware of import implementation).
Then I'd like to run fetching the data from URLs and processing in 3 parallel threads. I think it would be nice to implement it as a 3 separate Promises.
Database should be updated only when (and if) all three promises were completed successfully.
And finally controller should be notified after database was updated.
I'm able to implement the whole import as a Promise, but I don't know how to implement nested promises.
Could you suggest how to implement it or correct me if I'm trying to use wrong approach?
Upvotes: 3
Views: 3031
Reputation: 11479
You can achieve this with flatmap. The syntax in Java is sadly a bit clunky because of the anonymous interfaces (will get better with Java 8 and lambdas). Promise<T>.flatMap
accepts a Function<T, Promise<U>>
and will return a Promise<U>
. This means you can nest flatMaps from all your three operations and collect them with a flatmap, like this:
final Promise<String> promise1 = Promise.pure("one");
final Promise<String> promise2 = Promise.pure("two");
final Promise<String> promise3 = Promise.pure("three");
Promise<String> allThreeCombined = promise1.flatMap(new Function<String, Promise<String>>() {
@Override
public Promise<String> apply(final String result1) throws Throwable {
return promise2.flatMap(new Function<String, Promise<String>>() {
@Override
public Promise<String> apply(final String result2) throws Throwable {
return promise3.map(new Function<String, String>() {
@Override
public String apply(String result3) throws Throwable {
return result1 + result2 + result3;
}
});
}
});
}
});
If there is no special meaning to each of the different things you are fetching - for example if they are to be treated as a list of values you can also use Promise.sequence()
which accepts a list of Promise<T>
and return a Promise<List<T>>
so you can react on all values arriving.
Upvotes: 6