Apache CXF transform xml to SoapMessage for Unit-Tests - unit-testing

I want to create a small Unit-Test for an AbstractSoapInterceptor like this:
public class SimpleInterceptorTest {
private SimpleInterceptor simpleInterceptor;
#BeforeMethod
public void setUp() {
simpleInterceptor = new SimpleInterceptor();
}
#Test
public void testHandleMessage() throws Exception {
SoapMessage soapMessage = createSoapMessage("requests/sampleRequest.xml");
simpleInterceptor.handleMessage(soapMessage);
// Assertions
}
}
requests/sampleRequest.xml is a Soap-Request like:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<soap:Header>
<wsse:Security>
<wsc:SecurityContextToken xmlns:wsc="http://schemas.xmlsoap.org/ws/2005/02/sc" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="sct">
<wsc:Identifier>abcd</wsc:Identifier>
</wsc:SecurityContextToken>
</wsse:Security>
</soap:Header>
<soap:Body>
<wst:RequestSecurityToken xmlns:wst="http://schemas.xmlsoap.org/ws/2005/02/trust" >
<wst:TokenType>http://schemas.xmlsoap.org/ws/2005/02/sc/sct</wst:TokenType>
<wst:RequestType>http://schemas.xmlsoap.org/ws/2005/02/trust/Validate</wst:RequestType>
<wst:ValidateTarget>
<wsse:SecurityTokenReference>
<wsse:Reference URI="#sct"/>
</wsse:SecurityTokenReference>
</wst:ValidateTarget>
</wst:RequestSecurityToken>
</soap:Body>
</soap:Envelope>
Now I have the following questions:
Is this the right way to test Interceptors?
If yes, how to implement
the method createSoapMessage?

Here is an example how Unit-Tests for Apaches interceptors look like:
https://github.com/apache/cxf/blob/master/rt/wsdl/src/test/java/org/apache/cxf/wsdl/interceptors/DocLiteralInInterceptorTest.java
Therefore it is possible to implement the createSoapMessage method, but not as simple as wished.
I would be very grateful for easier solutions.
For now, I test the interceptors with SoapUI.

Related

How to add header parameter in SOAP web services as a WS producer in java

I am new to java web service. I want to add headers to my web service I tried to add #WebParam(name = "noun", header = true) in my input parameters of web method. I tried something like . I need an example with the below XML format of output. Can someone please help me to add the authentication info in header part.
// Sample XML
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ser="http://service.reports.cfr.nesl.com/">
<soapenv:Header>
<AuthenticationInfo>
<userName>User</userName>
<password>password<password/>
</AuthenticationInfo>
</soapenv:Header>
<soapenv:Body>
<ser:getCreditFacilReport>
<arg0>
<!--Optional:-->
<info_type>?</info_type>
<!--Optional:-->
<info_value>?</info_value>
<!--Optional:-->
<output_type>?</output_type>
<!--Optional:-->
<requester_pan>?</requester_pan>
</arg0>
</ser:getCreditFacilReport>
</soapenv:Body>
</soapenv:Envelope>
===========The below java code which i have without header param==================
// Service implements calss
#WebService(endpointInterface = "com.nesl.cfr.reports.service.CreditFacilReportService")
public class CreditFacilReportServiceImpl implements CreditFacilReportService
{
#Override
public CreditFacilReportResponseBean getCreditFacilReport(CreditFacilReportRequestBean requestbean)
{
/*
....
....
*/
}
}
//Service class
#WebService
#SOAPBinding(style=SOAPBinding.Style.RPC)
public interface CreditFacilReportService {
#WebMethod
public CreditFacilReportResponseBean getCreditFacilReport(CreditFacilReportRequestBean requestbean);
}

How to configure empty targetNamespace in the Web Service?

I'm trying to set up empty target namespace when creating the Web Service. Here is the example. My service looks like this:
package com.example;
import javax.jws.WebMethod;
import javax.jws.WebService;
#WebService
public class SampleService
{
#WebMethod
public void sampleMethod()
{
}
}
Defined like that, it accepts requests that look like this (please note the exam namespace declaration):
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:exam="http://example.com/">
<soapenv:Header/>
<soapenv:Body>
<exam:sampleMethod/>
</soapenv:Body>
</soapenv:Envelope>
I would like to configure the web service to accept the requests that look like this (without the namespace):
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header/>
<soapenv:Body>
<sampleMethod/>
</soapenv:Body>
</soapenv:Envelope>
I tried to set up the targetNamespace to the empty string, but that didn't work - it just defaulted to the exam namespace.
#WebService(targetNamespace="")
I'm using Apache CXF (3.1.0) to expose the service:
<bean id="sampleService" class="com.example.SampleService" />
<jaxws:endpoint id="sampleServiceWs" implementor="#sampleService"
address="/SampleService" publish="true">
</jaxws:endpoint>
To answer my question - I didn't find a way to set the empty targetNamespace, but I managed to leave out the request validation on my service, so that it now accepts the request with the namespace also. To do that, I used the #EndpointProperty annotation on top of the service class:
package com.example;
import javax.jws.WebMethod;
import javax.jws.WebService;
import org.apache.cxf.annotations.EndpointProperty;
#WebService
#EndpointProperty(key = "soap.no.validate.parts", value = "true")
public class SampleService
{
#WebMethod
public void sampleMethod()
{
}
}

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>

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").

Propagate SOAPFault with simple Camel proxy

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)