Pergunta

I'm playing around with the Play Framework (v2.2.2), and I'm trying to figure out how to suspend an HTTP request. I'm trying to create a handshake between users, meaning, I want user A to be able to fire off a request and wait until user B "connects". Once the user B has connected, user A's request should return with some information (the info is irrelevant; let's just say some JSON for now).

In another app I've worked on, I use continuations to essentially suspend and replay an HTTP request, so I have something like this...

@Override
public JsonResponse doGet(HttpServletRequest request, HttpServletResponse response) {

  Continuation reqContinuation = ContinuationSupport.getContinuation(request);
  if (reqContinuation.isInitial()) {
    ...
    reqContinuation.addContinuationListener(new ContinuationListener() {
      public void onTimeout(Continuation c) {...}
      public void onComplete(Continuation c) {...}
    });
    ...
    reqContinuation.suspend();
    return null;
  }
  else {
    // check results and return JsonResponse with data
  }
}

... and at some point, user B will connect and the continuation will be resumed/completed in a different servlet. Now, I'm trying to figure out how to do this in Play. I've set up my route...

GET    /test        controllers.TestApp.test()

... and I have my Action...

public static Promise<Result> test() {

  Promise<JsonResponse> promise = Promise.promise(new Function0<JsonResponse>() {
      public JsonResponse apply() {
        // what do I do now...?
        // I need to wait for user B to connect
      }
  });

  return promise.map(new Function<JsonResponse, Result>() {
      public Result apply(JsonResponse json) {
        return ok(json);
      }
  });
}

I'm having a hard time understanding how to construct my Promise. Essentially, I need to tell user A "hey, you're waiting on user B, so here's a promise that user B will eventually connect to you, or else I'll let you know when you don't have to wait anymore".

How do I suspend the request such that I can return a promise of user B connecting? How do I wait for user B to connect?

Foi útil?

Solução

You need to create a Promise that can be redeemed later. Strangely, the Play/Java library (F.java) doesn't seem to expose this API, so you have to reach into the Scala Promise class.

Create a small Scala helper class for yourself, PromiseUtility.scala:

import scala.concurrent.Promise

object PromiseUtility {
  def newPromise[T]() = Promise[T]()
}

You can then do something like this in a controller (note, I don't fully understand your use case, so this is just a rough outline of how to use these Promises):

if (needToWaitForUserB()) {
  // Create an unredeemed Scala Promise
  scala.concurrent.Promise<Json> unredeemed = PromiseUtility.newPromise();

  // Store it somewhere so you can access it later, e.g. a ConcurrentMap keyed by userId
  storeUnredeemed(userId, unredeemed);

  // Wrap as an F.Promise and, when redeemed later on, convert to a Result
  return F.Promise.wrap(unredeemed.future()).map(new Function<Json, Result>() {
    @Override
    public Result apply(Json json) {
      return ok(json);
    }
  });
}

// [..]
// In some other part of the code where user B connects

scala.concurrent.Promise<Json> unredeemed = getUnredeemed(userId);
unredeemed.success(jsonDataForUserB);
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top