WSO2 custom handler work with JSON data - wso2

Writing on a custom WSO2 handler my services work using JSON. Trying to get the handler read JSON data
The solve in Howto extract data from the JSON body of REST request inside a WSO2 ESB Synapse handler
did not work
Handler code
#Override
public boolean handleRequest(MessageContext messageContext) {
System.out.println("getEnvelope - "+ messageContext.getEnvelope().getBody().toString());
org.apache.axis2.context.MessageContext mc = ((Axis2MessageContext) messageContext).getAxis2MessageContext();
JSONObject jsonBody = new JSONObject(JsonUtil.jsonPayloadToString(mc));
System.out.println("Payload in json -"+ jsonBody);
String jsonPayloadToString = JsonUtil.jsonPayloadToString(((Axis2MessageContext) messageContext).getAxis2MessageContext());
System.out.println("Payload in string -"+ jsonPayloadToString);
console Output
getEnvelope - <soapenv:Body xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"/>
Payload in json -{}
Payload in string -{}
Tried the all 3 three combinations in axis2.xml
<messageBuilder contentType="application/json"
class="org.apache.axis2.json.JSONOMBuilder"/>
<!--messageBuilder contentType="application/json"
class="org.apache.synapse.commons.json.JsonStreamBuilder"/-->
<!--messageBuilder contentType="application/json"
class="org.apache.synapse.commons.json.JsonBuilder"/-->
-----------------
<messageFormatter contentType="application/json"
class="org.apache.axis2.json.JSONMessageFormatter"/>
<!--messageFormatter contentType="application/json"
class="org.apache.synapse.commons.json.JsonStreamFormatter"/-->
<!--messageFormatter contentType="application/json"
class="org.apache.synapse.commons.json.JsonFormatter"/-->
Any help will be of great help
Thanks

Try RelayUtils.buildMessage(messageContext); before printing the body.

Try this code for your json:
try {
RelayUtils.buildMessage(((Axis2MessageContext) messageContext).getAxis2MessageContext());
}
catch (XMLStreamException e) {
e.printStackTrace();
}
catch (IOException e1) {
e1.printStackTrace();
}
String body = JsonUtil.jsonPayloadToString(((Axis2MessageContext) messageContext).getAxis2MessageContext());
String httpMethod = (String) ((Axis2MessageContext) messageContext).getAxis2MessageContext().getProperty("HTTP_METHOD");
System.out.println("\n\nWSO2CustomHandler - handleRequest body!!" + body);
System.out.println("\n\nWSO2CustomHandler - handleRequest httpMethod!!" + httpMethod);

Related

how to create PACT for multipart/form-data uploading cdc test

I`m trying to create cdc test for uploading file verifying. I use DIUS library. I do not find any examples how to work with .withFileUpload() in DIUS. My code for pact is next:
#Pact(provider = PROVIDER, consumer = CONSUMER)
public RequestResponsePact createPact(PactDslWithProvider builder) throws Exception {
DslPart responseBody = new PactDslJsonBody()
.stringType("resource", DESTINATION_FILENAME)
.stringType("requestId", null)
.stringType("code", "201")
.array("response")
.closeArray()
.asBody();
return builder.given("UploadOperation")
.uponReceiving("Upload operation")
.path("/files/upload")
.matchQuery("overwrite", "true")
.matchQuery("destination_filename", DESTINATION_FILENAME)
.withFileUpload("file",
".gitignore",
"multipart/form-data",
new byte[]{11,44,66,123,66}) // some bytes
.willRespondWith()
.status(201)
.body(responseBody)
.toPact();
}
Code for pact creation and verification:
#Test
#PactVerification
public void doTest() throws IOException {
String url = String.format("Http://localhost:%d/files/upload?overwrite=true&destination_filename=%s", PORT, DESTINATION_FILENAME);
// HttpEntity for request
HttpEntity multipart = MultipartEntityBuilder.create()
.setMode(HttpMultipartMode.BROWSER_COMPATIBLE)
.addBinaryBody("file", new byte[]{11,44,66,123,66},
ContentType.create("multipart/form-data"), ".gitignore")
.build();
// I make the request and get an answer
HttpResponse response = Request.Put(url)
.addHeader("Content-Type", "multipart/form-data;
boundary=j72BRjsEynnAqDw43KTlsjxoKWsjdF_tl6N5")
.body(multipart)
.execute()
.returnResponse();
String json = EntityUtils.toString(response.getEntity());
System.out.println("json=" + json);
JSONObject jsonObject = new JSONObject(json);
assertTrue(jsonObject.getString("code").equals("201"));
assertTrue(response.getStatusLine().getStatusCode() == 201);}
but when I run the test i get: json={"error": Missing start boundary}
java.lang.AssertionError: Pact Test function failed with an exception, possibly due to ExpectedButNotReceived(expectedRequests=[ method: PUT
path: /files/upload
query: [destination_filename:[test], overwrite:[true]]
headers: [Content-Type:multipart/form-data; boundary=iYxVLiQ0ZrP5g0SUP2pWa-rg20UM4JFe90p]
matchers: MatchingRules(rules={query=Category(name=query, matchingRules={overwrite=MatchingRuleGroup(rules=[RegexMatcher(regex=true, example=null)], ruleLogic=AND), destination_filename=MatchingRuleGroup(rules=[RegexMatcher(regex=test, example=null)], ruleLogic=AND)}), header=Category(name=header, matchingRules={Content-Type=MatchingRuleGroup(rules=[RegexMatcher(regex=multipart/form-data;(\s*charset=[^;]*;)?\s*boundary=.*, example=multipart/form-data; boundary=iYxVLiQ0ZrP5g0SUP2pWa-rg20UM4JFe90p)], ruleLogic=AND)}), path=Category(name=path, matchingRules={})})
generators: Generators(categories={})
body: OptionalBody(state=PRESENT, value=--iYxVLiQ0ZrP5g0SUP2pWa-rg20UM4JFe90p
Content-Disposition: form-data; name="file"; filename=".gitignore"
Content-Type: multipart/form-data
,B{B
--iYxVLiQ0ZrP5g0SUP2pWa-rg20UM4JFe90p--
)])
...
Caused by: org.json.JSONException: JSONObject["code"] not found.
Whats wrong in my code? I suppose something wrong with Content type, with 'boundary' part. But I dont know how to specify arbitrary boundary.
Maybe anybody knows another library where multipart/form-data uploading requests realized.
Thanks.
I found the solution from test example in DIUS library
contentType in .withFileUpload() and accordingly in .addBinaryBody() methods shouldn`t be "multipart/form-data". It may be "form-data" for example.
.addHeader in request method is not necessary because content type was already defined in body.

Empty soap envelope in WSO2 axis2 module

I'm working on custom axis2 module for wso2 esb. Right now I'm using code from https://docs.wso2.com/display/ESB490/Writing+an+Axis2+Module
and I have a problem with incoming requests. It doesn't matter what request I send because it always looks like this:
<?xml version='1.0' encoding='utf-8'?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"><soapenv:Body/></soapenv:Envelope>
On the other hand OutFlow works more or less as it should - response looks ok but instead of "out" its direction is set as "in". If I'm not mistaken invoke method will be called for requests and revoke for responses - am I right? In my case both are using invoke. Any ideas what I'm doing wrong?
Edit:
My handler code:
public class LogHandler extends AbstractHandler implements Handler {
private Logger log = Logger.getLogger(LogHandler.class.toString());
#Override
public void init(HandlerDescription handlerDescription) {
super.init(handlerDescription);
}
public InvocationResponse invoke(MessageContext msgContext) throws AxisFault {
System.out.println("invoked: " + msgContext.getEnvelope().toString() + "\n");
log.info("invoked: " + msgContext.getEnvelope().toString() + "\n");
return InvocationResponse.CONTINUE;
}
public void revoke(MessageContext msgContext) {
log.info("revoked: " + msgContext.getEnvelope().toString() + "\n");
}
}
Module:
public class LoggingModule implements Module {
private static final Log log = LogFactory.getLog(LoggingModule.class);
// initialize the module
public void init(ConfigurationContext configContext, AxisModule module) throws AxisFault {
}
public void engageNotify(AxisDescription axisDescription) throws AxisFault {
}
// shutdown the module
public void shutdown(ConfigurationContext configurationContext) throws AxisFault {
}
public String[] getPolicyNamespaces() {
return null;
}
public void applyPolicy(Policy policy, AxisDescription axisDescription) throws AxisFault {
}
public boolean canSupportAssertion(Assertion assertion) {
return true;
}
}
module.xml:
<module name="sample-logging" class="pl.wso2.logging.LoggingModule">
<InFlow>
<handler name="InFlowLogHandler" class="pl.wso2.logging.LogHandler">
<order phase="loggingPhase"/>
</handler>
</InFlow>
<OutFlow>
<handler name="OutFlowLogHandler" class="pl.wso2.logging.LogHandler">
<order phase="loggingPhase"/>
</handler>
</OutFlow>
</module>
In my wso2 proxy I use Payload Mediator to create response and then return it using Respond Mediator.
For given request:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header/>
<soapenv:Body>
<aa>blahblah</aa>
</soapenv:Body>
</soapenv:Envelope>
there two thing logged:
request from InFlow
invoked: <?xml version='1.0' encoding='utf-8'?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlso
ap.org/soap/envelope/"><soapenv:Body/></soapenv:Envelope>
and response from OutFlow
invoked: <?xml version='1.0' encoding='utf-8'?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlso
ap.org/soap/envelope/"><soapenv:Body><m:checkpriceresponse xmlns:m="http://services.samples/xsd"><m:
code>dsadsa</m:code></m:checkpriceresponse></soapenv:Body></soapenv:Envelope>
As per https://axis.apache.org/axis2/java/core/docs/modules.html#Step2_:_LogHandler ...
"public void invoke(MessageContext ctx);" is the method that is called
by the Axis2 engine when the control is passed to the handler. "public
void revoke(MessageContext ctx);" is called when the handlers are
revoked by the Axis2 engine."
which means since you are calling same handler in both InFlow and OutFlow the same invoke() method should be getting triggered for both the request and the response. If you want different logics to be executed for requests and responses maybe you should write separate handlers for request and response.
After debugging everything I've found that while request was parsed in InFlow, instead of using its soap message, new one (empty) was created. Thankfully it's possible to access proper request using soap tracer handler (or just its code).

How to access response payload content from custom handler in WSO2 APIM 1.9

How to access response payload content from custom handler in WSO2 APIM? I tried get this from org.apache.synapse.MessageContext or from org.apache.synapse.core.axis2.Axis2MessageContext; but I am not able get the response payload. Can anyone please help?
You need to build the message inside you handler before reading the payload, as shown below.
public boolean handleResponse(MessageContext messageContext) {
try {
RelayUtils.buildMessage(((Axis2MessageContext) messageContext).getAxis2MessageContext());
} catch (IOException e) {
e.printStackTrace();
} catch (XMLStreamException e) {
e.printStackTrace();
}
// read the body
log.info(messageContext.getEnvelope().getBody());
return true;
}
Refer [1] for a complete sample to build the message inside handler for API Manager 1.8.0. You need to put the correct dependencies in pom.xml for API Manager 1.9.0 (update both synapse-core & synapse-nhttp-transport version to 2.1.2-wso2v7)
[1] https://github.com/R-Rajkumar/samples/tree/master/message-builder-handler

Apache CXF Endpoint validation with Interceptor

What I want to do:
Implement a Camel route from a CXF Endpoint to an JMS queue with schema validation in CXF endpoint.
Validation is enabled in CXF endpoint:
/* Set endpoint properties */
Map<String, Object> propertiesMap = new HashMap<String, Object>();
propertiesMap.put("schema-validation-enabled", "true");
/* Create endpoint */
CxfEndpoint cxfEndpoint = new CxfEndpoint();
cxfEndpoint.setWsdlURL("wsdl/input.wsdl");
cxfEndpoint.setDataFormat(DataFormat.CXF_MESSAGE);
cxfEndpoint.setProperties(propertiesMap);
cxfEndpoint.getInInterceptors().add(new FaultInterceptor());
The Camel route:
from(cxfEndpoint)
.routeId("INPUT_ROUTE")
.to("jms:foo.bar");
The CXF interceptor:
public class FaultInterceptor extends AbstractSoapInterceptor {
private static final Logger LOGGER = Logger.getLogger(FaultInterceptor.class);
public FaultInterceptor() {
super(Phase.UNMARSHAL);
}
public void handleMessage(SoapMessage message) throws Fault {
LOGGER.info("handleMessage=" + message.getExchange().getInMessage());
}
#Override
public void handleFault(SoapMessage message) {
Fault fault = (Fault) message.getContent(Exception.class);
LOGGER.info("handleFault='" + fault + "'");
/* Add some header property that says the message is invalid */
}
}
Problem:
The works ok if I send a valid SOAP message. If I send an invalid SOAP message, the handleFault method kicks in, logs the fault and that's all.
For the invalid SOAP message scenario, is it possible that I can log the fault with handleFault method and still route the invalid message to the JMS queue?
This is the only interceptor I've added to the endpoint.
I'm using:
Apache ServiceMix 5.0.0
Apache Camel 2.12.3
Apache CXF 2.7.10
You can't do a try/catch statement since the error happends in the "from" clause.
However, you can use a Dead Letter Channel.
errorHandler(deadLetterChannel("jms:foo.bar.invalid"));
from(cxfEndpoint)
.routeId("INPUT_ROUTE")
.to("jms:foo.bar");

Calling web service fail from PL/SQL

I just want to call a web service from PL/SQL, so I create a web service :
http://localhost:64955/Service1.asmx?op=add
firstly, the web methods are very simple,like below:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Services;
namespace Calculator
{
/// <summary>
/// Summary description for Service1
/// </summary>
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
// To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line.
// [System.Web.Script.Services.ScriptService]
public class Service1 : System.Web.Services.WebService
{
[WebMethod]
public string HelloWorld()
{
return "Hello World";
}
[WebMethod]
public int add(int firstNum, int secondNum)
{
return firstNum + secondNum;
}
}
}
and I want to invoke the second method(add) in the web service, so I write my PL/SQL code like this:
declare
l_param_list varchar2(512);
l_http_request UTL_HTTP.req;
l_http_response UTL_HTTP.resp;
l_response_text varchar2(32000);
begin
-- service's input parameters
l_param_list := 'firstNum=1'||'&'||'secondNum=2';
--http://localhost:64955/Service1.asmx?op=add
--16.158.161.7
-- prepareint Request...
l_http_request := UTL_HTTP.begin_request ('http://localhost:64955/Service1.asmx?op=add'
,'POST'
,'HTTP/1.1');
--...set header's attributes
UTL_HTTP.set_header(l_http_request,'Content-Type', 'application/x-www-form-urlencoded');
UTL_HTTP.set_header(l_http_request,'Content-Length', length(l_param_list));
--...set input parameters
UTL_HTTP.write_text(l_http_request, l_param_list);
-- get response and obtain received value
l_http_response := UTL_HTTP.get_response(l_http_request);
UTL_HTTP.read_text(l_http_response, l_response_text);
dbms_output.put_line(l_response_text);
dbms_output.put_line('test1');
--finalizing
UTL_HTTP.end_response(l_http_response);
exception
when UTL_HTTP.end_of_body then
UTL_HTTP.end_response(l_http_response);
dbms_output.put_line('test2');
end;
But when I run this PL/SQL code segment, I got some exceptions:
<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><soap:Fault><soap:Code><soap:Value>soap:Receiver</soap:Value></soap:Code><soap:Reason><soap:Text xml:lang="en">System.Web.Services.Protocols.SoapException: Server was unable to process request. ---> System.Xml.XmlException: Root element is missing.
at System.Xml.XmlTextReaderImpl.Throw(Exception e)
at System.Xml.XmlTextReaderImpl.ThrowWithoutLineInfo(String res)
at System.Xml.XmlTextReaderImpl.ParseDocumentContent()
at System.Xml.XmlTextReaderImpl.Read()
at System.Xml.XmlTextReader.Read()
at System.Web.Services.Protocols.SoapServerProtocol.SoapEnvelopeReader.Read()
at System.Xml.XmlReader.MoveToContent()
at System.Web.Services.Protocols.SoapServerProtocol.SoapEnvelopeReader.MoveToContent()
at System.Web.Services.Protocols.SoapServerProtocolHelper.GetRequestElement()
at System.Web.Services.Protocols.Soap12ServerProtocolHelper.RouteRequest()
at System.Web.Services.Protocols.SoapServerProtocol.RouteRequest(SoapServerMessage message)
at System.Web.Services.Protocols.SoapServerProtocol.Initialize()
at System.Web.Services.Protocols.ServerProtocol.SetContext(Type type, HttpContext context, HttpRequest request, HttpResponse response)
at System.Web.Services.Protocols.ServerProtocolFactory.Create(Type type, HttpContext context, HttpRequest request, HttpResponse response, Boolean& abortProcessing)
--- End of inner exception stack trace ---</soap:Text></soap:Reason><soap:Detail /></soap:Fault></soap:Body></soap:Envelope>
test1
I am a beginner on the PL/SQL, so can anybody tell me what's wrong with my code?
BTW, the web service can be invoked normally from a windows form application.
The problem is that your webservice is SOAP , but you are not sending a SOAP request.
To do this, check the wsdl of your webservice, by browsing this URL http://localhost:64955/Service1.asmx?wsdl ,from there you will know how to create the SOAP envelop to call your webmethod.
you would do something like :
soap_request :=
'<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<m:add xmlns:m="Some-URI">
<firstNum>1</firstNum>
<secondNum>2</secondNum>
</m:add>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>';
l_http_request := UTL_HTTP.begin_request ('http://localhost:64955/Service1.asmx?op=add'
,'POST'
,'HTTP/1.1');
--...set header's attributes
UTL_HTTP.set_header(l_http_request,'Content-Type', 'application/xml');
UTL_HTTP.set_header(l_http_request,'Content-Length', length(soap_request));
--...set input parameters
UTL_HTTP.write_text(l_http_request, soap_request);
-- get response and obtain received value
l_http_response := UTL_HTTP.get_response(l_http_request);
UTL_HTTP.read_text(l_http_response, l_response_text);
dbms_output.put_line(l_response_text);
dbms_output.put_line('test1');
--finalizing
UTL_HTTP.end_response(l_http_response);