Propagate SOAPFault with simple Camel proxy - web-services

I'm trying to create a simple WS proxy using Switchyard 1.1 with Camel:
--> PromotedService --> Camel --> ProxifiedService
With the current configuration I'm able to send and recieve messages without any problem.
However, when the ProxifiedService throws a SoapFault it is not propagated to the caller of the PromotedService.
What can I do to ensure the the PromotedServiceCaller receives the SOAPFault as reponse?
This is what I have tried so far:
onException(Exception.class)
.process(
new Processor() {
public void process(Exchange exchange) throws Exception {
SoapFault fault = exchange.getProperty(Exchange.EXCEPTION_CAUGHT, SoapFault.class);
System.out.println("Fault: " + fault); // --> This returns NULL
Exception excep = exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Exception.class);
System.out.println("excep: " + excep);
System.out.println("excep message: " + excep.getMessage());
System.out.println("excep cause: " + excep.getCause());
SoapFault SOAP_FAULT = new SoapFault(excep.getMessage(), SoapFault.FAULT_CODE_CLIENT);
Element detail = SOAP_FAULT.getOrCreateDetail();
Document doc = detail.getOwnerDocument();
Text tn = doc.createTextNode("this is a test");
detail.appendChild(tn);
exchange.getOut().setFault(true);
exchange.getOut().setBody(SOAP_FAULT);
exchange.setProperty(Exchange.ERRORHANDLER_HANDLED, false);
exchange.removeProperty("CamelExceptionCaught");
}
})
.handled(true)
.end();
from("switchyard://PromotedService")
.process(myProc) // --> I just add some headers here to the original request.
.handleFault()
.to("switchyard://ProxifiedService").end();
This is the SOAPFault generated by the ProxifiedService:
<soapenv:Envelope xmlns:ser="http://service.admin.ws.my.company/" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header>
</soapenv:Header>
<soapenv:Body>
<soapenv:Fault>
<faultcode>soapenv:Server</faultcode>
<faultstring>Missing valid token.</faultstring>
</soapenv:Fault>
</soapenv:Body>
And this the message the caller is really receiving:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header/>
<soap:Body>
<soap:Fault>
<faultcode>soap:Server</faultcode>
<faultstring>org.switchyard.HandlerException: org.apache.cxf.binding.soap.SoapFault: javax.xml.transform.dom.DOMSource#663dcb96</faultstring>
</soap:Fault>
</soap:Body>
</soap:Envelope>
Thank you!

onException() only takes Throwable. In your code the argument is SoapFault which is not Throwable.
This will work
onException(SOAPException.class)

Related

How to get Message count in Topic in WSO2 MB using AdminServices

