Appending JSON content to a JSON file in WSO2 - json

I have few JSON Payloads that have to be appended to a JSON file.
This is how my JSON Payload will look:
{"variant": {"940894": {"attributes": {"Size": "XL" } } } }
I will be getting multiple json Payloads of this type.
At the end I need to form a file that looks like this:
[
{"variant": {"940894": {"attributes": {"Size": "XL" } } } },
{"variant": {"940895": {"attributes": {"Size": "Med" } } } },
{"variant": {"940895": {"attributes": {"Size": "Small" } } } }
]
These are the properties I have set for the requirement:
<property expression="fn:concat('Test',get-property('File_Name'),'.txt')" name="FILE_NAME" scope="default"
<propertyGroup description="File and OutputPayload properties">
<property name="messageType" scope="axis2" type="STRING" value="text/plain"/>
<property name="ContentType" scope="axis2" type="STRING" value="text/plain"/>
<property expression="$ctx:FILE_NAME" name="transport.vfs.ReplyFileName" scope="transport" type="STRING"/>
<property name="OUT_ONLY" scope="default" type="STRING" value="true"/>
</propertyGroup>
<call>
<endpoint>
<address uri="vfs:sftp://username:password/home/user/test/out/json?transport.vfs.Append=true">
<suspendOnFailure>
<initialDuration>-1</initialDuration>
<progressionFactor>1</progressionFactor>
</suspendOnFailure>
<markForSuspension>
<retriesBeforeSuspension>0</retriesBeforeSuspension>
</markForSuspension>
</address>
</endpoint>
</call>
But I get an error saying "The file type does not support append mode". What else can I try here.

I had a look at the code, and as you already noticed SFTP protocol doesn't allow you to do file appending. The supported operations for SFTP are here in the code.
Capability.CREATE, Capability.DELETE, Capability.RENAME, Capability.GET_TYPE,
Capability.LIST_CHILDREN, Capability.READ_CONTENT, Capability.URI, Capability.WRITE_CONTENT,
Capability.GET_LAST_MODIFIED, Capability.SET_LAST_MODIFIED_FILE, Capability.RANDOM_ACCESS_READ
But if you use FTP protocol instead you should be able to do File Appending as it's supported here.
Capability.CREATE, Capability.DELETE, Capability.RENAME,
Capability.GET_TYPE, Capability.LIST_CHILDREN,
Capability.READ_CONTENT, Capability.GET_LAST_MODIFIED,
Capability.URI, Capability.WRITE_CONTENT,
Capability.APPEND_CONTENT, Capability.RANDOM_ACCESS_READ
Appending works with the Local file system too.
If you want to append the file and still use SFTP you will have to READ -> APPEND -> WRITE the file. Or can consider writing a Custom Class mediator.

Related

GET url of endpoint

I'm trying to develop a sequence in Wso2 esb. I need to log the URL of the endpoint
this a snippet of my sequence
<script language="js"><![CDATA[
var log = mc.getServiceLog();
var requestBody = mc.getProperty("requestBody");
log.info("Avant de checker l'adresse "+requestBody.city);
mc.setProperty("addressNonNull",1);
if (requestBody.street || requestBody.zip || requestBody.city || requestBody.country) {
if(requestBody.street) {
mc.setProperty("query.param.street",requestBody.street);
}
if(requestBody.city) {
mc.setProperty("query.param.city",requestBody.city);
}
mc.setProperty("addressNonNull",1);
}
log.info("crm_create_subtasks_v2 address_value ==>"+requestBody.street+"|" +requestBody.zip+"|"+requestBody.city);
]]>
</script>
<switch source="get-property('addressNonNull')" xmlns:ns="http://org.apache.synapse/xsd">
<case regex="1.0">
<header name="Content-Type" scope="transport" value="application/json"/>
<property name="Content-Encoding" action="remove" scope="transport"/>
<property name="Authorization" expression="fn:concat('Basic ', base64Encode('user:password'))" scope="transport" type="STRING" xmlns:ns="http://org.apache.synapse/xsd"/>
<call>
<endpoint key="jira_address_exist_v2"/>
</call>
<property expression="json-eval($.)" name="check address exist"
scope="default" type="STRING" xmlns:ns="http://org.apache.synapse/xsd"/>
<log>
<property name="create_subtasks_v2 response jira_address_exist_v2" expression="json-eval($.)"/>
</log>
I need to display URL generated befor making request to the endpoint "jira_address_exist_v2" in the logs.
Best regards
Add this just before the call mediator,
<log level="simple"/>
<call>
<endpoint key="jira_address_exist_v2"/>
</call>
Not sure if this works, but at least you can give it a try. Add the following just before .
<log level="full">
<property name="To" expression="$trp:To" />
<property name="TO" expression="$trp:TO" />
</log>
If this doesn't work you can also enable wire log. Go to the esb console -> confiugre -> logging and search for a class xxx.http.wire and enable debug. Then you'll see what the esb receives and sends out.

How can I create a JSON payload with text containing XML in it?

