Setting SOAP Envelope Payload in a Custom Mediator - wso2

I am writing a proxy service in WSO2 ESB that accepts a JSON payload and performs some transformations (to a SOAP message) that are quite complex, so we are writing the transformation logic in a Custom Mediator.
As you can see, my custom mediator class sets a property in the message context, and the proxy flow extracts this property and sets the payload (using a Javascript API that I could find).
This results in my SOAP message being "double wrapped" in two envelope tags, and I need to use an enricher with a XPath expression to remove the outer envelope/body tags.
Is it possible to set the XML payload within the custom mediator, thus avoiding to read a property and writing the XML payload in the proxy flow?
The proxy code is listed below:
<?xml version="1.0" encoding="UTF-8"?>
<proxy name="stackOverflowProxy" startOnLoad="true" trace="disable"
transports="jms" xmlns="http://ws.apache.org/ns/synapse">
<target>
<inSequence>
<!-- process incoming request in custom class. the payload is a JSON object -->
<class name="stackOverflow.CustomMediator"/>
<!-- set registration xml string as xml payload -->
<script language="js"><![CDATA[mc.setPayloadXML(new XML(mc.getProperty('mediatorPayload')));]]></script>
<enrich>
<source clone="true"
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xpath="$body//soapenv:Envelope/soapenv:Body/*"/>
<target type="body"/>
</enrich>
</inSequence>
<outSequence/>
<faultSequence/>
</target>
</proxy>
And this is the Custom Mediator class:
package stackOverflow;
// imports ...
public class CustomMediator extends AbstractMediator {
public boolean mediate(MessageContext messageContext) {
//messageContext has a json object property
//message is processed and transformed to a SOAPEnvelope (namespaces omitted for simplicity)
//soapEnvelopeString = <Envelope><Body><tag>value</tag></Body></Envelope>
messageContext.setProperty("mediatorPayload", soapEnvelope.toString());
return true;
}
}

In your custom mediator you are setting entire soap message in to a property and in script mediator setting it as payload of the soap message. thats why you are getting double soap env.
in your class mediator set only the body payload to property and then insert that value as payload in main flow using script will solve your issue.
package stackOverflow;
// imports ...
public class CustomMediator extends AbstractMediator {
public boolean mediate(MessageContext messageContext) {
//messageContext has a json object property
//message is processed and transformed to a SOAPEnvelope (namespaces omitted for simplicity)
//**soapPayload = <tag>value</tag>**
messageContext.setProperty("mediatorPayload", soapPayload);
return true;
}
}

Related

Logging is not functioning properly after changing Logging Configuration via managemnt console in WSO2 EI 6.5.0

