I have json messages like this:
{
"subject": "Enchanté"
"sender_name": "Rémi"
"sender_email" "foo#bar.com"
}
I'm using wso2 5.0.0 to send an email using MailTransportSender with something like this:
<property name="Subject" expression="json-eval($.subject)" scope="transport"/>
<property name="From" expression="fn:concat(json-eval($.sender_name), ' <', json-eval($.sender_email),'>')" scope="transport"/>
The smtp email is
From: Rémi <foo#bar.com>
Subject: =?UTF8?Q?Enchant=C3=A9?=
Note that wso2 correctly encodes the Subject: but not the FROM: . It should be :
From: =?UTF8?Q?R=C3=A9mi?= <foo#bar.com>
How to make wso2esb encode the sender_name as well (rfc2047) ?
Related
I'm developping a mediation flow in WSO2 Integration Studio. The indbound-endpoint is a rest api and the endpoints is a soap web service.
The client ask for a list of medical specialties.
The backend service respond with this list in SOAP response.
Simply converting SOAP response to JSON with a property mediator is not an option since the client wait for a specific JSON format.
I tried the script mediator without any success. Moreover i read that script mediator should be only used as a last chance solution.
What is the best practices to do this type of work? (convert soap to json with data collection in it)
SOAP Response is something like:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<GetSpecialtiesResponse xmlns="http://tempuri.org/">
<GetSpecialtiesResult xmlns:a="http://schemas.datacontract.org/2004/07/WsAgenda.DataContracts" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<a:Specialty>
<a:code>cardiology</a:code>
<a:name>Cardiologie</a:name>
</a:Specialty>
<a:Specialty>
<a:code>neurology</a:code>
<a:name>Neurologie</a:name>
</a:Specialty>
</GetSpecialtiesResult>
</GetSpecialtiesResponse>
</s:Body>
</s:Envelope>
Specific needed REST response format is something like:
{
"specialities": [
{
"id": "cardiology",
"name": "Cardiologie"
},
{
"id": "neurology",
"name": "Neurologie"
}
]
}
You can convert SOAP to JSON using below 2 properties.
<property name="ContentType"
scope="axis2"
type="STRING"
value="application/json"/>
<property name="messageType"
scope="axis2"
type="STRING"
value="application/json"/>
Output
{
"GetSpecialtiesResponse":{
"GetSpecialtiesResult":{
"Specialty":[
{
"code":"cardiology",
"name":"Cardiologie"
},
{
"code":"neurology",
"name":"Neurologie"
}
]
}
}
}
I am trying to create a Camel route that will:
Get JMS messages from a queue, the message body is a SOAP request.
Send the message to a cxf endpoint.
Put the response onto a response queue.
This is my code:
private void setupRequestRoute() {
from("jms:queue:input")
.setHeader(CxfConstants.OPERATION_NAME, simple("XXXXXX"))
.setHeader(CxfConstants.OPERATION_NAMESPACE, simple("XXXXXX"))
.log("Route headers : ${headers}")
.to("cxf:bean:myEndpoint")
.to("jms:queue:response")
.end();
}
Endpoint configuration:
<cxf:cxfEndpoint id="myServiceEndpoint"
address="http://localhost:8080/MyService/V2"
wsdlURL="schemas/MyService.wsdl"
xmlns:c="http://xxxx.xxxx/xxxxxxxx/XXX/MyService/V2">
<cxf:outFaultInterceptors>
<ref bean="interceptor.out.soap.fault"/>
</cxf:outFaultInterceptors>
<cxf:properties>
<entry key="schema-validation-enabled" value="true" />
<entry key="dataFormat" value="PAYLOAD" />
<entry key="defaultBus" value="true" />
<entry key="allowStreaming" value="false" />
</cxf:properties>
</cxf:cxfEndpoint>
I feel I've misunderstood something fundamental about camel works in this scenario. It appears to be the presence of the soap envelope that is causing this issue. I had presumed that camel would be able to take the raw soap message and convert it to the correct message format for the cxf endpoint.
Could someone explain to me how I can pass the SOAP request to the CXF endpoint?
2018-12-03 12:27:32,222 | ERROR | INPUT] | DefaultErrorHandler | 43 - org.apache.camel.camel-core - 2.16.4 | Failed delivery for (MessageId: ID:xxxxxxxxxxxx-46588-1543829293785-1:21:1:1:1
on ExchangeId: ID-xxxxxxxxxxxx-35264-1543835233229-2-1). Exhausted after delivery attempt: 1 caught: java.lang.IllegalArgumentException: The PayLoad elements cannot fit with the message parts of the BindingOpera
tion. Please check the BindingOperation and PayLoadMessage.
Message History
---------------------------------------------------------------------------------------------------------------------------------------
RouteId ProcessorId Processor Elapsed (ms)
[from.XS.to.xsb?dat] [from.XS.to.xsb?dat] [jms://queue:input ] [ 17]
[from.XS.to.xsb?dat] [setHeader7 ] [setHeader[operationName] ] [ 0]
[from.XS.to.xsb?dat] [setHeader8 ] [setHeader[operationNamespace] ] [ 0]
[from.XS.to.xsb?dat] [log6 ] [log ] [ 12]
[from.XS.to.xsb?dat] [to45 ] [cxf:bean:myEndpoint ] [ 3]
Exchange
---------------------------------------------------------------------------------------------------------------------------------------
Exchange[
Id ID-xxxxxxxxxxxx-35264-1543835233229-2-1
ExchangePattern InOut
Headers {breadcrumbId=ID:xxxxxxxxxxxx-46588-1543829293785-1:21:1:1:1, CamelRedelivered=false, CamelRedeliveryCounter=0, JMSCorrelationID=null, JMSCorrelationIDAsBytes=null, JMSDeliveryMode=2,
JMSDestination=queue://input, JMSExpiration=0, JMSMessageID=ID:xxxxxxxxxxxx-46588-1543829293785-1:21:1:1:1, JMSPriority=4, JMSRedelivered=false, JMSReplyTo=queue://response, JMSTimestamp=1543840052184, JMSType=null, JMSXGroupID=null, JMSXUserID=null, operationName=MyOperation, operationNamespace=MyOperationNameSpace}
BodyType String
Body <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:v2="http://xxxx.xxxx/xxxxxxxx/xxx/xxxxxxxxxxxxxxxxxx/V2" xmlns:v21="http://xxxx.xxxx/xxxxxxxx/xxx/xxxxxx/V2">
<soapenv:Header><wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecur
ity-utility-1.0.xsd"><wsse:UsernameToken wsu:Id="UsernameToken-xxxx"><wsse:Username>username</wsse:Username><wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-ws
s-username-token-profile-1.0#PasswordDigest">xxxx</wsse:Password><wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">
xxxxx</wsse:Nonce><wsu:Created>2018-12-03T12:27:32.183Z</wsu:Created></wsse:UsernameToken></wsse:Security></soapenv:Header> <soapenv:Body> <v2:MyRequest>
...
...
</v2:MyRequest> </soapenv:Body></soapenv:Envelope>
]
Stacktrace
Stacktrace
---------------------------------------------------------------------------------------------------------------------------------------
java.lang.IllegalArgumentException: The PayLoad elements cannot fit with the message parts of the BindingOperation. Please check the BindingOperation and PayLoadMessage.
at org.apache.camel.component.cxf.CxfEndpoint$CamelCxfClientImpl.setParameters(CxfEndpoint.java:1189)[44:org.apache.camel.camel-cxf:2.16.4]
at org.apache.cxf.endpoint.ClientImpl.doInvoke(ClientImpl.java:470)[57:org.apache.cxf.cxf-core:3.1.5]
at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:416)[57:org.apache.cxf.cxf-core:3.1.5]
at org.apache.camel.component.cxf.CxfProducer.process(CxfProducer.java:134)[44:org.apache.camel.camel-cxf:2.16.4]
at org.apache.camel.processor.SendProcessor.process(SendProcessor.java:145)[43:org.apache.camel.camel-core:2.16.4]
at org.apache.camel.management.InstrumentationProcessor.process(InstrumentationProcessor.java:77)[43:org.apache.camel.camel-core:2.16.4]
at org.apache.camel.processor.RedeliveryErrorHandler.process(RedeliveryErrorHandler.java:460)[43:org.apache.camel.camel-core:2.16.4]
at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:196)[43:org.apache.camel.camel-core:2.16.4]
at org.apache.camel.processor.Pipeline.process(Pipeline.java:121)[43:org.apache.camel.camel-core:2.16.4]
at org.apache.camel.processor.Pipeline.process(Pipeline.java:83)[43:org.apache.camel.camel-core:2.16.4]
at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:196)[43:org.apache.camel.camel-core:2.16.4]
at org.apache.camel.util.AsyncProcessorHelper.process(AsyncProcessorHelper.java:109)[43:org.apache.camel.camel-core:2.16.4]
at org.apache.camel.processor.DelegateAsyncProcessor.process(DelegateAsyncProcessor.java:91)[43:org.apache.camel.camel-core:2.16.4]
at org.apache.camel.component.jms.EndpointMessageListener.onMessage(EndpointMessageListener.java:112)[46:org.apache.camel.camel-jms:2.16.4]
at org.springframework.jms.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:555)[154:org.apache.servicemix.bundles.spring-jms:3.2.17.RELEASE_1]
at org.springframework.jms.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:515)[154:org.apache.servicemix.bundles.spring-jms:3.2.17.RELEASE_1]
at org.springframework.jms.listener.AbstractMessageListenerContainer.doExecuteListener(AbstractMessageListenerContainer.java:485)[154:org.apache.servicemix.bundles.spring-jms:3.2.17.RELEASE_1]
at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.doReceiveAndExecute(AbstractPollingMessageListenerContainer.java:325)[154:org.apache.servicemix.bundles.spring-jms:3.2.17.RELEASE_1]
at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.receiveAndExecute(AbstractPollingMessageListenerContainer.java:263)[154:org.apache.servicemix.bundles.spring-jms:3.2.17.RELEASE_1]
at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.invokeListener(DefaultMessageListenerContainer.java:1103)[154:org.apache.servicemix.bundles.spring-jms:3.2.17.RELEASE_1]
at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.executeOngoingLoop(DefaultMessageListenerContainer.java:1095)[154:org.apache.servicemix.bundles.spring-jms:3.2.17.RELEASE_1]
at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.run(DefaultMessageListenerContainer.java:992)[154:org.apache.servicemix.bundles.spring-jms:3.2.17.RELEASE_1]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)[:1.8.0_181]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)[:1.8.0_181]
at java.lang.Thread.run(Thread.java:748)[:1.8.0_181]
You specify PAYLOAD data format, but according to the docs that is for soap:body processing. Can you XPath out the body into the current exchange, or do you need all the WSE headers?
Or try one of the other data formats MESSAGE (called RAW in later versions I think?) or CXF_MESSAGE sound like they are closer to what you're trying to achieve.
Details : I have created on flow in MuleESB which is calling a web-service without any parameter just sending it username, password and token in a property and it is working fine.
But the second API I want to post some parameters while calling soap request but I don't know how to use it I tried to pass through set payload but no response.
<http:listener-config name="HTTP_Listener_Configuration" host="0.0.0.0" port="8081" doc:name="HTTP Listener Configuration"/>
<http:request-config name="HTTP_Request_Configuration" host="webservicehostadd" port="443" doc:name="HTTP Request Configuration">
<http:basic-authentication username="username" password="pass"/>
</http:request-config>
<ws:consumer-config name="Web_Service_Consumer" wsdlLocation="https://xxxx/1.0?wsdl" service="xxx" port="xxxx" serviceAddress="https://xxxxx/1.0" connectorConfig="HTTP_Request_Configuration" doc:name="Web Service Consumer"/>
<flow name="mycustomflow">
<http:listener config-ref="HTTP_Listener_Configuration" path="/TEST" doc:name="HTTP"/>
<set-property propertyName="APIKey" value="xxx-xxx-xxx-xxx-xxx" doc:name="Property"/>
<dw:transform-message doc:name="Transform Message" metadata:id="xxx-xxx-xxx-xxx-xxxxxxxx">
<dw:input-payload mimeType="application/xml"/>
<dw:set-payload><![CDATA[%dw 1.0
%output application/xml
%namespace ns0 http://localhost/getDetails:getDetailsWSD
---
{
ns0#getDetails: {
getDetailsOrder: {
ID: payload.ns0#getDetails.getDetailsOrder.ID,
AllData: payload.ns0#getDetails.getDetailsOrder.AllData
}
}
}]]></dw:set-payload>
</dw:transform-message>
<ws:consumer config-ref="Web_Service_Consumer" operation="employeeDetails" doc:name="Web Service Consumer"/>
</flow>
It showed the below error:
Exception while executing:
[row,col]: [1,1]
Unexpected character '{' (code 123) in prolog; expected '<'
at [row,col {unknown-source}]: [1,1].
Updated answer:
<dw:transform-message metadata:id="XXXXX" doc:name="Transform Message">
<dw:set-payload><![CDATA[
%output application/xml skipNullOn="everywhere"
%namespace ns0 localhost/getDetails:getDetailsWSD
---
{
ns0#getDetails: {
getDetailsOrder: {
ID: payload.ns0#getDetails.getDetailsOrder.ID,
AllData: payload.ns0#getDetails.getDetailsOrder.AllData
}
}
}]]>
</dw:set-payload>
</dw:transform-message>
In your scenario: you are passing a body in XML format and sometimes an empty body in your Postman requests.
Passing an empty body results your payload to be {NullPayload}. To handle this, we have to remove explicitly defining the input mime type: <dw:input-payload mimeType="application/xml"/>.
In your transformation: ID: payload.ns0#getDetails.getDetailsOrder.ID,. You are retrieving a value from an empty payload and this will fail. To avoid failing, we have added: skipNullOn="everywhere". You can read more about it here.
I have tried the transformation myself which results to this:
<?xml version='1.0' encoding='UTF-8'?>
<ns0:getDetails xmlns:ns0="http://localhost/getDetails:getDetailsWSD">
<getDetailsOrder/>
</ns0:getDetails>
I think we are done with your initial issue regarding transformation of your empty payload. Your concern now is consuming the web service.
Thank you.
I have created my proxy with custom url, based on:
http://wso2.com/library/knowledge-base/2011/01/custom-urls-wso2-esb-proxy-services/
Calling this custom URL with my SOAP message results in an error, I can still use the original url.
custom: /services/wss/PlanningOphaalServiceProxy_v1
original: /services/PlanningOphaalServiceProxy_v1
The error:
TID: [0] [ESB] [2015-08-19 15:47:05,039] ERROR {org.apache.axis2.engine.AxisEngine} - InvalidSecurity {org.apache.axis2.engine.AxisEngine}
org.apache.axis2.AxisFault: InvalidSecurity
at org.apache.rampart.handler.PostDispatchVerificationHandler.invoke(PostDispatchVerificationHandler.java:151)
at org.apache.axis2.engine.Phase.invokeHandler(Phase.java:340)
at org.apache.axis2.engine.Phase.invoke(Phase.java:313)
at org.apache.axis2.engine.AxisEngine.invoke(AxisEngine.java:261)
at org.apache.axis2.engine.AxisEngine.receive(AxisEngine.java:167)
at org.apache.synapse.transport.passthru.ServerWorker.processEntityEnclosingRequest(ServerWorker.java:411)
at org.apache.synapse.transport.passthru.ServerWorker.run(ServerWorker.java:183)
at org.apache.axis2.transport.base.threads.NativeWorkerPool$1.run(NativeWorkerPool.java:172)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
TID: [0] [ESB] [2015-08-19 15:47:05,041] ERROR {org.apache.synapse.transport.passthru.ServerWorker} - Error processing POST request for : /services/wss/PlanningOphaalServiceProxy_v1 {org.apache.synapse.transport.passthru.ServerWorker}
org.apache.axis2.AxisFault: InvalidSecurity
Solved: This is not possible. CustomURI does not work in combination with WS-Security, according to WSO2 SUpport
I tried Custom URI and working fine after adding custom dispatched in axis2.xml
below is URI for my proxy
http://localhost:8280/GenericProxy
and Proxy code as below:
<?xml version="1.0" encoding="UTF-8"?>
<proxy xmlns="http://ws.apache.org/ns/synapse"
name="CustomProxy"
transports="https,http"
statistics="disable"
trace="disable"
startOnLoad="true">
<target>
<inSequence>
<property name="messageType"
value="application/xml"
scope="default"
type="STRING"/>
<log level="full">
<property name="################## Body - In Seq###################"
expression="$body"/>
</log>
<send>
<endpoint>
<address uri="http://localhost:8090/services/OracleStoredProcedure.SOAP12Endpoint/"/>
</endpoint>
</send>
</inSequence>
<outSequence>
<log level="full">
<property name="############## Res Seq ############" value="Response"/>
</log>
</outSequence>
</target>
<parameter name="ServiceURI">/GenericProxy</parameter>
<description/>
</proxy>
And logs as below
[2015-08-21 16:35:25,173] INFO - ProxyService Successfully created the Axis2 se
rvice for Proxy service : CustomProxy
[2015-08-21 16:35:41,405] INFO - LogMediator To: /GenericProxy, MessageID: urn:
uuid:8e35439e-4d28-95be-4e25eb385843, Direction: request, #################
# Body - In Seq################### = <soapenv:Body xmlns:soapenv="http://schemas
.xmlsoap.org/soap/envelope/"><emp>
<ID>sample</ID>
</emp></soapenv:Body>, Envelope: <?xml version="1.0" encoding="utf-8"?><soapenv:
Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"><soapenv:Body
><emp>
<ID>sample</ID>
</emp></soapenv:Body></soapenv:Envelope>
[2015-08-21 16:35:42,200] INFO - LogMediator To: http://www.w3.org/2005/08/addr
essing/anonymous, WSAction: , SOAPAction: , MessageID: urn:uuid:0431fb5f-4b03-47
41-727bdb3637d8, Direction: response, ############## Res Seq ############ =
Response, Envelope: <?xml version="1.0" encoding="utf-8"?><soapenv:Envelope xml
ns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"><soapenv:Body><soapenv:En
velope>
I am trying to write configure a gateway, which should take a complete SOAP Message and then delegate it to another SOAP Provider (incl. all SOAP headers of the first request).
What I have done so far:
1) web.xml
MessageDispatcherServlet with Mapping:
<servlet-mapping>
<servlet-name>spring-ws</servlet-name>
<url-pattern>/appservices/*</url-pattern>
</servlet-mapping>
2) Configuration with an Endpoint-Mapping
<bean class="org.springframework.ws.server.endpoint.mapping.UriEndpointMapping">
<property name="defaultEndpoint" ref="ws-in-gw"/>
</bean>
3) Configuration of Spring Integration inbound-gateway and outbound-gateway
<int-ws:inbound-gateway id="ws-in-gw"
request-channel="in"
reply-channel="out"
mapped-request-headers="*" />
<int:channel id="in" />
<int:channel id="out" />
<int-ws:outbound-gateway
id="ws-out-gw-status"
request-channel="in-status"
reply-channel="out-status"
uri="http://${delegationServer}/${delegation.contextroot}/soap/AnotherService"
interceptor="soapEnricher"
</int-ws:outbound-gateway>
<bean id="soapEnricher" class="foo.bar.SoapHeaderEnricher" />
public class SoapHeaderEnricher implements ClientInterceptor {
#Override
public boolean handleRequest(MessageContext messageContext) throws WebServiceClientException {
try {
SoapMessage soapMessage = (SoapMessage) messageContext.getRequest();
SoapHeader sh = soapMessage.getSoapHeader();
// can use sh.addHeaderElement(new QName(...)) now, but where are the original Headers???
} catch () {
}
}
My first Problem was, that the original SOAP Headers had been cut of, so I introduced the ' mapped-request-headers="*" ' attribute at the inbound gateway.
When I now configure a wire-tap, I see the Headers (myToken:MySecretToken) are received:
DEBUG 10:46:53 - [Payload DOMSource content=javax.xml.transform.dom.DOMSource#24a6ce98][Headers={errorChannel=org.springframework.messaging.core.GenericMessagingTemplate$TemporaryReplyChannel#43456ff4, myToken:MySecretToken=org.springframework.ws.soap.saaj.SaajSoapHeaderElement#3b91ead, ...}]
This is the SOAP Message for my test:
<soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:stat="http://status.service.promakler.provinzial.com/">
<soapenv:Header>
<myToken:MySecretToken xmlns=""
xmlns:myToken="http://foo.bar">12345</myToken:MySecretToken>
</soapenv:Header>
<soapenv:Body>
<stat:getStatus/>
</soapenv:Body>
</soapenv:Envelope>
So the Headers are now in my Message, but in the ClientInterceptor, there is no way to get the Headers (just the payload)?! I can add new Headers, but how can I get the original Header?
Can anybody give me a hint (or perhaps there is even a quiet simpler solution??)
Regards
Timo
Try to introduce a custom extension of DefaultSoapHeaderMapper and override populateUserDefinedHeader to extract those SaajSoapHeaderElement from the MessageHeaders and populate them to the SoapHeader. And finally inject your solution to the header-mapper of your <int-ws:outbound-gateway>.