I do not wish to have code making the asynchronous call in the
controller, but instead have that code in a service class that can be
reused by multiple controllers however, there is no way to call await
outside of a controller since that method is protected.
So for example in the controller:
ServiceClass service = new My ServiceClass();
MyObject myObject= service.getMeAnObject();
render(myObject);
And the service class:
public class ServiceClass
{
...
public MyObject getMeAnObject()
{
String url = "http://...";
Promise<HttpResponse> promise = url(url).getAsync();
// do something here similar to await in a controller
// that suspends the code waiting for the response
// to be retrieved
HttpResponse response = promise.get();
return buildMyObjectFromResponse(reponse);
}
...
}
Is there a way to achieve something like that?
Note that I also posted this question to stack overflow and a user
advised me to make my service class extend Controller. While I don't
like this solution since the service class is not conceptually a
controller I gave it a try and it works when I use it from one
Controller, but fails with the following exception when used from
another controller, in an apparently similar situation (the one that
works is an html page rendered, the failing one is an api call
returning json data, both calls the service class). The failure is:
Caused by: play.exceptions.ContinuationsException: Cannot use
await/continuations when not all application classes on the callstack
are properly enhanced. The following class is not enhanced:
controllers.api.PrivateAPI
at play.mvc.Controller.verifyContinuationsEnhancement(Controller.java:
1028)
at play.mvc.Controller.await(Controller.java:991)
...
I think the goal is really to be able to encapsulate the full "getting
the data" mechanism somewhere outside the controller without having to
worry about how it is retrieved (through WS or any other mechanism)
but still be able to prevent holding the other requests while that
data is being retrieved.
Thanks for any help you can provide.
- Dan
2011/12/16 Dan Serfaty <dser...@gmail.com>:
> --
> You received this message because you are subscribed to the Google Groups "play-framework" group.
> To post to this group, send email to play-fr...@googlegroups.com.
> To unsubscribe from this group, send email to play-framewor...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/play-framework?hl=en.
>
It is understandable that the await call is located in the controller
and maybe an better solution would be for the service to return a
Promise<MyObject> and have the controller wait for this but then
there's no way for me todo that is there?
So for example in the controller:
ServiceClass service = new My ServiceClass();
Promise<MyObject> promise = service.getMeAnObject();
MyObject myObject = await(promise);
render(myObject);
And the service class:
public class ServiceClass
{
...
public Promise<MyObject> getMeAnObject()
{
String url = "http://...";
// Somehow Build a Promise<MyObject>
}
...
}
Thanks,
- Dan
On Dec 16, 12:40 am, Morten Kjetland <morten.kjetl...@gmail.com>
wrote:
> Hi,
>
> Yann's sugestion should work.
>
> As long as you execute the await-method inside a controller it should work.
>
> This is why you cannot use await outside a controller:
>
> we have to enhance the java-code to enable continuations.. We only do this
> in controllers which explicit uses await.
>
> -Morten
>
>
>
>
>
>
>
> On Fri, Dec 16, 2011 at 9:34 AM, Yann Simon <yann.simon...@gmail.com> wrote:
> > Could you return your own Promise that uses the Promise<HttpResponse>
> > and make the await in the controller?
>
> > 2011/12/16 Dan Serfaty <dserf...@gmail.com>:
In the controller:
ServiceClass service = new My ServiceClass();
Promise<MyObject> promise = service.getMeAnObject();
MyObject myObject = await(promise);
render(myObject);
And the service class:
public class ServiceClass
{
public Promise<MyObject> getMeAnObject()
{
String url = "http://...";
return execute(WS.url(url).getAsync());
}
private Promise<MyObject> execute(final Promise<HttpResponse>
promise)
{
try
{
final Promise<MyObject> smartFuture = new Promise<MyObject>();
ScheduledThreadPoolExecutor executor =
MyAppThreadPools.getServiceThreadPool();
executor.submit(new Runnable()
{
@Override
public void run()
{
try
{
smartFuture.invoke(new MyObject(promise.get()));
}
catch (Throwable e)
{
smartFuture.invokeWithException(e);
}
}
});
return smartFuture;
}
catch (Exception e)
{
throw new RuntimeException(e);
}
}
}
Thanks all.
- Dan