Understanding Playframework Promises - Client to Server request spawning multiple requests

StackOverflow https://stackoverflow.com/questions/22673425

  •  22-06-2023
  •  | 
  •  

Frage

Trying out the play framework with Promises.

The goal is to expose an API to a user at localhost:9000/status

This call should go out to MyServer/v1/agents and retrieve an account list as Json.

["alpha", "beta"]

For each of these accounts, there is another api MyServer/v1/agents/<name>/status that will respond with a Status for a given account.

{"resultCode": 0, "resultDescription": "up"}

The end result for the user I'd like to present to the user should be something like:

{ "alpha": "false", "beta": "true" }

This is the code I tried out, but I am getting back an empty Json result being displayed. When I insert debug messages, I do eventually see the map get filled in with my accounts.

What is the proper way to do something like this in play? Should I be using Actors?

//This function sends out the request to get back the status for a given account  
 public static Promise<Boolean> isCampaignActive(String name) {
    Logger.debug("isCampaignActive:" + name);
    Promise<WS.Response> status = WS.url("http://MyServer/v1/agents/"+name+"/status").get();
    Promise<JsonNode> jsonResponse = status.map(Functions.responseToJson);
    Promise<Boolean> s = jsonResponse.map(new Function<JsonNode, Boolean>() {
       @Override
       public Boolean apply(JsonNode jsNode) {
           boolean asBoolean = jsNode.get("resultCode").asBoolean();
           return asBoolean;
       }
    });
    return s;
}



//This function is the API exposed to the client that should return the final result
public static Promise<Result> status() {
    Promise<WS.Response> accounts = WS.url("http://MyServer/v1/agents").get();
    Promise<JsonNode> responseJson = accounts.map(Functions.responseToJson);

    Promise<List<String>> accountList = responseJson.map(new F.Function<JsonNode, List<String>>() {

        @Override
        public List<String> apply(JsonNode jsonAccounts) throws Throwable {

            List<String> accountList = new ArrayList<String>();
            for(JsonNode accountName : jsonAccounts) {

                accountList.add(accountName.asText());
            }
            return accountList;
        }

    });

    Promise<Result> result = accountList.map(new F.Function<List<String>, Result>() {
        @Override
        public Result apply(List<String> list) throws Throwable {
            final Map<String, Boolean> tempMap = new HashMap<String, Boolean>();

            for (final String accountNamex : list) {
                Promise<Boolean> campaignActive = isCampaignActive(accountNamex);
                campaignActive.map(new F.Function<Boolean, Void>(){

                    @Override
                    public Void apply(Boolean status) throws Throwable {
                        tempMap.put(accountNamex, status);
                        return null;
                    }

                }
                );
            }


            Logger.debug(tempMap.toString());
            return ok(Json.toJson(tempMap));
        }});
    return result;

}
War es hilfreich?

Lösung

I think the problem in your code is mostly the last operation.

Side effecting from Functions run in map is not thread safe since they may return at any given moment and you do not want to synchronize as that will block the threads of the server. So you must never do things like what you do with tempMap.

The idea with promises/futures is instead to transform values until you reach a Promise. And since those operations never touch any mutable state outside of each Function<A, B> it is thread safe and can run concurrently.

To go from a List<Promise<Boolean>> to a Promise<List<Boolean>> take a look at Promise.sequence: http://www.playframework.com/documentation/2.2.0/api/java/play/libs/F.Promise.html

Then you can transform that Promise<List<Boolean>> to a Promise<Result> containing your json representation of those booleans.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top