java.util.concurrent Future & async()

1,730 views
Skip to first unread message

Eric Jain

unread,
Apr 2, 2012, 8:32:41 PM4/2/12
to play-framework
I have some code that returns a java.util.concurrent Future<String>.
What's the most straightforward way to build an AsyncResult from that?

btw it might be useful to show imports in the examples at [1], given
that there are several Promise classes floating around
(akka.dispatch.*, play.api.libs.concurrent.*, play.libs.F.*); not to
mention Callable...

[1] http://www.playframework.org/documentation/2.0/JavaAsync

Eric Jain

unread,
Apr 2, 2012, 11:30:08 PM4/2/12
to play-framework
Related question; what's the advantage of:

public static Result index() {
Promise<Integer> promiseOfInt = Akka.future(
new Callable<Integer>() {
public Integer call() {
intensiveComputation();
}
}
);
return async(
promiseOfInt.map(
new Function<Integer,Result>() {
public Result apply(Integer i) {
return ok("Got result: " + i);
}
}
)
);
}


over:

public static Result index() {
return async(Akka.future(new Callable<Result>() {
public Result call() {
return ok("Got result: " + intensiveComputation());
}
});
}

P.S. the documentation has 'async' instead of 'return async'--I assume
that's a typo?

Derek Williams

unread,
Apr 2, 2012, 11:44:22 PM4/2/12
to play-fr...@googlegroups.com
On Mon, Apr 2, 2012 at 9:30 PM, Eric Jain <eric...@gmail.com> wrote:
Related question; what's the advantage of:
...

Your version doesn't make a good example of how to map a Future created somewhere else :)

If the example code was actual production code, then your version would be more efficient.

-- 
Derek Williams

Eric Jain

unread,
Apr 3, 2012, 12:10:33 AM4/3/12
to play-fr...@googlegroups.com
On Mon, Apr 2, 2012 at 20:44, Derek Williams <de...@fyrie.net> wrote:
> Your version doesn't make a good example of how to map a Future created
> somewhere else :)
>
> If the example code was actual production code, then your version would be
> more efficient.

I was wondering if there was a good reason to have two separate
promises, because the documentation states that "to create a
Promise<Result> we need another promise first".

So the correct answer is that there is no reason to create a
Promise<Integer> in this case; it's just done to show how to use
Promise.map, which is equivalent to:

