了解Playframework承诺 - 客户端到服务器请求产生多个请求

时间:2014-03-26 21:26:52

标签: playframework playframework-2.0

使用Promises尝试播放框架。

目标是向用户公开API 本地主机:9000 /状态

此调用应发送至MyServer/v1/agents并检索帐户列表为Json。

["alpha", "beta"]

对于其中每个帐户,还有另一个api MyServer/v1/agents/<name>/status,它会回复给定帐户的状态。

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

我想向用户呈现的最终结果应该是:

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

这是我试过的代码,但是我回来显示一个空的Json结果。 当我插入调试消息时,我最终会看到地图已填入我的帐户。

在游戏中做这样的事情的正确方法是什么?我应该使用演员吗?

//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;

}

1 个答案:

答案 0 :(得分:2)

我认为代码中的问题主要是最后一次操作。

在map中运行的函数的副作用不是线程安全的,因为它们可能在任何给定时刻返回,并且您不希望同步,因为这将阻止服务器的线程。所以你绝不能做像tempMap那样的事情。

承诺/期货的想法是改变价值,直到你达到承诺。并且由于这些操作从不触及每个Function<A, B>之外的任何可变状态,因此它是线程安全的并且可以同时运行。

要从List<Promise<Boolean>>转到Promise<List<Boolean>>,请查看Promise.sequence:http://www.playframework.com/documentation/2.2.0/api/java/play/libs/F.Promise.html

然后,您可以将Promise<List<Boolean>>转换为包含这些布尔值的json表示的Promise<Result>