WSO2 ESB:如何从嵌套迭代器聚合有效负载

时间:2015-12-28 10:17:40

标签: wso2 wso2esb synapse

我试图从Facebook页面产生评论流。最后,我喜欢WSO2的响应:

<comments>
    <comment>
       <post_id>123</post_id>
       <comment_id>456</comment_id>
       <from_name>Bob Brown</from_name>
       <from_id>789</from_id>
       <message>This is a comment on a post.</message>
       <created_time>2015-12-17T15:25:30+0000</created_time>
    </comment>
</comments>

我使用WSO2 ESB的API模块在Facebook页面上提供抽象层,以便在给定的时间戳之后获得页面上所有注释的简单流。

我现在正在处理的逻辑是获取给定Facebook页面上的所有帖子(使用WSO2 Facebook Connector),迭代所有帖子(使用迭代中介),检查帖子是否有评论(使用过滤器中介),如果有注释,则迭代注释并将它们重构为一个简单的XML元素(使用PayloadFactory中介)。这就是我被卡住的地方。

我已经发现在迭代介体中我无法更新迭代器外部的属性。我最初的本能是用第二个迭代器中生成的注释有效负载作为子元素来丰富外部属性,但没有骰子。

我现在正在尝试聚合第二个迭代器的输出,如下所示,但我无法聚合有效负载:

<?xml version="1.0" encoding="UTF-8"?>
<inSequence xmlns="http://ws.apache.org/ns/synapse">
    <property expression="$ctx:query.param.limit" name="limit"
        scope="default" type="STRING"/>
    <property expression="$ctx:query.param.since" name="since"
        scope="default" type="STRING"/>
    <property name="fields" scope="default" type="STRING" value="id,comments{id,message,from,created_time}"/>
    <call-template target="facebook_getFeed">
        <with-param name="pageId" value="{get-property('uri.var.page')}"/>
        <with-param name="maxPosts" value="{get-property('limit')}"/>
        <with-param name="since" value="{get-property('since')}"/>
        <with-param name="fields" value="{get-property('fields')}"/>
    </call-template>
    <log level="custom">
        <property name="S3_MESSAGE" value="Iterating through posts"/>
    </log>
    <property name="comment_stream" scope="default">
        <comments xmlns=""/>
    </property>
    <iterate continueParent="true" expression="//jsonObject/data"
        id="fb_api_comments_post_iterate" sequential="true" xmlns:ns1="http://cache.services">
        <target>
            <sequence>
                <filter xmlns:ns="http://org.apache.synapse/xsd" xpath="count(//data/comments)>0">
                    <then>
                        <property expression="//data/id"
                            name="fb_post_id" scope="operation" type="STRING"/>
                        <iterate continueParent="true"
                            expression="//data/comments/data"
                            id="fb_api_comments_comment_iterate" sequential="true">
                            <target>
                                <sequence>
                                    <log level="custom">
                                    <property name="S3_MESSAGE" value="Transforming comment"/>
                                    </log>
                                    <payloadFactory media-type="xml">
                                    <format>
                                    <comments xmlns="">
                                    <post_id>$1</post_id>
                                    <comment_id>$2</comment_id>
                                    <from_name>$3</from_name>
                                    <from_id>$4</from_id>
                                    <message>$5</message>
                                    <created_time>$6</created_time>
                                    </comments>
                                    </format>
                                    <args>
                                    <arg evaluator="xml" expression="get-property('fb_post_id')"/>
                                    <arg evaluator="xml" expression="//data/id"/>
                                    <arg evaluator="xml" expression="//data/from/name"/>
                                    <arg evaluator="xml" expression="//data/from/id"/>
                                    <arg evaluator="xml" expression="//data/message"/>
                                    <arg evaluator="xml" expression="//data/created_time"/>
                                    </args>
                                    </payloadFactory>
                                </sequence>
                            </target>
                        </iterate>
                    </then>
                </filter>
            </sequence>
        </target>
    </iterate>
    <aggregate>
        <correlateOn expression="fb_api_comments_comment_iterate"/>
        <completeCondition>
            <messageCount max="-1" min="-1"/>
        </completeCondition>
        <onComplete enclosingElementProperty="comment_stream" expression="//comments">
            <loopback/>
        </onComplete>
    </aggregate>
</inSequence>

非常感谢任何协助。

2 个答案:

答案 0 :(得分:1)

在你的问题中,你提到属性更新落在迭代介体之外。根据我的知识,这是因为这个原因。

在调用每个迭代周期之前,将克隆消息上下文,并且它仅在迭代器目标内的上下文中可用。因此,我们无法在迭代器内更新消息/属性,这些消息/属性位于默认/ synapse范围内。如果要存储全局内容,请将属性与operation scope一起使用。

如何解决这个问题,

  • 在迭代器之前 - 将属性分配给操作范围
  • 内部迭代器 - 进行修改
  • 在迭代器之外 - 将属性分配给默认范围(如果你 想把它带回默认范围)

使用以下结构作为代理服务的示例:

synchronized

答案 1 :(得分:0)

虽然我很高兴有人发布技术上更正确的答案,但由于时间的限制,我咬了一口子弹,不情愿地在脚本调解员中写了一些任意的JavaScript:

var payload = mc.getPayloadXML();
print("Starting FB Post Loop...");
var comments = new XML("<comments></comments>");
comments.comment = new XMLList();
for (var i = 0; i < payload[0].data.length(); i++){
  print("Checking if post has comments...");
  if(payload[0].data[i].comments.data.length() > 0){
    print("Comments exist on this post...");
    print("Post ID: " + payload[0].data[i].id);
    for (var ii = 0; ii < payload[0].data[i].comments.data.length(); ii++){
      print("Building comment entry...");
      var comment = <comment/>;
      comment.post_id      = payload[0].data[i].id.toString();
      comment.comment_id   = payload[0].data[i].comments.data[ii].id.toString();
      comment.from_id      = payload[0].data[i].comments.data[ii].from.id.toString();
      comment.from_name    = payload[0].data[i].comments.data[ii].from.name.toString();
      comment.message      = payload[0].data[i].comments.data[ii].message.toString();
      comment.created_time = payload[0].data[i].comments.data[ii].created_time.toString();
      print(comment);
      comments.comment += comment;
    }
  }
}
mc.setPayloadXML(comments);

恕我直言,不得不回归自定义代码是好的,但从可维护性的角度来看,往往意味着一个受伤的世界。硬币的另一面是我真的喜欢在可能的情况下利用WSO2 / Synapse调解器,因为使用WSO2 ESB是关于什么的!

期待阅读/讨论其他解决方案。