I have developed API which call the class mediator via sequence in WSO2 EI 6.5.0. Initially API logs are getting printed except class mediator logs in Server log.
To enable logs for class mediator as per this, I logged into management console Home> Configure> Logging section and went to section Configure Log4J Loggers , searched log keyword whatever i added inside class mediator to find out class mediator and changed class level to Debug
post this change, nothing is printed when i invoke service via postman, but API response getting. I just restarted server, post this management console url also not getting printed in server logs.
Below is the management console logging configuration image for reference.
Class Mediator:
package com.abc.in;
import org.apache.synapse.MessageContext;
import org.apache.synapse.mediators.AbstractMediator;
import org.apache.synapse.core.axis2.Axis2MessageContext;
/*import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;*/
import java.util.ArrayList;
import java.util.Map;
public class DuplicateHeadersMediator extends AbstractMediator {
// private static final Log logger = LogFactory.getLog(DuplicateHeadersMediator.class);
public boolean mediate(MessageContext messageContext) {
log.info("DuplicateHeadersMediator called********** : " );
trace.info("trace DuplicateHeadersMediator called********** :");
org.apache.axis2.context.MessageContext axis2MessageContext = ((Axis2MessageContext) messageContext)
.getAxis2MessageContext();
Map excessHeaders = (Map) axis2MessageContext.getProperty("EXCESS_TRANSPORT_HEADERS");
log.info("excessHeaders : " + excessHeaders.entrySet());
trace.info("trace excessHeaders : " + excessHeaders.entrySet());
Map transportHeaders = (Map) axis2MessageContext.getProperty("TRANSPORT_HEADERS");
log.info("transportHeaders : " + transportHeaders.entrySet());
trace.info("trace transportHeaders : " + transportHeaders.entrySet());
if (excessHeaders.size() != 0 && transportHeaders.size() != 0) {
for (Object key : transportHeaders.keySet()) {
addPropertiesForExcessHeaders((String)key,excessHeaders,messageContext);
}
}
return true;
}
// Add extra properties to the synapse message context for duplicated headers.
private void addPropertiesForExcessHeaders(String headerName, Map excessHeaders, MessageContext messageContext) {
if (excessHeaders.get(headerName) != null) {
ArrayList<String> list = (ArrayList) excessHeaders.get(headerName);
if (list.size() > 0) {
int i = 2;
for (String value : list) {
String propName = headerName + i;
messageContext.setProperty(propName, value);
log.info("propName : " + propName);
trace.info("trace propName : " + propName);
i += 1;
}
}
}
}
}
API:
<?xml version="1.0" encoding="UTF-8"?>
<api context="/readcookiesapi" name="ReadCookiesAPI" xmlns="http://ws.apache.org/ns/synapse">
<resource methods="POST">
<inSequence>
<log level="custom">
<property name="ReadCookiesAPI" value="is called *****"/>
</log>
<sequence key="HeaderMediatorCall_Sequecne"/>
<log level="custom">
<property expression="$trp:test" name="test1"/>
<property expression="$ctx:test2" name="test2"/>
<property expression="$ctx:test3" name="test3"/>
</log>
<respond/>
</inSequence>
<outSequence/>
<faultSequence/>
</resource>
</api>
Sequence:
<?xml version="1.0" encoding="UTF-8"?>
<sequence name="HeaderMediatorCall_Sequecne" trace="disable" xmlns="http://ws.apache.org/ns/synapse">
<log level="custom">
<property name="HeaderMediatorCall_Sequecne" value="B4 *****"/>
</log>
<class name="com.abc.in.DuplicateHeadersMediator"/>
<log level="custom">
<property name="HeaderMediatorCall_Sequecne" value="after *****"/>
</log>
</sequence>
Kindly clarify my doubts mentioned below.
how can I recover default logging mechanism since this change made product logging weird, so that artifacts like API, Sequence etc and server logs i'll get properly
why class mediator logs are not getting printed initially or how can i get those class mediators log in wso2 ei server 6.5.0
When you extend AbstractMediator you should already have an instance of the logger for you to use. Check here. So you don't have to instantiate a new Logger. You can simply use the existing logger.
I have used java.util.logging.Logger to reflect logger inside class mediator. Still not sure why org.apache.commons.logging.LogFactory not printing anything in log.
import java.util.logging.Logger;
public class ParseEmailBody extends AbstractMediator {
private static final Logger logger = Logger.getLogger(ParseEmailBody.class.getName());
public boolean mediate(MessageContext context) {
logger.info("===Inside ParseEmailBody Class Mediator===");
return true;
}

Regd. getting empty response with data mapper in wso2 EI

I am trying to transform json to xml using datamapper and i am getting the empty xml structure but not getting any values in wso2. I have created data mapper dependencies and loaded both input and out structures and used AI to map json -> xml and they mapped correctly.
I tried on eclipse oxygen(esb-6.2.0) and integration studio(v8) also and deployed in EI(6.5.0) but still the behavior is same empty response structure. I kept a log in the in-sequence and it is logging the json request but not the xml response. I am not getting why the issue is happening.
Please provide your thoughts and attached the code to this post. Please do needful
The issue is with the API. In the API we need to specify the input and the output data type. In your case since the transformation is from JSON to XML, the input type needs to be JSON while the output type needs to be XML. But you have defined both as xml which resulted in this issue. Modify the input type to JSON and you will get the expected results
<api xmlns="http://ws.apache.org/ns/synapse" name="DataMapper" context="/data">
<resource methods="POST" url-mapping="/mapper">
<inSequence>
<log separator="/">
<property name="payload" expression="json-eval($.body)"/>
</log>
<datamapper config="gov:datamapper/Wso2DataMapper.dmc" inputSchema="gov:datamapper/Wso2DataMapper_inputSchema.json" outputSchema="gov:datamapper/Wso2DataMapper_outputSchema.json" xsltStyleSheet="gov:datamapper/Wso2DataMapper_xsltStyleSheet.xml" inputType="JSON" outputType="XML"/>
<respond/>
</inSequence>
<outSequence/>
<faultSequence/>
</resource>
</api>
input
{
"studNo":"Sample studNo",
"studName":"Sample studName",
"StudGroup":"Sample StudGroup",
"studAddress":{
"addrLine1":"Sample addrLine1",
"AddrLine2":"Sample AddrLine2",
"Mandal":"Sample Mandal",
"District":"Sample District",
"State":"Sample State",
"Country":"Sample Country",
"Zip":"Sample Zip"
}
}
output
<Student xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<studentNo>Sample studNo</studentNo>
<studentName>Sample studName</studentName>
<studentGroup>Sample StudGroup</studentGroup>
<studentAddress>
<AddressLine1>Sample AddrLine2</AddressLine1>
<AddressLine2>Sample addrLine1</AddressLine2>
<Mandal>Sample Mandal</Mandal>
<District>Sample District</District>
<State>Sample State</State>
<Country>Sample Country</Country>
<ZIP>Sample Zip</ZIP>
</studentAddress>
</Student>

How to get Request payload content at Response path class mediator using OMElement - WSO2 APIM ver 3.2.0

I am using WSO2 APIM version 3.2.0.
I have a POST request with the request payload.
In the response message mediation of WSO2 APIM I have added the policy that contains the class mediator that tries to get the payload sent during the request.
OMElement element = (OMElement) mc.getEnvelope().getBody().getFirstOMChild();
log.info("payload: " + element.toString());
The above code snippet prints the response payload content but I need the request payload content at the response path.
Response message mediation with a policy added
Below is the sequence with class mediator
sequence with class mediator
Code snippet inside class mediator
OMElement element = (OMElement) mc.getEnvelope().getBody().getFirstOMChild();
log.info("payload: " + element.toString());
Pls let me know what changes to be done, to get the request payload content.
First, we have to store the request payload in a custom property in the Message Context. Then, we can use that property to retrieve the Request Payload in the Response path of the execution.
For example: You are invoking an API with JSON Payload. So, we have to first capture the sent payload and store it in a custom property in the Message Context. Given below is a sample sequence to perform the same
<?xml version="1.0" encoding="UTF-8"?>
<sequence xmlns="http://ws.apache.org/ns/synapse" name="admin--MockAPI:v1.0.0--In">
<property name="RequestPayload" expression="json-eval($)" />
<log level="custom">
<property name="RequestPayload" expression="$ctx:RequestPayload" />
</log>
</sequence>
Then, in the Response path, inside your custom class mediator, you have to access the RequestPayload property from the MessageContext to extract the stored payload. You can achieve this by using the following snippet
synapseContext.getProperty("RequestPayload");

CXF RestFul Service - Get Post Body Parameters

I have developed a webservice following the below link, however I am unable to get the request parameters from the POST request body.
http://info.appdirect.com/blog/how-to-easily-build-rest-web-services-with-java-spring-and-apache-cxf
I use the Soap UI to invoke the
service, with "Post QueryString in Message Body" option checked.
So far, I have tried below options, but none seem to work:
Tried MultiValued Map, but the map is always empty.
#POST
#Path("/getpostfile/{fileName}")
#Produces("application/pdf")
#Consumes("application/x-www-form-urlencoded")
public Response getPostFile(MultivaluedMap form){...}
Tried #FormParam() & #QueryParam as well, but still the params are null in webservice method.
Tried creating a POJO bean with #XmlRootElement annotation, however this time I get an exception saying "SEVERE: No message body reader has been found for class com.wcc.LoginInfo, ContentType: application/x-www-form-urlencoded". LoginInfo is my bean class with two parameters:
#XmlRootElement
public class LoginInfo {
String username;
String password;
....
Below is the service method:
#POST
#Path("/getpostfile/{fileName}")
#Produces("application/pdf")
#Consumes("application/x-www-form-urlencoded")
public Response getPostFile(LoginInfo logininfo){...}
Below is my cxf-beans.xml file:
<bean .....>
<jaxrs:server id="wccservice" address="/">
<jaxrs:serviceBeans>
<ref bean="wccdocumentservice" />
</jaxrs:serviceBeans>
<jaxrs:providers>
<ref bean="formUrlEncodeProvider" />
</jaxrs:providers>
</jaxrs:server>
<bean id="wccdocumentservice" class="com.wcc.WCCDocumentServiceImpl" />
<bean id="formUrlEncodeProvider" class="org.apache.cxf.jaxrs.provider.FormEncodingProvider" />
<bean id="jsonProvider" class="org.apache.cxf.jaxrs.provider.json.JSONProvider">
<property name="marshallAsJaxbElement" value="true" />
</bean>
Any ideas on how to retrieve the POST parameters in request body, in the Webservice method?
Guess I was dwelling too much into CXF, missed the simple approach. We can get the Post request parameters in CXF service similar to the way we get the parameters in a Servlet.
For Query Parameters in POST request:
#POST
#Path("/getpostfile/{fileName}")
#Produces("application/pdf")
#Consumes("application/x-www-form-urlencoded")
public Response getPostFile(#PathParam("fileName") String fileName, #Context HttpServletRequest request)
{
System.out.println("id is : " + request.getParameter("id")+", password is : " + request.getParameter("password"));
and for Parameters in POST message body, you may use getBody() method from below link:
Getting request payload from POST request in Java servlet
Hope that helps someone!

Custom Mediator in Sequence only run when WSO2 StartUp

I make a custom mediator that simply print "Hello World" my custom mediator look like this :
public class HelloWorld extends AbstractMediator implements ManagedLifecycle{
public static void helloWorld() {
System.out.println("Hello World");
}
public void init(SynapseEnvironment synapseEnvironment) {
// initializing surcharges map with some symbols
helloWorld();
}
public void destroy() {
// clearing the surcharges contents
}
#Override
public boolean mediate(MessageContext arg0) {
// TODO Auto-generated method stub
return false;
}
}
i call this class in sequence called "Hello" :
<sequence name="Hello">
<class name="com.exec.HelloWorld">
</class>
and i use this sequence in proxy like this :
<proxy xmlns="http://ws.apache.org/ns/synapse" name="FileProxy" transports="vfs" startOnLoad="true" trace="disable">
<target>
<inSequence>
<log level="full"/>
<target sequence="Hello"/>
</inSequence>
</target>
<parameter name="transport.vfs.ActionAfterProcess">MOVE</parameter>
<parameter name="transport.PollInterval">15</parameter>
<parameter name="transport.vfs.MoveAfterProcess">file:///Users/Source</parameter>
<parameter name="transport.vfs.FileURI">file:///Users/Target/</parameter>
<parameter name="transport.vfs.FileNamePattern">.*.txt</parameter>
<parameter name="transport.vfs.ContentType">text/plain</parameter>
I expect that everytime i put a file (*.txt) in the Source folder than my sequence will be called. But the problem is the sequence is only called once (when the wso2 esb Startup). How can i make my sequence to be called every time I put a file in the Source folder?
Thanks,
I think it is working as expected, but I think you missunderstood how it works your custom mediator. The message you see is the one showed by the init method, this is when the meditor is created.
This mediator is running everytime you left a file in the folder but the method launched when it happens is "mediator" methos, which implementation does nothing (retrun false). So you should implement mediator method as
public boolean mediate(MessageContext arg0) {
hellowWorld();
return false;
}
and it will show the message as you expect.
Hope it works!
You should call your logic inside mediate method(). And make the return value as true. If you make that as false, mediation engine will return false in the mediation process, and it makes issue in the message flow.
You can check this sample