2011-12-14 4 views
8

Есть ли способ использовать механизм ожидания() вне контроллера?асинхронные вызовы WS и ждут() вне контроллера

Я не хочу, чтобы код выполнял асинхронный вызов в контроллере, но вместо этого имел этот код в классе службы, который может повторно использоваться несколькими контроллерами, однако невозможно вызвать вызов за пределами контроллера, поскольку метод защищен.

Так, например, в контроллере:

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

Есть ли способ, чтобы добиться чего-то подобного?

Благодарим за помощь.


Редактировать: Я последовал совету Pere и сделал класс обслуживания реализовать контроллер, он работает, однако, необходимо, чтобы контроллер с помощью его можно повысить. Единственный способ, по которому я узнал, что это сделать, - это хотя бы вызвать метод wait() в классе вызывающего контроллера.

Однако, я все еще не проверял, что код фактически приостановлен.


Edit 2: Одно предложение, которое я получил от группы Google является то, что я должен действительно попытаться сделать AWAIT в контроллере, так что может быть, лучшим решением было бы для службы, чтобы вернуть Пообещайте и попросите контролера подождать, но тогда нет способа, чтобы я сделал это?

Так, например, в контроллере:

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

До сих пор это лучший подход, который я нашел, я думаю, если не существует проблемы с управлением отдельными пулами потоков в экземпляре воспроизведения.

Я привел пример того, что играет в классе WSAsync.WSAsyncRequest , и это, похоже, сработает.

По существу, ожидание выполняется внутри контроллера, но класс службы возвращает обещание объекта, который я ожидал вернуть службе, что является прекрасным, потому что я не знаю подробностей о том, как этот объект был извлечен на уровня контроллера.

В контроллере:

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; 
} 
Смежные вопросы