WSO2 api context growing too big - api

I have a situation where my api file sizes keeps growing as I keep adding more and more switch mediator cases... what's the best way to split and organize them in wso2. Below is a sample example of one of the files...
The problem is the cases are growing, and the file size is becoming too large.
Sometimes one of the 'CASE' can be like 100 lines! Here in the example, I'm obfuscating by using (...) of course.
I would appreciate any help. Ideally there is a way how we can chunk this into smaller file sizes. It's surprisingly hard to find after googling. I'm pretty sure I'm not the first person to run into this.
Also you can see here that function fixDate(given_time) is being repeated in this file, what's the best way to include this function once and use it throughout the file.
Thanks for any insights!
The file is \synapse-config\api\Applications.xml ... and it's growing in size...
<?xml version="1.0" encoding="UTF-8"?>
<api context="/applications" name="Applications" xmlns="http://ws.apache.org/ns/synapse">
<resource methods="GET">
<inSequence>
<property name="DISABLE_CHUNKING" scope="axis2" type="STRING" value="true"/>
....
...
...
<property expression="$url:page" name="uri.var.page" scope="default" type="STRING"/>
<script language="js"><![CDATA[
...
></script>
<payloadFactory description="PayloadFactory" media-type="json">
<format>
$1
</format>
<args>
<arg evaluator="xml" expression="get-property('uri.var.ats_credentials')"/>
</args>
</payloadFactory>
<property expression="json-eval($.auth_code)" name="uri.var.auth_code" scope="default" type="STRING"/>
<log level="full">
</log>
<switch source="get-property('uri.var.ats_type')">
<case regex="CASE 1">
<payloadFactory media-type="json">
<format>{
"filters": [
{
"name": "applicantworkflow.updateddate",
"value": [
"$1"
],
"secondaryValue": [
"$2"
]
},
{
"name":
"applicantworkflow.id",
"value": [
"$3"
],
"operator": ">"
}
]
.......
<case regex="CASE 2">
<script language="js"><![CDATA[function fixDate(given_time) {
......
<case regex="CASE 3">
<script language="js"><![CDATA[function fixDate(given_time) {
......
<case regex="CASE 4">
<script language="js"><![CDATA[function fixDate(given_time) {
......
//FILE SIZE KEEPS GROWING..... with different cases......
<default>
<log description="Fault Log" level="custom">
<property expression="fn:concat('Invalid ATS - ', get-property('uri.var.ats_type'))" name="message"/>
</log>
<payloadFactory media-type="json">
<format>{
"Error": "Invalid ATS"
}
</format>
<args/>
</payloadFactory>
<respond description="Respond"/>
</default>
</switch>
</inSequence>
<outSequence>
<send/>
</outSequence>
<faultSequence>
<send/>
</faultSequence>
</resource>
<handlers>
<handler class="com.tti.security.OpenSourceAuthHandler"/>
</handlers>
</api>

The easiest solution for this is to use separate sequences. Create a separate sequence for each case (or at least the ones that are getting really big). And from the switch mediator call the sequences using the sequence mediator.
First save the sequence in a sequence file that you add to your project:
<sequence name="case1_sequence" xmlns="http://ws.apache.org/ns/synapse">
<case regex="CASE 1">
<payloadFactory media-type="json">
<format>{
"filters": [
{
"name": "applicantworkflow.updateddate",
"value": [
"$1"
],
"secondaryValue": [
"$2"
]
},
{
"name":
"applicantworkflow.id",
"value": [
"$3"
],
"operator": ">"
}
]
..
</sequence>
Then use the sequence mediator inside your switch statement to call the sequences.
<switch source="get-property('uri.var.ats_type')">
<case regex="CASE 1">
<sequence key="case1_sequence"/>
</case>
..
</switch>

Related

OnComplete in Aggregate sequence not triggered after the Iteration sequence

I'm building a microservice where I have a main sequence that first reads a json file and then goes into iteration sequence that is connected to an aggregator sequence with an ID. Here is the order from the main sequence:
<property expression="json-eval($)" name="ORIGINAL_PAYLOAD" scope="default" type="STRING"/>
<sequence key="data-iterate-seq"/>
<property name="aggregatedResponses" scope="default">
<batch_response/>
</property>
<sequence key="data-aggregate-seq"/>
The problem I'm facing is that once it goes into iterate it first triggers the code in aggregate that is outside of OnComplete, then it goes back and does the iterations and never goes to the OnComplete neither it goes back to the main sequence. I managed to make it continue with the main sequence using continueParent=true but this way it never goes into OnComplete of the aggregation sequence. I have also tried switching the onComplete expression to $body/*[1] and //jsonObject but it didn't work Edit: neither did the <send/> and <loopback/> operators.
Here is my iterator
<?xml version="1.0" encoding="UTF-8"?>
<sequence name="data-iterate-seq" trace="disable" xmlns="http://ws.apache.org/ns/synapse">
<iterate attachPath="json-eval($)" expression="json-eval($.records)" id="requestIterator" preservePayload="true">
<target>
<sequence>
<payloadFactory media-type="json">
<format>$1</format>
<args>
<arg evaluator="json" expression="$"/>
</args>
</payloadFactory>
<property name="messageType" scope="axis2" type="STRING" value="application/json"/>
<log level="custom" separator="
">
<property expression="json-eval($)" name="BODY_INSIDE_ITERATE"/>
</log>
<!-- Prepare Payload -->
<property expression="json-eval($.recordId)" name="recordId" scope="default" type="STRING"/>
<property name="entitySetName" scope="default" type="STRING" value="accounts"/>
<property expression="concat(get-property('msdynamics365.resource'),'/api/data/',get-property('msdynamics365.api.version'),'/')" name="patch-url" scope="axis2" type="STRING"/>
<payloadFactory media-type="json">
<format>{"batch_response": "{ "relativeUrlTemplate": "{{apiUrl}}{{entitySetName}}{{entityRecordId}}",
"method": "PATCH",
"entitySetName": "$1",
"entityRecordId": "$2",
"data": {
"name":"$3",
"email":"$4"
}
}}
</format>
<args>
<arg evaluator="xml" expression="$ctx:entitySetName"/>
<arg evaluator="xml" expression="$ctx:recordId"/>
<arg evaluator="json" expression="$.data.name"/>
<arg evaluator="json" expression="$.data.emailaddress1"/>
</args>
</payloadFactory>
<property name="messageType" scope="axis2" type="STRING" value="application/json"/>
<log level="full"/>
<log level="custom" separator="
">
<property name="Results" value="Number of iterations"/>
</log>
</sequence>
</target>
</iterate>
</sequence>
and my aggregator:
<?xml version="1.0" encoding="UTF-8"?>
<sequence name="data-aggregate-seq" onError="data-fault-seq" trace="disable" xmlns="http://ws.apache.org/ns/synapse">
<aggregate id="requestIterator">
<completeCondition>
<messageCount max="-1" min="-1"/>
</completeCondition>
<onComplete aggregateElementType="root" enclosingElementProperty="aggregatedResponses" expression="json-eval($)" xmlns:ns="http://org.apache.synapse/xsd">
<property expression="json-eval($)" name="aggregatedResponses" scope="default" type="STRING"/>
<log level="full">
<property expression="json-eval($)" name="OUT_SEQUENCE_AGGREGATED_RESPONSE"/>
</log>
<log level="full">
<property expression="get-property('aggregatedResponses')" name="Responses"/>
</log>
</onComplete>
</aggregate>
<log level="custom">
<property expression="json-eval($)" name="FINAL_PAYLOAD"/>
<property expression="get-property('aggregatedResponses')" name="aggregated_Response"/>
</log>
</sequence>
Any suggestions on what I'm doing wrong or anything that might help would be really appreciated!
Thank you in advance!!
According to the documentation, you need to use a call or send mediator inside the Iterate mediator to continue the message flow.
In Iterate you need to send the split messages to an endpoint to
continue the message flow.
For me, it seems you are only transforming the message payload. Hence you can use Foreach mediator to do that without Iterate mediator.

Filter data from JSON by checking condition with two properties - WSO2 ESB

Below is the JSON file:
{
"_id": "rezbase_v3",
"_rev": "3-096e751caeeda12a8c30e28075a95e97",
"exchangerate_data": [
{
"buyingrate": 0.274725274725275,
"sellingrate": 0.274725274725275,
"buyingrateinverse": 3.64,
"sellingrateinverse": 3.64,
"basecurrency": {
"currencyCode": "USD",
"currencyName": "US dollar"
},
"quotecurrency": {
"currencyCode": "QAR",
"currencyName": "Qatari riyal"
},
"updateddate": 1491182700431,
"basecurrencyname": "US dollar",
"quotecurrencyname": "Qatari riyal"
},
{
"buyingrate": 0.00681384573453257,
"sellingrate": 0.00681384573453257,
"buyingrateinverse": 146.76,
"sellingrateinverse": 146.76,
"basecurrency": {
"currencyCode": "USD",
"currencyName": "US dollar"
},
"quotecurrency": {
"currencyCode": "LKR",
"currencyName": "Sri Lankan rupee"
},
"updateddate": 1491182700431,
"basecurrencyname": "US dollar",
"quotecurrencyname": "Sri Lankan rupee"
}
]
}
And from the file I need to filter buyingrate where basecurrency/currencycode is USD and quotecurrency/currencycode is LKR.
I have tried below expression:
<property description="quote1" expression="//jsonObject/exchangerate_data[basecurrency/currencyCode='USD' and quotecurrency/currencyCode='LKR']/buyingrate/text()" name="quote1" scope="default" type="STRING"/>
And I could be able to get the buyingrate.
But when I make the values as properties and tried to get the buyingrate, It is logging the exact expression insstead of the value.
<property description="basecurrency" name="basecurrency" scope="default" type="STRING" value="USD"/>
<property description="quotecurrency" name="quotecurrency" scope="default" type="STRING" value="LKR"/>
<property name="apos" scope="default" type="STRING" value="'"/>
<property description="exchangeratePath" expression="fn:concat(get-property('exchangeratePath'),'//jsonObject/exchangerate_data[basecurrency/currencyCode=',get-property('apos'),get-property('basecurrency'),get-property('apos'),' and quotecurrency/currencyCode=',get-property('apos'),get-property('quotecurrency'),get-property('apos'),']/buyingrate/text()')" name="exchangeratePath" scope="default" type="STRING"/>
<log level="custom">
<property expression="get-property('exchangeratePath')" name="exchangeratePath"/>
</log>
Logged value:
[2018-04-27 08:50:41,314] INFO - LogMediator exchangeratePath = //jsonObject/exchangerate_data[basecurrency/currencyCode='USD' and quotecurrency/currencyCode='LKR']/buyingrate/text()
I have checked tried the way mentioned in this answer.
This is resolved by:
<property description="exchangeratePath" expression="fn:concat(get-property('exchangeratePath'),'//jsonObject/exchangerate_data[basecurrency/currencyCode=',get-property('apos'),get-property('basecurrency'),get-property('apos'),' and quotecurrency/currencyCode=',get-property('apos'),get-property('quotecurrency'),get-property('apos'),']/buyingrate/text()')" name="exchangeratePath" scope="default" type="STRING"/>
<property description="exchangeRate" expression="evaluate($ctx:exchangeratePath)" name="exchangeRate" scope="default" type="STRING"/>

how to send response as String using class mediator in wso2 esb

In my project I created some proxy.There transport type is tcp.
My response is
{
"BillingSystem": {
"request_id": "20114140080000011479122000",
"request_timestamp": "12102012121200",
"response_timestamp": "12102012121300",
"action": "AddSubscription",
"username": "Cellcard ",
"result_code": "0",
"result_desc": "Success"
}
}
I catch this response using class mediator and create WZ2OCS2:1:14:14008:1:#1479122000# using that response. I need to send this string to tcp client. I set this String in the class meditor
context.setProperty("responseClientValue", responseClientValue);
After set this value in class mediator I used payload factory mediator and after that property mediator.
<payloadFactory description="" media-type="xml">
<format>
<name xmlns="">$1</name>
</format>
<args>
<arg evaluator="xml" expression="get-property('responseClientValue')"/>
</args>
</payloadFactory>
property mediator
<property name="messageType" scope="axis2" type="STRING" value="application/text"/>
When I run project Its show xml code
<?xml version='1.0' encoding='UTF-8'?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"><soapenv:Body><name>WZ2OCS2:1:14:14008:1:#1479122000#</name></soapenv:Body></soapenv:Envelope>?
Here is my proxy service
<?xml version="1.0" encoding="UTF-8"?>
<proxy name="SurepayBillingErrorHandlingProxy" startOnLoad="true" transports="tcp" xmlns="http://ws.apache.org/ns/synapse">
<target>
<inSequence>
<class description="" name="esb.cellcard.billing.SurepayMediator"/>
<property name="messageType" scope="axis2" type="STRING" value="application/json"/>
<send>
<endpoint key="SurpayBillingEP"/>
</send>
</inSequence>
<outSequence>
<class name="esb.cellcard.billing.ResponseRequestId"/>
<payloadFactory description="" media-type="xml">
<format>
<name xmlns="">$1</name>
</format>
<args>
<arg evaluator="xml" expression="get-property('responseClientValue')"/>
</args>
</payloadFactory>
<property name="messageType" scope="axis2" type="STRING" value="application/text"/>
<send/>
</outSequence>
<faultSequence/>
</target>
<parameter name="transport.tcp.responseClient">true</parameter>
<parameter name="transport.tcp.inputType">string</parameter>
<parameter name="transport.tcp.recordDelimiter">?</parameter>
<parameter name="transport.tcp.contentType">text/plain</parameter>
<parameter name="transport.tcp.port">6050</parameter>
<parameter name="transport.tcp.recordDelimiterType">character</parameter>
</proxy>
How can I get only string value. Thank you
Change your payloadFactory like this :
<payloadFactory>
<format>
<text xmlns="http://ws.apache.org/commons/ns/payload">$1</text>
</format>
<args>
<arg evaluator="xml" expression="$ctx:responseClientValue"/>
</payloadFactory>
Change property messageType like this :
<property name="messageType" scope="axis2" type="STRING" value="text/plain"/>
(see axis2.xml, by default, the PlainTextFormatter class is associated with text/plain : <messageFormatter contentType="text/plain" class="org.apache.axis2.format.PlainTextFormatter"/>)

How to map field values while converting message JSON<->SOAP

I need to map values of several fields while message is sending from one system to another. For example receive SOAP message with status "START" and produce JSON message with status "BEGIN".
Is it possible to do this with WSO2 ESB (or with some help from other WSO2 products)?
You can use the PayloadFactory and Switch mediator.
A simple example:
<switch source="//status">
<case regex="START">
<property name="status" scope="default" type="STRING" value="BEGIN"/>
</case>
<default>
<property expression="//status" name="status" scope="default" type="STRING"/>
</default>
</switch>
<payloadFactory media-type="json">
<format>
{"status": $1}
</format>
<args>
<arg expression="get-property('status')"/>
</args>
</payloadFactory>
I hope this helps.

[WSO2 ESB][4.9.0] NPE on iterate when sending back

Newbie on WSO2 ESB, we start using it as our central point as ESB but we are facing a real issue by doing a simple case :/
Here is the api I wrote (based on that simple) to show you my issue even if our usecase is different.
Users
<?xml version="1.0" encoding="UTF-8" ?>
<api context="/services/users" name="ListUsersAPI" xmlns="http://ws.apache.org/ns/synapse">
<resource methods="GET" protocol="http" url-mapping="/*">
<inSequence>
<payloadFactory media-type="json">
<format>{ "persons":{ "person":[ { "Id":"1", "givenName":"ajith", "lastName":"vitharana", "age":"25", "contactInfos":[ { "InfoId":"1", "department":"1", "contactType":"email", "value":"ajith#abc.org" }, { "InfoId":"2", "department":"1", "contactType":"mobile",
"value":"111111111" }, { "InfoId":"3", "department":"1", "contactType":"home", "value":"Magic Dr,USA" } ] }, { "Id":"2", "givenName":"shammi", "lastName":"jagasingha", "age":"30", "contactInfos":[ { "InfoId":"1", "department":"1", "contactType":"email",
"value":"shammi#abc.org" }, { "InfoId":"2", "department":"1", "contactType":"mobile", "value":"2222222222" }, { "InfoId":"3", "department":"1", "contactType":"home", "value":"Magic Dr,USA" } ] } ] }}</format>
<args/>
</payloadFactory>
<property action="remove" name="NO_ENTITY_BODY" scope="axis2" />
<property name="messageType" scope="axis2" type="STRING" value="application/json" />
<respond/>
</inSequence>
<outSequence/>
<faultSequence/>
</resource>
</api>
Roles
<?xml version="1.0" encoding="UTF-8" ?>
<api context="/services/roles" name="UserRolesAPI" xmlns="http://ws.apache.org/ns/synapse">
<resource methods="GET" protocol="http" uri-template="/{personid}">
<inSequence>
<filter regex="1" source="get-property('uri.var.personid')">
<then>
<payloadFactory media-type="json">
<format>{ "Id":1, "roles":[ { "roleId":1, "personKey":1, "role":"Deverloper" }, { "roleId":2, "personKey":1, "role":"Engineer" } ]}</format>
<args/>
</payloadFactory>
<property action="remove" name="NO_ENTITY_BODY" scope="axis2" />
<property name="messageType" scope="axis2" type="STRING" value="application/json" />
<respond/>
</then>
<else/>
</filter>
<filter regex="2" source="get-property('uri.var.personid')">
<then>
<payloadFactory media-type="json">
<format>{"personId": 2,"roles": [{ "personRoleId": 1, "personKey": 2, "role": "Manager" },{ "personRoleId": 2, "personKey": 2, "role": "QA" }]}</format>
<args/>
</payloadFactory>
<property action="remove" name="NO_ENTITY_BODY" scope="axis2" />
<property name="messageType" scope="axis2" type="STRING" value="application/json" />
<respond/>
</then>
<else/>
</filter>
</inSequence>
<outSequence/>
<faultSequence/>
</resource>
</api>
Finally, the main one, calling the first one, then iterating
<?xml version="1.0" encoding="UTF-8" ?>
<api context="/userdetails" name="UserDetailsAPI" xmlns="http://ws.apache.org/ns/synapse">
<resource methods="GET" protocol="http">
<inSequence>
<call>
<endpoint>
<http method="get" trace="disable" uri-template="http://localhost:8280/services/users" />
</endpoint>
</call>
<iterate attachPath="//jsonObject/persons" expression="//jsonObject/persons/person" id="it1" preservePayload="true" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<target>
<sequence>
<property expression="$body/jsonObject/persons/person/Id" name="uri.var.Id" scope="default" type="STRING" xmlns:ns="http://org.apache.synapse/xsd" />
<property expression="$body//jsonObject//person" name="response1" scope="default" type="STRING" xmlns:ns="http://org.apache.synapse/xsd" />
<call>
<endpoint>
<http method="get" trace="disable" uri-template="http://localhost:8280/services/roles/{uri.var.Id}" />
</endpoint>
</call>
<loopback/>
</sequence>
</target>
</iterate>
</inSequence>
<outSequence>
<send/>
</outSequence>
<faultSequence>
<sequence key="fault" />
</faultSequence>
</resource>
</api>
Executing the last api (http://localhost:8280/userdetails) is causing the following NPE:
20160408T101619.566 org.apache.synapse.transport.passthru.PassThroughHttpSender.handleException(PassThroughHttpSender.java:609) [PassThroughMessageProcessor-14] PassThroughHttpSender - Failed to submit the response
java.lang.NullPointerException
at org.apache.synapse.transport.passthru.util.SourceResponseFactory.create(SourceResponseFactory.java:64)
at org.apache.synapse.transport.passthru.PassThroughHttpSender.submitResponse(PassThroughHttpSender.java:462)
at org.apache.synapse.transport.passthru.PassThroughHttpSender.invoke(PassThroughHttpSender.java:267)
at org.apache.axis2.engine.AxisEngine.send(AxisEngine.java:442)
at org.apache.synapse.core.axis2.Axis2Sender.sendBack(Axis2Sender.java:212)
at org.apache.synapse.core.axis2.Axis2SynapseEnvironment.send(Axis2SynapseEnvironment.java:444)
at org.apache.synapse.mediators.builtin.SendMediator.mediate(SendMediator.java:102)
at org.apache.synapse.mediators.AbstractListMediator.mediate(AbstractListMediator.java:81)
at org.apache.synapse.mediators.AbstractListMediator.mediate(AbstractListMediator.java:48)
at org.apache.synapse.mediators.base.SequenceMediator.mediate(SequenceMediator.java:149)
at org.apache.synapse.rest.Resource.process(Resource.java:297)
at org.apache.synapse.rest.API.process(API.java:335)
at org.apache.synapse.rest.RESTRequestHandler.dispatchToAPI(RESTRequestHandler.java:97)
at org.apache.synapse.rest.RESTRequestHandler.process(RESTRequestHandler.java:52)
at org.apache.synapse.core.axis2.Axis2SynapseEnvironment.injectMessage(Axis2SynapseEnvironment.java:266)
at org.apache.synapse.mediators.builtin.LoopBackMediator.mediate(LoopBackMediator.java:55)
at org.apache.synapse.mediators.AbstractListMediator.mediate(AbstractListMediator.java:81)
at org.apache.synapse.mediators.eip.splitter.IterateMediator.mediate(IterateMediator.java:241)
at org.apache.synapse.mediators.base.SequenceMediator.mediate(SequenceMediator.java:267)
at org.apache.synapse.core.axis2.Axis2SynapseEnvironment.mediateFromContinuationStateStack(Axis2SynapseEnvironment.java:679)
at org.apache.synapse.core.axis2.Axis2SynapseEnvironment.injectMessage(Axis2SynapseEnvironment.java:244)
at org.apache.synapse.core.axis2.SynapseCallbackReceiver.handleMessage(SynapseCallbackReceiver.java:529)
at org.apache.synapse.core.axis2.SynapseCallbackReceiver.receive(SynapseCallbackReceiver.java:172)
at org.apache.axis2.engine.AxisEngine.receive(AxisEngine.java:180)
at org.apache.synapse.transport.passthru.ClientWorker.run(ClientWorker.java:251)
at org.apache.axis2.transport.base.threads.NativeWorkerPool$1.run(NativeWorkerPool.java:172)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
20160408T101619.576 org.apache.synapse.core.axis2.Axis2Sender.handleException(Axis2Sender.java:246) [PassThroughMessageProcessor-14] Axis2Sender - Accept:*/*,Accept-Encoding:gzip, deflate, sdch,Accept-Language:fr-FR,fr;q=0.8,en-US;q=0.6,en;q=0.4,Cache-Control:no-cache,Content-Type:application/json; charset=UTF-8,Host:localhost:8280,Postman-Token:3bfb96b7-0c31-964e-8c37-3b5dbd222efe,<?xml version='1.0' encoding='utf-8'?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"><soapenv:Body><jsonObject><Id>1</Id><roles><roleId>1</roleId><personKey>1</personKey><role>Deverloper</role></roles><roles><roleId>2</roleId><personKey>1</personKey><role>Engineer</role></roles></jsonObject></soapenv:Body></soapenv:Envelope> Unexpected error sending message back
org.apache.axis2.AxisFault: Failed to submit the response
at org.apache.synapse.transport.passthru.PassThroughHttpSender.handleException(PassThroughHttpSender.java:610)
at org.apache.synapse.transport.passthru.PassThroughHttpSender.invoke(PassThroughHttpSender.java:269)
at org.apache.axis2.engine.AxisEngine.send(AxisEngine.java:442)
at org.apache.synapse.core.axis2.Axis2Sender.sendBack(Axis2Sender.java:212)
at org.apache.synapse.core.axis2.Axis2SynapseEnvironment.send(Axis2SynapseEnvironment.java:444)
at org.apache.synapse.mediators.builtin.SendMediator.mediate(SendMediator.java:102)
at org.apache.synapse.mediators.AbstractListMediator.mediate(AbstractListMediator.java:81)
at org.apache.synapse.mediators.AbstractListMediator.mediate(AbstractListMediator.java:48)
at org.apache.synapse.mediators.base.SequenceMediator.mediate(SequenceMediator.java:149)
at org.apache.synapse.rest.Resource.process(Resource.java:297)
at org.apache.synapse.rest.API.process(API.java:335)
at org.apache.synapse.rest.RESTRequestHandler.dispatchToAPI(RESTRequestHandler.java:97)
at org.apache.synapse.rest.RESTRequestHandler.process(RESTRequestHandler.java:52)
at org.apache.synapse.core.axis2.Axis2SynapseEnvironment.injectMessage(Axis2SynapseEnvironment.java:266)
at org.apache.synapse.mediators.builtin.LoopBackMediator.mediate(LoopBackMediator.java:55)
at org.apache.synapse.mediators.AbstractListMediator.mediate(AbstractListMediator.java:81)
at org.apache.synapse.mediators.eip.splitter.IterateMediator.mediate(IterateMediator.java:241)
at org.apache.synapse.mediators.base.SequenceMediator.mediate(SequenceMediator.java:267)
at org.apache.synapse.core.axis2.Axis2SynapseEnvironment.mediateFromContinuationStateStack(Axis2SynapseEnvironment.java:679)
at org.apache.synapse.core.axis2.Axis2SynapseEnvironment.injectMessage(Axis2SynapseEnvironment.java:244)
at org.apache.synapse.core.axis2.SynapseCallbackReceiver.handleMessage(SynapseCallbackReceiver.java:529)
at org.apache.synapse.core.axis2.SynapseCallbackReceiver.receive(SynapseCallbackReceiver.java:172)
at org.apache.axis2.engine.AxisEngine.receive(AxisEngine.java:180)
at org.apache.synapse.transport.passthru.ClientWorker.run(ClientWorker.java:251)
at org.apache.axis2.transport.base.threads.NativeWorkerPool$1.run(NativeWorkerPool.java:172)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.NullPointerException
at org.apache.synapse.transport.passthru.util.SourceResponseFactory.create(SourceResponseFactory.java:64)
at org.apache.synapse.transport.passthru.PassThroughHttpSender.submitResponse(PassThroughHttpSender.java:462)
at org.apache.synapse.transport.passthru.PassThroughHttpSender.invoke(PassThroughHttpSender.java:267)
... 26 more
I'm afraid, this is the same issue than here (but not sure).
Would you please help me quickly to avoid before we decide to give wso2 away ?
The better would be to have the third part (userdetails) fixed by an answer.
Thank a lot !
In this case your loopback is inside the iterate mediator and that is calling outSequence each time you iterate.
If you move your loopback mediator out of the iterate as shown below, this should send the last response from the iterate to the client. If you want to aggregate your responses from the iteration, you should use aggregate mediator[1].
[1] https://docs.wso2.com/display/ESB490/Aggregate+Mediator
Updated
Unfortunately the above solution does not work, because each time an iteration completes, the flow still continues, so even if we have a loopback outside the iterate, we will be calling the outSequence multiple times. We will have to use an aggregate to be able to use the complete condition to trigger the outSequence once. Please have a look at the below configuration.
<api xmlns="http://ws.apache.org/ns/synapse" name="UserDetailsAPI" context="/userdetails">
<resource methods="GET">
<inSequence>
<call>
<endpoint>
<http trace="disable" method="GET" uri-template="http://localhost:8280/services/users"/>
</endpoint>
</call>
<iterate xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" id="it1" preservePayload="true" attachPath="//jsonObject/persons" expression="//jsonObject/persons/person">
<target>
<sequence>
<property xmlns:ns="http://org.apache.synapse/xsd" name="uri.var.Id" expression="$body/jsonObject/persons/person/Id" scope="default" type="STRING"/>
<property xmlns:ns="http://org.apache.synapse/xsd" name="response1" expression="$body//jsonObject//person" scope="default" type="STRING"/>
<call>
<endpoint>
<http trace="disable" method="GET" uri-template="http://localhost:8280/services/roles/{uri.var.Id}"/>
</endpoint>
</call>
</sequence>
</target>
</iterate>
<aggregate id="it1">
<completeCondition>
<messageCount min="-1" max="-1"/>
</completeCondition>
<onComplete expression="//jsonObject">
<loopback/>
</onComplete>
</aggregate>
</inSequence>
<outSequence>
<send/>
</outSequence>
<faultSequence>
<sequence key="fault"/>
</faultSequence>
</resource>
</api>