英文:
WSO2 Enterprise Integrator iterate and aggregate, issue with aggregation
问题
我想在迭代中执行并行API调用,然后使用聚合中介器对响应进行分组。格式为JSON。我正在使用以下代码:
[...iterate中的代码]
<script language="js">var c = mc.getProperty("account");
print("Value : "+ c );
mc.setProperty("concatValue", c);
mc.setPayloadJSON({"result":{"account" : c}});</script>
<log>
<property expression="json-eval($)" name="JSON-Payload in sequence"/>
</log>
</sequence>
</target>
</iterate>
<property name="Aggregated_Responses" scope="default" value = "{}"/>
<aggregate id="it1">
<completeCondition>
<messageCount max="-1" min="-1"/>
</completeCondition>
<onComplete expression="json-eval($)" enclosingElementProperty="Aggregated_Responses">
<log>
<property expression="json-eval($)" name="JSON-Payload in oncomplete"/>
</log>
</onComplete>
</aggregate>
<loopback/>
</sequence>
聚合没有起作用,如果我在oncomplete中添加loopback,它将返回一个JSON,第二个JSON将在日志中打印一条消息,指示响应已发送。有人可以帮助我解决这个问题吗?
另外一个问题:在迭代中的工作通常是并行进行还是串行进行的?
(注意:这里只是提供了翻译好的代码部分,不包括问题的回答部分。)
英文:
I want to perform parallel API calls in iterate mediator then to group the responses using the aggregate mediator. The format is JSON. I am using this code:
[...code in iterate]
<script language="js">var c = mc.getProperty("account");
print("Value : "+ c );
mc.setProperty("concatValue", c);
mc.setPayloadJSON({"result":{"account" : c}});</script>
<log>
<property expression="json-eval($)" name="JSON-Payload in sequence"/>
</log>
</sequence>
</target>
</iterate>
<property name="Aggregated_Responses" scope="default" value = "{}"/>
<aggregate id="it1">
<completeCondition>
<messageCount max="-1" min="-1"/>
</completeCondition>
<onComplete expression="json-eval($)" enclosingElementProperty="Aggregated_Responses">
<log>
<property expression="json-eval($)" name="JSON-Payload in oncomplete"/>
</log>
</onComplete>
</aggregate>
<loopback/>
</sequence>
The aggregation is not working, if i add loopback isnide the on complete, it will return one json and the second one will print a message in the logs saying that the response was already sent. Can someone help me solve this issue?
And an additional question: do the work inside the iterate is usually done in parallel or in series?
答案1
得分: 0
如果您正在使用迭代中介器
,则在迭代流程中应该包含一个调用中介器
,该中介器执行外部调用。如果没有,您必须使用ForEach中介器
。
迭代示例
<?xml version="1.0" encoding="UTF-8"?>
<sequence name="iterate-aggregate-example" trace="disable" xmlns="http://ws.apache.org/ns/synapse">
<property description="countRequests" expression="count(//Account)"
name="countRequests" scope="default" type="STRING"/>
<iterate expression="//Account" id="IterateAccountCreate"
sequential="true">
<target>
<sequence>
<payloadFactory media-type="xml">
<format>
<echo:echoString xmlns_echo="http://echo.services.core.carbon.wso2.org">
<in xmlns="">$1</in>
</echo:echoString>
</format>
<args>
<arg evaluator="xml" expression="//Account/text()"/>
</args>
</payloadFactory>
<property action="remove" description="TRANSPORT_HEADERS"
name="TRANSPORT_HEADERS" scope="axis2"/>
<property description="OperationName" name="OperationName"
scope="default" type="STRING" value="echoString"/>
<header action="remove" name="To" scope="default"/>
<header name="Action" scope="default" value="urn:echoString"/>
<header name="SOAPAction" scope="transport" value="urn:echoString"/>
<log category="DEBUG" description="***Request***">
<property expression="$body" name="request"/>
</log>
<call>
<endpoint key="echo"/>
</call>
<log category="DEBUG" description="***Response***" separator="***Response***">
<property expression="$body" name="create_instanties_response"/>
</log>
</sequence>
</target>
</iterate>
<aggregate description="" id="IterateAccountCreate">
<completeCondition timeout="10">
<messageCount max="{get-property('countRequests')}" min="{get
property('countRequests')}"/>
</completeCondition>
<onComplete expression="//ns:echoStringResponse" xmlns_ns="http://echo.services.core.carbon.wso2.org">
<log description="***aggregated***" separator="***aggregated***">
<property expression="$body" name="aggregated_body"/> </log>
</onComplete>
</aggregate>
</sequence>
英文:
If you are using the Iterate Mediator
you should have a Call Mediator
within the iterate flow which does an external call. If not you have to use the Foreach Mediator
instead.
Iterate Example
<?xml version="1.0" encoding="UTF-8"?>
<sequence name="iterate-aggregate-example" trace="disable" xmlns="http://ws.apache.org/ns/synapse">
<property description="countRequests" expression="count(//Account)"
name="countRequests" scope="default" type="STRING"/>
<iterate expression="//Account" id="IterateAccountCreate"
sequential="true">
<target>
<sequence>
<payloadFactory media-type="xml">
<format>
<echo:echoString xmlns_echo="http://echo.services.core.carbon.wso2.org">
<in xmlns="">$1</in>
</echo:echoString>
</format>
<args>
<arg evaluator="xml" expression="//Account/text()"/>
</args>
</payloadFactory>
<property action="remove" description="TRANSPORT_HEADERS"
name="TRANSPORT_HEADERS" scope="axis2"/>
<property description="OperationName" name="OperationName"
scope="default" type="STRING" value="echoString"/>
<header action="remove" name="To" scope="default"/>
<header name="Action" scope="default" value="urn:echoString"/>
<header name="SOAPAction" scope="transport" value="urn:echoString"/>
<log category="DEBUG" description="***Request***">
<property expression="$body" name="request"/>
</log>
<call>
<endpoint key="echo"/>
</call>
<log category="DEBUG" description="***Response***" separator="***Response***">
<property expression="$body" name="create_instanties_response"/>
</log>
</sequence>
</target>
</iterate>
<aggregate description="" id="IterateAccountCreate">
<completeCondition timeout="10">
<messageCount max="{get-property('countRequests')}" min="{get
property('countRequests')}"/>
</completeCondition>
<onComplete expression="//ns:echoStringResponse" xmlns_ns="http://echo.services.core.carbon.wso2.org">
<log description="***aggregated***" separator="***aggregated***">
<property expression="$body" name="aggregated_body"/> </log>
</onComplete>
</aggregate>
</sequence>
答案2
得分: 0
最终的工作解决方案,附带一些解释:
<payloadFactory media-type="json">
<format>
{
"payloadss": [{
"account":"99999999999"
},{
"account":"6666666666"
}]
}
</format>
<args/>
</payloadFactory>
<iterate attachPath="json-eval($.payloadss)" expression="json-eval($.payloadss)"
id="iterate-over" preservePayload="true" continueParent="false">
<target>
<sequence>
<property expression="json-eval($.payloadss.account)" name="accounte" scope="default" type="STRING"/>
<call-template target="call_template_a">
<with-param name="url" value="/getaccount"/>
<with-param name="method_type" value="get"/>
</call-template>
[应用错误检查等...]
</sequence>
</target>
</iterate>
[使用与迭代相同的id,否则它将不起作用]
<property name="Aggregated_Responses" scope="default">
<jsonObject/>
</property>
<aggregate description="iterate-over" id="iterate-over">
<completeCondition timeout="120">
<messageCount max="-1" min="-1"/>
</completeCondition>
[使用类似这样的表达式,否则它将不起作用,如果需要,您甚至可以在末尾添加/您的字段名称]
<onComplete xmlns:ns="http://org.apache.synapse/xsd" expression="$body/*[1]"
enclosingElementProperty="Aggregated_Responses">
[在这里,JSON将作为有效载荷,您可以选择使用脚本中介器来映射值并更改其名称,否则您只需返回结果,它将被聚合在一起]
<property expression="json-eval($)" name="bbbb"/>
<script language="js"><![CDATA[
var dataFull = JSON.parse(mc.getProperty('bbbb'));
var responseList = [];
var newJson = JSON.parse("{}");
for (i = 0; i < dataFull.length; i++) {
item = dataFull[i];
newJson.newAccountNumber = item.accountNumber;
responseList.push(newJson);
}
mc.setProperty("responseList", JSON.stringify(responseList));
]]></script>
<payloadFactory media-type="json">
<format>
{
"data": $2
}
</format>
<args>
<arg evaluator="xml" expression="get-property('responseList')"/>
</args>
</payloadFactory>
[发送应该在此级别,之后的代码将不会被执行]
<send/>
</onComplete>
</aggregate>
</sequence>
希望这可以帮助您!如果您需要进一步的帮助,请随时告诉我。
英文:
Final working solution with some explanation:
<payloadFactory media-type="json">
<format>
{
"payloadss": [{
"account":"99999999999"
},{
"account":"6666666666"
}]
}
</format>
<args/>
</payloadFactory>
<iterate attachPath="json-eval($.payloadss)" expression="json-eval($.payloadss)"
id="iterate-over" preservePayload="true" continueParent="false">
<target>
<sequence>
<property expression="json-eval($.payloadss.account)" name="accounte" scope="default" type="STRING"/>
<call-template target="call_template_a">
<with-param name="url" value="/getaccount"/>
<with-param name="method_type" value="get"/>
</call-template>
[.. apply error check etc .. ]
</sequence>
</target>
</iterate>
[ use same id as the iterate otherwise it wont work ]
<property name="Aggregated_Responses" scope="default">
<jsonObject/>
</property>
<aggregate description="iterate-over" id="iterate-over">
<completeCondition timeout="120">
<messageCount max="-1" min="-1"/>
</completeCondition>
[ use expression like this otherwise it wont work, you can even add at the end /
your field name if needed ]
<onComplete xmlns:ns="http://org.apache.synapse/xsd" expression="$body/*[1]"
enclosingElementProperty="Aggregated_Responses">
[ here the json will be as payload, optionnally you can have a script mediator
to map the value and change in their names, otherwise you can just return the
result and it
will be aggregated together]
<property expression="json-eval($)" name="bbbb"/>
<script language="js"><![CDATA[
var dataFull = JSON.parse(mc.getProperty('bbbb'));
var responseList = [];
var newJson = JSON.parse("{}");
for (i = 0; i < dataFull.length; i++) {
item = dataFull[i];
newJson.newAccountNumber = item.accountNumber;
responseList.push(newJson);
}
mc.setProperty("responseList", JSON.stringify(responseList));
]]></script>
<payloadFactory media-type="json">
<format>
{
"data": $2
}
</format>
<args>
<arg evaluator="xml" expression="get-property('responseList')"/>
</args>
</payloadFactory>
[ the send should be at this level, the code just after will not be executed]
<send/>
</onComplete>
</aggregate>
</sequence>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论