To get the message count from topic, I have invoked the WSO2 MB 3.1.0 AdminService api calls. It worked for queue but not for the topic. When invoking with topic, it doesn't give the correct count (it always gives 0)
(To show the message count in topic in WSO2 MB Management console, I have created an inbound endpoint with suspend state in WSO2 ESB and created a durable subscription to the topic)
Get Message Count from queue.
url:https://localhost:9447/services/AndesAdminService.AndesAdminServiceHttpsSoap12Endpoint
Request body:
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsd="http://wso2.org/carbon/andes/admin/xsd">
<soap:Header/>
<soap:Body>
<xsd:getMessageCount>
<!--Optional:-->
<xsd:destinationName>test-queue</xsd:destinationName>
<!--Optional:-->
<xsd:msgPattern>**queue**</xsd:msgPattern>
</xsd:getMessageCount>
</soap:Body>
</soap:Envelope>
Get Message Count from topic.
url:https://localhost:9447/services/AndesAdminService.AndesAdminServiceHttpsSoap12Endpoint
Request body:
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsd="http://wso2.org/carbon/andes/admin/xsd">
<soap:Header/>
<soap:Body>
<xsd:getMessageCount>
<!--Optional:-->
<xsd:destinationName>mytopic</xsd:destinationName>
<!--Optional:-->
<xsd:msgPattern>**topic**</xsd:msgPattern>
</xsd:getMessageCount>
</soap:Body>
</soap:Envelope>
I set the messagePattern as "topic" to get the message count in the topic. Is this not correct? If so whats the correct way of getting the message count in a topic using Admin services.
Reference:
https://docs.wso2.com/display/MB310/Calling+Admin+Services+from+Apps
There is no way to get message count of topics. Topics are supposed to be real time and there is no meaning to a message count in a "topic".
However, if you are looking for a message count remaining in a "durable topic", you can pass below information and get the message count.
queuename = carbon:{subscription ID}
, msgPattern = queue
Relevant code
public long getMessageCount(String queueName, String msgPattern) throws MBeanException {
if (log.isDebugEnabled()) {
log.debug("Counting at queue : " + queueName);
}
long messageCount = 0;
try {
if (!DLCQueueUtils.isDeadLetterQueue(queueName)) {
if ("queue".equals(msgPattern)) {
messageCount = Andes.getInstance().getMessageCountOfQueue(queueName);
}
} else {
messageCount = Andes.getInstance().getMessageCountInDLC(queueName);
}
} catch (AndesException e) {
log.error(MESSAGE_COUNT_RETRIEVE_ERROR + queueName, e);
throw new MBeanException(e, MESSAGE_COUNT_RETRIEVE_ERROR + queueName);
}
return messageCount;
}

Delphi SOAP Request

I'm trying to send a SOAP Request to a webservice in Delphi XE5. Actually there is a WSDL available which I imported via WSDL Importer. I established a connection to this webservice with the components THTTPRIO (rio) and IdEncoderMIME1 for the HTTP Authentication Request.
The SOAP Request was build via TXMLDocument and has the following structure:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:cod=NS_Codelist>
<soapenv:Header/>
<soapenv:Body>
<cod:GetLatestChangeDatesRequest>
<!--Zero or more repetitions:-->
<CodeListID>1035</CodeListID>
</cod:GetLatestChangeDatesRequest>
</soapenv:Body>
</soapenv:Envelope>
Furthermore I received the Porttype of the webservice.
codeserv:= GetCodeListPortType(true,'',rio);
These are methods from the WSDL:
codeserv.GetLatestChangeDates(const body:GetLatestChangeDatesRequestType):GetLatestChangeDatesResponseType
GetLatestChangeDatesRequestType = array of Int64;
GetLatestChangeDatesRequest = GetLatestChangeDatesRequestType;
GetLatestChangeDatesResponseType = array of CodeListLatestChangeDateType;
GetLatestChangeDatesResponse = GetLatestChangeDatesResponseType;
CodeListLatestChangeDateType
property CodeListID: Int64
property LatestChangeDate: TXSDate
I have already tried to set an array of Int64 for the parameter but then it says "element CodeListID is missing".
Unfortunately I don't find a way to send this XML SOAP Request to the webservice and to receive the response. Any ideas?
EDIT: I have tried to use the WSDL methods
var
codeserv: CodeListPortType;
arrIDs: GetLatestChangeDatesRequest;
response: GetLatestChangeDatesResponse;
begin
codeserv:= GetCodeListPortType(true,'',rio);
SetLength(arrIDs,1);
arrIDs[0]:= 1035;
response:= codeserv.GetLatestChangeDates(arrIDs);
But then I receive the following error message: 'invalid content was found starting with element 'long'. One of '{CodeListID}' is expected.'
In the SOAP Request there have to be the element CodeListID. Unfortunately it seems the method GetLatestChangeDates isn't creating the elements in the SOAP Request. The SOAP Request posted above should have been created with this method (hopefully).

Change JAX-WS output namespace prefix

