2011-12-14 45 views
8

有没有办法在控制器外部使用await()机制?异步WS调用并在控制器外部等待()

我不希望代码在控制器中进行异步调用,而是让服务类中的代码可以被多个控制器重用,但是无法在控制器之外调用await,因为方法受到保护。

因此,例如控制器:

ServiceClass service = new My ServiceClass(); 
    MyObject myObject= service.getMeAnObject(); 
    render(myObject); 

而服务类:

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); 
     } 
     ... 
    } 

有没有办法实现类似的东西?

感谢您的帮助。


编辑:我也跟着佩尔的建议和提出的服务类实现控制器,它的工作原理然而,这是必要的控制器使用它来增强。我发现完成的唯一方法是至少调用一次调用控制器类中的await方法()。

但是,我仍然没有证实代码实际上是暂停的。


编辑2:一个建议我从谷歌组得到的是,我确实应该尝试做的await控制器,所以也许一个更好的解决办法是为服务返回一个 承诺,并有控制器等待这个,但然后 有没有办法给我todo那里呢?

因此,例如控制器:

ServiceClass service = new My ServiceClass(); 
    Promise<MyObject> promise = service.getMeAnObject(); 
    MyObject myObject = await(promise); 
    render(myObject); 

而服务类:

public class ServiceClass 
    { 
    ... 
    public Promise<MyObject> getMeAnObject() 
    { 
     String url = "http://..."; 
     // Somehow Build a Promise<MyObject> 
    } 
    ... 
    } 

}

回答

3

到目前为止,除非在Play实例中管理单独的线程池时出现问题,否则这是我认为的最佳方法。

我已经在WSAsync.WSAsyncRequest 类中发挥了什么样的作用,这似乎工作。

实质上,await是在控制器内完成的,但服务类返回对象的Promise,我希望服务返回,这很好,因为我不知道该对象如何在控制器级别。

在控制器:

ServiceClass service = new My ServiceClass(); 
Promise<MyObject> promise = service.getMeAnObject(); 
MyObject myObject = await(promise); 
render(myObject); 

而服务类:

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); 
     } 
    } 
} 

因此,这似乎解决我的问题现在。

谢谢大家。

1

至于你提到等待是从控制器才能访问。

使服务类扩展控制器,在那里创建一些受保护的支持方法,并将其用作控制器的父类。

通过这种方式,您可以在控制器之间共享实现,同时访问所有控制器方法(等待,渲染等)。

+3

感谢您的回复。它似乎工作。然而,在我看来,这并不是最好的解决方案,因为服务等级在概念上并不是控制者。理想情况下,这种代码中断机制可以在任何地方使用。 –

1

这可能是为时已晚,以帮助你:)但办法做到这一点是通过使用Promise.onRedeem()方法来调用返回,并在控制器期待已久的新的承诺...

public Promise<Boolean> deauthorise() { 
    final Promise<Boolean> promise = new Promise<>(); 

    WS.url("https://connect.stripe.com/oauth/deauthorize") 
      .setParameter("client_secret", play.Play.configuration.getProperty("stripe.secretKey")) 
      .setParameter("client_id", play.Play.configuration.getProperty("stripe.clientId")) 
      .setParameter("stripe_user_id", this.stripeUserId) 
      .postAsync() 
      .onRedeem(new Action<Promise<HttpResponse>>() { 
       @Override 
       public void invoke(Promise<HttpResponse> result) { 
        HttpResponse response = result.getOrNull(); 
        promise.invoke(response != null && response.success()); 
       } 
      }); 
    return promise; 
}