public static Result index() {
final Promise<Integer> promiseOfInt = ...


return async(Akka.future(new Callable<Result>() {
public Result call() {

return ok("Got result: " + promiseOfInt.get());
}
});
}

Correct?

Also, I'm still looking for the best way to make use of a
java.util.concurrent.Future. Is there any reason to wrap it in a
Promise<Integer> (how?) that is then mapped to a Promise<Result>,
rather than simply doing the following?

public static Result index() {
final Future<Integer> intFuture = ...


return async(Akka.future(new Callable<Result>() {
public Result call() {

return ok("Got result: " + intFuture.get());
}
});
}

Derek Williams

unread,
Apr 3, 2012, 12:33:39 AM4/3/12
to play-fr...@googlegroups.com
On Mon, Apr 2, 2012 at 10:10 PM, Eric Jain <eric...@gmail.com> wrote:
So the correct answer is that there is no reason to create a
Promise<Integer> in this case; it's just done to show how to use
Promise.map, which is equivalent to:

public static Result index() {
 final Promise<Integer> promiseOfInt = ...
 return async(Akka.future(new Callable<Result>() {
  public Result call() {
    return ok("Got result: " + promiseOfInt.get());
  }
 });
}

Correct?

Kind of, as this version of it will block a thread, whereas the two versions you originally posted wont.

In a more typical situation, you will have some service that will return a Promise<Integer>, and you need to use that to create your response, which is where using 'map' is the best way to go. It can be hard to express that in a simple example.
 
Also, I'm still looking for the best way to make use of a
java.util.concurrent.Future. Is there any reason to wrap it in a
Promise<Integer> (how?) that is then mapped to a Promise<Result>,
rather than simply doing the following?

That's a tough one. If the Future is actually one of Netty's ListenableFuture or something equivalent then it is easy, but if all you have is a plain j.u.c.Future the best you can do to create a non blocking solution is to take the j.u.c.Future and a Promise, and give them to some thread running a polling loop that will complete the Promise with the result of the Future when it is done. This would probably only be worthwhile if you have a large amount of Futures that you need to wait for.

If the j.u.c.Future interface supported some kind of callback method there would be a whole lot less reasons to have all these different (and incompatible) Promise/Future implementations. At least there would be a common interface they all could implement.

--
Derek Williams

Eric Jain

unread,
Apr 3, 2012, 1:09:12 AM4/3/12
to play-fr...@googlegroups.com
On Mon, Apr 2, 2012 at 21:33, Derek Williams <de...@fyrie.net> wrote:
> Kind of, as this version of it will block a thread, whereas the two versions
> you originally posted wont.

It hadn't occurred to me that the goal here isn't just to avoid
blocking on the request handling thread, but to avoid blocking any
thread. Seen in that light, this now makes sense :-)


> That's a tough one. If the Future is actually one of Netty's

> ListenableFuture or something equivalent then it is easy [...]

Some of the Future instances I'm dealing with happen to have an
addListener() method. But how do I adapt those Futures to a Promise?

Derek Williams

unread,
Apr 3, 2012, 2:09:54 AM4/3/12
to play-fr...@googlegroups.com
I got my libraries mixed up, ListenableFuture was from async-http-client, and it's ChannelFuture that is in Netty, sorry about that.

An example of how to do that in Scala is in WS:


Class names change of course depending on what library you are using. If you still need help with it, let me know what library you are using and I can see if I can whip up a Scala example (or a really bad Java example) of how to do it.
 
--
Derek Williams

Eric Jain

unread,
Apr 3, 2012, 2:48:50 AM4/3/12
to play-fr...@googlegroups.com
On Mon, Apr 2, 2012 at 23:09, Derek Williams <de...@fyrie.net> wrote:
> An example of how to do that in Scala is in WS:
>
> https://github.com/playframework/Play20/blob/master/framework/src/play/src/main/scala/play/api/libs/ws/WS.scala#L114
>
> Class names change of course depending on what library you are using. If you
> still need help with it, let me know what library you are using and I can
> see if I can whip up a Scala example (or a really bad Java example) of how
> to do it.

The code looks like so:

client.prepare().addListener(new ActionListener<String>() {
@Override
public void onResponse(String id) {

}

@Override
public void onFailure(Throwable t) {

}
});

Problem #1: The only way I can find to create a Promise using Play's
Java API is via Akka.future(callable).

Derek Williams

unread,
Apr 3, 2012, 9:34:09 AM4/3/12
to play-fr...@googlegroups.com
On Tue, Apr 3, 2012 at 12:48 AM, Eric Jain <eric...@gmail.com> wrote:
The code looks like so:

client.prepare().addListener(new ActionListener<String>() {
 @Override
 public void onResponse(String id) {

 }

 @Override
 public void onFailure(Throwable t) {

 }
});

Problem #1: The only way I can find to create a Promise using Play's
Java API is via Akka.future(callable).

I'm much more familiar with Akka's api then Play's, so I'll use that directly for this example:

import akka.dispatch.Promise

val akkaPromise = Promise[String]()

client.prepare().addListener(new ActionListener[String] {
  def onResponse(id: String) {
    akkaPromise.success(id)
  }

  def onFailure(t: Throwable) {
    akkaPromise.failure(t)
  }
}

import play.libs.Akka

// convert to Play Promise
val playPromise = Akka.asPromise(promise)

--
Derek Williams

Eric Jain

unread,
Apr 3, 2012, 1:34:27 PM4/3/12
to play-fr...@googlegroups.com
On Tue, Apr 3, 2012 at 06:34, Derek Williams <de...@fyrie.net> wrote:
> I'm much more familiar with Akka's api then Play's, so I'll use that
> directly for this example:
>
> import akka.dispatch.Promise
>
> val akkaPromise = Promise[String]()

Thanks; here's how I got it to work:

final Promise<String> promise = new
DefaultPromise<String>(Akka.system().dispatcher());

Reply all
Reply to author
Forward
0 new messages