The web service that calls us expects us to return the following XML:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:loc="http://www.csapi.org/schema/parlayx/sms/notification/v2_2/local">
<soapenv:Header />
<soapenv:Body>
<loc:notifySmsDeliveryReceiptResponse />
</soapenv:Body>
</soapenv:Envelope>
We use JAX-WS to provide our web service. The following is how we define our web service interface:
#BindingType(value = javax.xml.ws.soap.SOAPBinding.SOAP11HTTP_MTOM_BINDING)
#WebService (targetNamespace = "http://www.csapi.org/schema/parlayx/sms/notification/v2_2/local")
#HandlerChain(file = "deliverysoaphandler.xml")
#SOAPBinding(style = Style.DOCUMENT)
public interface DeliveryService {
#WebMethod ()
public void notifySmsReception(
#WebParam(name = "correlator", targetNamespace = "http://www.csapi.org/schema/parlayx/sms/notification/v2_2/local") #XmlElement(required = true) String correlator,
#WebParam(name = "message", targetNamespace = "http://www.csapi.org/schema/parlayx/sms/notification/v2_2/local") #XmlElement(required = true) Message message
) throws DeliveryException;
}
This produces the following return document:
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header/>
<S:Body>
<ns2:notifySmsReceptionResponse xmlns:ns2="http://www.csapi.org/schema/parlayx/sms/notification/v2_2/local"/>
</S:Body>
</S:Envelope>
We think the document is essential the same as what the calling system expects but gets rejected because 1) the namespaces are capitalized, 2) the same namespace reference is repeated and 3) there is a namespace declaration in the middle of the document.
Is there anyway in which I can persuade the JAX-WS provider to produce what the other system wants?
Based on this description, I am not sure the namespaces are the problem.
The service consumer is expecting:
<soapenv:Body>
<loc:notifySmsDeliveryReceiptResponse />
</soapenv:Body>
but is receiving
<S:Body>
<ns2:notifySmsReceptionResponse xmlns:ns2="..."/>
</S:Body>
which indicates a response to a different operation name.
Try changing your service endpoint interface WebMethod method name to:
#WebMethod ()
public void notifySmsDeliveryReceipt(
Doing so will require you to also change the method name on the implementation class (or it will no longer compile).
Alternatively, you can also just change your #WebMethod to the desired/indicated operation name:
#WebMethod (operationName="notifySmsDeliveryReceipt")
public void notifySmsReception(
The service should now produce:
<S:Body>
<ns2:notifySmsDeliveryReceiptResponse xmlns:ns2="http://www.csapi.org/schema/parlayx/sms/notification/v2_2/local"/>
</S:Body>

Soapui property transfer to request header

I want to set the value of token in this soap ws header
<soapenv:Enveloppe ...
<soapenv:Header>
<web:token>123456 </web:token>
FROM step named test get idSession in response
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<ns1:authentification xmlns:ns1="http://ws.demowebservices.com/">
<bloc1>
<bloc2>
<idSession>e1c64cd9-b933-4f56-ae1f-0f7d7f23942b</idSession>
</bloc2>
I tried to put in-between web:token tag
${test#Response#//ns1:authentification/bloc1/bloc2/idSession}
but it does not work
What should I put instead ?
I'm not sure if this is what you're trying to achieve, however If you have a SOAP Test step called Test Request and you want to use the value of the <soapenv:Header><web:token></soapenv:Header> of this request in another SOAP Test step you can refer this value in the second SOAP Test step request using the follow syntax:
<soapenv:Enveloppe ...
<soapenv:Header>
<web:token>${Test Request#Request#//soapenv:Header/web:token}</web:token>
The syntax ${Test Request#Request#//soapenv:Header/web:token} has three parts, the name of the test step, followed by the property (could be #Request or #Response), and finally the xpath to get the value //soapenv:Header/web:token.
UPDATED:
As you said you've two SOAP Test Request, the first one is called test an has the follow response:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<ns1:authentification xmlns:ns1="http://ws.demowebservices.com/">
<bloc1>
<bloc2>
<idSession>e1c64cd9-b933-4f56-ae1f-0f7d7f23942b</idSession>
</bloc2>
</bloc1>
</ns1:authentification>
</soap:Body>
</soap:Envelope>
The second is named for example test 2 (don't care because the second name not affect your purpose) and has the follow request:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header>
<web:token>${test#Response#//ns1:authentification/bloc1/bloc2/idSession}</web:token>
</soapenv:Header>
<soapenv:Body>
...
</soapenv:Body>
</soapenv:Envelope>
With ${test#Response#//ns1:authentification/bloc1/bloc2/idSession} you're referencing the idSession value of the test response correctly. Take a look on the http log tab when you send your test 2 as shown in the follow image:
Hope this helps,

adding security details to soap header in spring client

I am trying to consume SOAP (external system) web service using Spring WS template as client.
I need to pass header information(security details) as header along with the soap message.
I tried adding that information into Header using java xml SOAPMessage(javax.xml.soap.SoapMessage) and trying to convert it into spring SOAPMessage(org.springframework.ws.soap.SoapMessage) later after adding header details.
but its not able to cast it, getting class cast exception as both of them are not in heirarchy.
please help me on how to pass security details on header info in spring soap message
My code is as below
public void doWithMessage(WebServiceMessage message) throws IOException,
TransformerException
SaajSoapMessage saajSoapMessage =(SaajSoapMessage)message;
SOAPMessage soapMessage = saajSoapMessage.getSaajMessage();
SOAPPart soapPart = soapMessage.getSOAPPart();
SOAPEnvelope soapEnvelope = soapPart.getEnvelope();
SOAPHeader soapHeader = soapEnvelope.getHeader();
Name headerElementName = soapEnvelope.createName("Security","wsse","http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
// Add "Security" soapHeaderElement to soapHeader
SOAPHeaderElement soapHeaderElement = soapHeader.addHeaderElement(headerElementName);
// This may be important for some portals!
soapHeaderElement.setActor(null);
// Add usernameToken to "Security" soapHeaderElement
SOAPElement usernameTokenSOAPElement = soapHeaderElement.addChildElement("UsernameToken");
// Add username to usernameToken
SOAPElement userNameSOAPElement = usernameTokenSOAPElement.addChildElement("Username");
userNameSOAPElement.addTextNode("myUserName");
// Add password to usernameToken
SOAPElement passwordSOAPElement = usernameTokenSOAPElement.addChildElement("Password");
passwordSOAPElement.addTextNode("myPassword");
((SoapMessage) soapMessage).setSoapAction("GetMetaDataLookUpRequestType");//exception while casting
}
And my request xml is as below
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:v1="http://emc.com/it/enterprise/contract/CMCContractLookupService/v1" xmlns:v11="http://emc.com/it/enterprise/data/v1">
<soapenv:Header>
<wsse:Security soapenv:mustUnderstand="1"
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-wssecurity-utility-1.0.xsd">
<wsse:UsernameToken wsu:Id="UsernameToken-20">
<wsse:Username>xxxx</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">xxxx</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
</soapenv:Header>
<soapenv:Body>
<v1:GetContractMetaDataLookUpRequest>
<v11:GetMetaDataLookUpRequestDocument>
<v11:ContractID>123456</v11:ContractID>
<v11:BadgeID>1</v11:BadgeID>
</v11:GetMetaDataLookUpRequestDocument>
</v1:GetContractMetaDataLookUpRequest>
</soapenv:Body>
</soapenv:Envelope>
I need help mainly on how can i add that header info(as shown in above xml request) into soap header message.
help is greatly appreciated. thank you.
This should be saajSoapMessage.setSoapAction("GetMetaDataLookUpRequestType") instead of ((SoapMessage)soapMessage).setSoapAction("GetMetaDataLookUpRequestType").