I try to create an automatic JIRA problem reporting (in some FAULT sequences.
I make a JSON payload for JIRA APIs what works just fine for text.
I would like to however report to JIRA a SOAP request and response whereby I could investigate on the issue.
my question is how can I create a JSON payload with text containing XML in it?
I get this exception in WSO2 ESB
[2016-09-18 21:46:31,774] ERROR - NativeWorkerPool Uncaught exception
java.lang.Error: Error: could not match input
at org.apache.synapse.commons.staxon.core.json.stream.impl.JsonScanner.zzScanError(JsonScanner.java:530)
at org.apache.synapse.commons.staxon.core.json.stream.impl.JsonScanner.yylex(JsonScanner.java:941)
payload which I want to generate
<payloadFactory description="" media-type="json">
<format>
{
"fields": {
"project":
{
"key": "$1"
},
"summary": "$2",
"description": "$3",
"issuetype": { "name": "$4" }
}
}
</format>
<args>
<arg evaluator="xml" expression="$func:projectKey"/>
<arg evaluator="xml" expression="$func:summary"/>
<arg evaluator="xml" expression="$func:description"/>
<arg evaluator="xml" expression="$func:issueType"/>
</args>
</payloadFactory>
and I want to send some text containing XML into the parameter $func:description. When I sent only poor XML into the $func:description, the payload Factory transferred into into JSON what is not needed in this case, the the XML is supposed to be a text - the message
for the completeness to get the XML message I used
<property expression="$body" name="request"
scope="default" type="STRING"/>
call the end-point
<property expression="$body" name="response"
scope="default" type="STRING"/>
and I need to know bind "request" + "response" into $func:description
If the XML is well-formed you can simply set messageType property to application/json and do the conversion automatically. Refer this for more details.
Or else you can use the payload Factory mediator or Enrich mediator to custom build your Json.
create the payload with the XML structure you like.
use JS script mediator to modify one node as CDATA.
change the content type.
My proxy config, please do the change you need for your requirement:
<?xml version="1.0" encoding="UTF-8"?>
<proxy xmlns="http://ws.apache.org/ns/synapse"
name="XMLinsideJSON"
transports="http https"
startOnLoad="true">
<target>
<inSequence>
<property name="BOK" expression="//*[1]" type="OM" scope="default"/>
<enrich>
<source type="inline" clone="true">
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header/>
<soapenv:Body>
<fields xmlns="">
<summary xmlns=""/>
<project xmlns=""/>
<description xmlns=""/>
<issuetype xmlns="">
<name xmlns=""/>
</issuetype>
</fields>
</soapenv:Body>
</soapenv:Envelope>
</source>
<target type="envelope"/>
</enrich>
<script language="js">
importPackage(Packages.org.apache.axiom.om);
var elem= mc.getEnvelope().getBody().getFirstElement().getFirstElement();
var myText = elem.getOMFactory().createOMText(elem, mc.getProperty("BOK"), OMNode.CDATA_SECTION_NODE);
elem.addChild(myText)
</script>
<property name="messageType" scope="axis2" value="application/json"/>
<respond/>
</inSequence>
<outSequence>
<send/>
</outSequence>
</target>
</proxy>
My request:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header/>
<soapenv:Body>
<payload>
<response>
<data>AAA</data>
</response>
</payload>
</soapenv:Body>
</soapenv:Envelope>
My response:
{"fields":{"summary":"<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\"><soapenv:Body>\n <payload>\n <response>\n <data>AAA</data>\n </response>\n </payload>\n </soapenv:Body></soapenv:Envelope>","project":null,"description":null,"issuetype":{"name":null}}}

WSO2 - Transforming and aggregating different JSON data from multiple endpoints

I've created an API in WSO2 Carbon (5.0) which I POST a payload to:
{
"IdNumber" : "8008185218088",
"LastName" : null
}
I then call initiate a clone mediator sequence which forwards this payload to two different REST endpoints. The json response from the endpoints is different:
Endpoint 1 response:
{
"Name" : "Daniel",
"Number" : "12345678"
}
Endpoint 2 response:
{
"Name": "Bob",
"Address": "200 Bob Street",
"Code": "123"
}
The API response I'd like to create based on the above:
{
"Endpoint 1 Response" : {
"Name" : "Daniel",
"Number" : "12345678"
},
"Endpoint 2 Response" : {
"Name": "Bob",
"Address": "200 Bob Street",
"Code": "123"
}
}
What mediators on the outSequence do I need to configure to achieve this? How would I query the individual json response fields and combine them into a custom formatted json message for the client?
I've looked at the Aggregate mediator but I don't think it's right for differently formatted messages.
Here is my inSequence for reference:
<resource methods="POST">
<inSequence>
<property name="ROOT" scope="default">
<root:rootelement xmlns:root="www.wso2esb.com"/>
</property>
<log level="full"/>
<clone continueParent="true" id="test" sequential="true">
<target>
<sequence>
<send>
<endpoint>
<address uri="http://192.168.1.1/api/service/person" format="rest"/>
</endpoint>
</send>
</sequence>
</target>
<target>
<sequence>
<send>
<endpoint>
<address uri="http://192.168.1.1/api2/query" format="rest"/>
</endpoint>
</send>
</sequence>
</target>
</clone>
</inSequence>
You will be unable to aggregate messages like this. A solution is to use the 'call' mediator, store the first response (or the values) in a property and call the second service afterwards.
Something like this:
<call>
<endpoint>
<address uri="http://192.168.1.1/api/service/person" format="rest"/>
</endpoint>
</call>
<property name="Name1" expression="//Name" />
<property name="Number1" expression="//Number" />
<send>
<endpoint>
<address uri="http://192.168.1.1/api2/query" format="rest"/>
</endpoint>
</send>
<outSequence>
-- build message using payloadfactory
</outSequence>
You can use a payloadFactory in the outSequence to build the response message.

Converting input XML to JSON format in WSO2 ESB

I want to convert the input XML to JSON format in WSO2 ESB.
I have tried using the property mediator but it is not working,
<property name="messageType" value="application/json" scope="axis2" type="STRING"></property>
<property name="Content-Type" value="application/json" scope="transport" type="STRING"></property>
Try this configuration:
<inSequence>
...
</inSequence>
<outSequence>
<property name="messageType" value="application/json" scope="axis2"></property>
<respond/>
</outSequence>
You just need to add formatter (which is define by messageType property) to format out going message.
<property name="messageType" value="application/json" scope="axis2" type="STRING"></property>
Content-Type property is used to build incoming message to the format of the SOAP, which is used inside the ESB. If incoming message is XML you can use the following builder. Adding this property is not compulsory, if the "Content-Type" is sent with the incoming message headers ESB automatically pic it and build the message.
<property name="Content-Type" value="application/xml" scope="transport" type="STRING"></property>
Also make sure you have enable the "application/json" message formatters inside the axis2.xml file. this can be found inside the repository/conf/axis2 folder.
Let's assume your xml input is,
<name>abc</name>
<id>123</id>
Then you need to convert it to Json format as,
{
"name" : "abc",
"id" : "123"
}
You can use PayloadFactory mediator to convert XML to JSON format
<payloadFactory media-type="json">
<format>
{
"name" : "$1",
"id" : "$2"
}
</format>
<args>
<arg evaluator="xml" expression="//name"/>
<arg evaluator="xml" expression="//id"/>
</args>
</payloadFactory>
Hope this helps!!

Iterate Mediator over json arrays

I'd like to iterate the results array of a json message
{
"results":[
{
"category":"mdl",
"subcategory":"ip",
"ip":"103.14.120.121",
"subtype":"IP-MDL",
"date":"1405074556",
"longitude":"75.3333",
"latitude":"19.8833",
"country":"India",
"city":"Aurangabad",
"organization":"Good Domain Registry Private Limited",
"isp":"Good Domain Registry Private Limited"
},
{
"category":"mdl",
"subcategory":"ip",
"ip":"108.162.198.96",
"subtype":"IP-MDL",
"date":"1405074556",
"longitude":"-122.3933",
"latitude":"37.7697",
"country":"United States",
"city":"San Francisco",
"organization":"CloudFlare",
"isp":"CloudFlare"
}
]
}
unfortunately iteration mediator doesn't seem to accept non xpath expression
anyone knows how to iterate over the previous message json results the same way i do it in xml ?
I'd like to use ESB json-native support but doesn't seem to be able to break down json messages as with XML (i've tried iterate mediator, json payload factory and script mediator without any success)
<iterate expression="json-eval(results)">
<target>
<sequence>
<property name="messageType" value="application/json" scope="axis2"/>
<payloadFactory media-type="json">
<format>
{
"event":{
"providerName":"$1",
"providerSource":"$2",
"providerClassification":"$3",
"providerVersion":"$4",
"body":{
"results":{$5}
}
}
}
</format>
<args>
<arg value="bdigital"/>
<arg evaluator="json" expression="$.results.category"/>
<arg evaluator="json" expression="$.results.subcategory"/>
<arg value="1.0"/>
<arg evaluator="json" expression="$.results"/>
</args>
</payloadFactory>
<call>
<endpoint>
<http method="post"
uri-template="http://BD-VM-PP-CIC01:8280/services/CICQueue"/>
</endpoint>
</call>
</sequence>
</target>
</iterate>
thanks in advance,
You could do the following?
<property name="messageType" value="application/xml" scope="axis2" type="STRING"></property>
<iterate xmlns:ns="http://org.apache.synapse/xsd" continueParent="true" expression="//jsonObject/results" id="MyIterator">
<target>
<sequence>
<property name="cat" expression="json-eval($.results.category)" type="STRING"></property>
etc.
There is a new version in WSO2 EI in which you can iterate over JSON using JSON Path. You can do something like below.
<iterate id="iterate-over-users" preservePayload="true" attachPath="json-eval($.results)" expression="json-eval($.results)">
<target>
<sequence>
<send>
<endpoint>
<http method="POST" uri-template="http://backend.com"/>
</endpoint>
</send>
</sequence>
</target>
</iterate>
Refer to the following blog for more info. https://medium.com/#arunans23/iterate-over-json-payload-with-wso2-enterprise-integrator-8ccb9cdd2c70