2011-12-14 33 views
8

Có cách nào để sử dụng cơ chế await() bên ngoài bộ điều khiển không?Các cuộc gọi WS không đồng bộ và chờ() bên ngoài bộ điều khiển

Tôi không muốn mã thực hiện cuộc gọi không đồng bộ trong bộ điều khiển, nhưng thay vào đó có mã trong lớp dịch vụ có thể được nhiều bộ điều khiển sử dụng lại, không có cách nào để gọi bên ngoài bộ điều khiển phương pháp được bảo vệ.

Vì vậy, ví dụ như trong bộ điều khiển:

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

Và các lớp dịch vụ:

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

Có cách nào để đạt được một cái gì đó như thế?

Cảm ơn sự giúp đỡ của bạn.


Sửa: Tôi làm theo lời khuyên của Pere và làm cho lớp dịch vụ thực hiện điều khiển, nó hoạt động tuy nhiên, nó là cần thiết rằng bộ điều khiển sử dụng nó được nâng cao. Cách duy nhất tôi phát hiện ra để làm điều đó được thực hiện ít nhất là gọi một phương thức await() trong lớp điều khiển gọi.

Tuy nhiên, tôi vẫn chưa xác minh rằng mã thực sự bị tạm ngưng.


Chỉnh sửa 2: Một gợi ý tôi nhận được từ nhóm google là tôi thực sự nên cố gắng và làm như đang chờ đợi trong bộ điều khiển, như vậy có lẽ là một giải pháp tốt hơn sẽ được sử dụng dịch vụ phải trả lại một Hứa hẹn và yêu cầu bộ điều khiển chờ điều này nhưng sau đó không có cách nào để tôi làm điều đó?

Vì vậy, ví dụ như trong bộ điều khiển:

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

Và các lớp dịch vụ:

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

}

Trả lời

3

Cho đến nay, đây là cách tiếp cận tốt nhất tôi đã tìm thấy tôi nghĩ, trừ khi có vấn đề với việc quản lý các nhóm luồng riêng biệt trong cá thể Phát.

Tôi đã lấy ví dụ về những gì Play thực hiện trong lớp WSAsync.WSAsyncRequest và điều này dường như hoạt động.Về bản chất, sự chờ đợi được thực hiện trong bộ điều khiển, nhưng lớp dịch vụ trả về một lời hứa của đối tượng mà tôi mong đợi dịch vụ trả về, điều này là tốt vì tôi không biết chi tiết về cách đối tượng đó được lấy ra tại mức điều khiển.

Trong bộ điều khiển:

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

Và các lớp dịch vụ:

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

Vì vậy, điều này dường như để giải quyết vấn đề của tôi bây giờ.

Cảm ơn tất cả.

1

Như bạn nói chờ chỉ truy cập từ một Controller.

Làm cho lớp Dịch vụ mở rộng Bộ điều khiển, tạo một số phương thức hỗ trợ được bảo vệ trong đó và sử dụng nó làm lớp cha cho Bộ điều khiển.

Bằng cách đó bạn có thể chia sẻ việc triển khai trên bộ điều khiển, trong khi có quyền truy cập vào tất cả các phương thức điều khiển (đang chờ, kết xuất, v.v ...).

+3

Cảm ơn bạn đã trả lời. Nó dường như hoạt động. Tuy nhiên, nó không thực sự là giải pháp tốt nhất theo ý kiến ​​của tôi, vì lớp dịch vụ không phải là một bộ điều khiển khái niệm. Lý tưởng nhất, cơ chế gián đoạn mã này sẽ có sẵn từ mọi nơi. –

1

Đây có lẽ là quá muộn để giúp bạn :) nhưng cách để làm điều đó là sử dụng phương pháp Promise.onRedeem() để gọi một lời hứa mới được trả về và chờ đợi trong bộ điều khiển ...

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; 
} 
Các vấn đề liên quan