How can convert local xml file to org.ksoap2.serialization.SoapObject? - java

I am developing android web application which needs to connect web - service for response.
I am using kSOAP for web service invocation process.
[kSOAP is a SOAP web service client library for constrained Java environments such as Applets or J2ME applications.]
If I am saving that responded xml into the local directory, eg. /mnt/sdcard/appData/config.xml and then when ever I ask request for web service, first it will checks if local file is there then consider that file as responded file otherwise connect to the server.
This process reduce response time and increase efficiency of application.
Is it possible to convert it ('config.xml') to SOAP object? And How?
Consider my xml local file is as below:
config.xml
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<Response xmlns="http://testuser.com/webservices/response">
<Result>
<SName>Test User</SName>
<UnitDesc>SAMPLE Test </UnitDesc> <RefreshRate>60</RefreshRate>
<Out>
<Definition>
<Code>ABC</Code>
<Description>(Specific)</Description>
<Action>true</Action>
<Despatch>false</Despatch>
</Definition>
<Definition>
<Code>CDE</Code><Description>(Specific)</Description>
<ActionDate>true</ActionDate>
</Definition>
</Out>
<SampleText>
<string>Test XML Parsing</string>
<string>Check how to convert it to SOAP response</string>
<string>Try if you know</string>
</SampleText>
<GeneralData>
<Pair>
<Name>AllowRefresh</Name>
<Value>Y</Value>
</Pair>
<Pair>
<Name>ListOrder</Name>
<Value>ACCENDING</Value>
</Pair>
</GeneralData>
</Result>
</Response>
</soap:Body>
</soap:Envelope>
Current code is shown below:
final String CONFIGURATION_FILE="config.xml";
File demoDataFile = new File("/mnt/sdcard/appData");
boolean fileAvailable=false;
File[] dataFiles=demoDataFile.listFiles(new FilenameFilter() {
#Override
public boolean accept(File dir, String filename) {
return filename.endsWith(".xml");
}
});
for (File file : dataFiles) {
if(file.getName().equals(CONFIGURATION_FILE))
{
fileAvailable=true;
}
}
if(fileAvailable)
{
//**What to do?**
}
else
{
//Create the envelope
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
//Put request object into the envelope
envelope.setOutputSoapObject(request);
//Set other properties
envelope.encodingStyle = SoapSerializationEnvelope.XSD;
envelope.dotNet = true;
String method="test";
synchronized (transportLockObject)
{
String soapAction = "http://testuser.com/webservices/response/"+method;
try {
transport.call(soapAction, envelope);
} catch (SSLHandshakeException she) {
she.printStackTrace();
SecurityService.initSSLSocketFactory(ctx);
transport.call(soapAction, envelope);
}
}
//Get the response
Object response = envelope.getResponse();
//Check if response is available... if yes parse the response
if (response != null)
{
if (sampleResponse != null)
{
sampleResponse.parse(response);
}
}
else
{
// Throw no response exception
throw new NoResponseException("No response received for " + method + " operation");
}
}

You can extend HttpTransportSE class and override method call like this:
public void call(String soapAction, SoapEnvelope envelope) throws IOException, XmlPullParserException
{
if(localFileAvailable)
{
InputStream is = new FileInputStream(fileWithXml);
parseResponse(envelope, is);
is.close();
}
else
{
super.call(soapAction, envelope);
}
}

The question was how to convert an xml file to a SoapObject. So how to get your input xml envelope into a ksoap2 call.
The way to do this is actually available within the HttpTransportSE class even though this was not its intended use!
There is a method "parseResponse" that takes in the envelope and an input stream(your xml file) and updates the envelope input header and body. But the clever thing is that you can copy these into the outHeader and outBody fields and then all the hard work of mapping fields goes away.
#Override
public void call(String soapAction, SoapEnvelope envelope) throws IOException, XmlPullParserException {
if ( getFileInputStream() != null ){
parseResponse(envelope, getFileInputStream());
envelope.bodyOut = envelope.bodyIn;
envelope.headerOut = envelope.headerIn;
getFileInputStream().close();
}
super.call(soapAction,envelope);
}

Related

Soap Header is fetched as null using SOAPMessage.getSOAPHeader() while retrieving custom SOAP header

I am trying to extract custom SOAP header using the chain-handler mechanism as below:
Webservice:
`#HandlerChain(file="handler-chain.xml")
public class CustomAPI extends SessionBeanBase {
#WebMethod
public GetBalanceResponse getBalances(
#WebParam(name="subscriptionId")long subscriptionId,
#WebParam(name="validityPeriodFromDt")Date validityPeriodFromDt,
#WebParam(name="validityPeriodToDt")Date validityPeriodToDt) throws APIException
{
try {
GetBalancesItem item = new GetBalancesItem(subscriptionId, validityPeriodFromDt, validityPeriodToDt);
final BalanceBusinessLogic api = (BalanceBusinessLogic)startCall(RSLogic.class, this, "getBalances");
BusinessLogicCallable<GetBalancesItem> t = new BusinessLogicCallable<GetBalancesItem>() {
public Response callBusinessLogic(GetBalancesItem getBalancesItem) throws CCSException, APIException {
Date validityPeriodFromDt = getBalancesItem.getValidityPeriodFromDt();
Date validityPeriodToDt = getBalancesItem.getValidityPeriodToDt();
long subscriptionId = getBalancesItem.getSubscriptionId();
return api.checkBalance(subscriptionId, validityPeriodFromDt, validityPeriodToDt);
}
};
return (GetBalanceResponse)callBusinessLogic(t, item);
} catch (Throwable e) {
// Handle exception (and rethrow it hence the need for return null)
handleExceptions(e);
return null;
}
}`
Handler-chain. xml as:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<handler-chains xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/javaee_web_services_metadata_handler_2_0.xsd">
<handler-chain>
<handler>
<handler-name>ApiSoapHandler</handler-name>
<handler-class>com.api.framework.ApiSoapHandler</handler-class>
</handler>
</handler-chain>
</handler-chains>
ApiSOAPhandlercode as:
public boolean handleMessage(SOAPMessageContext context) {
logger.debug("Inside ApiSoapHandler");
try {
SOAPMessage message = context.getMessage();
SOAPPart soapPart= message.getSOAPPart();
SOAPEnvelope soapEnvelope = soapPart.getEnvelope();
if (soapEnvelope.getHeader() == null) {
soapEnvelope.addHeader();
}
// set the soap header
SOAPHeader latestSOAPHeader = soapHeader.get();
if (latestSOAPHeader != null) {
Iterator iterator = latestSOAPHeader.getChildElements();
while(iterator.hasNext()) {
SOAPHeaderElement soapHeaderElement = (SOAPHeaderElement)iterator.next();
soapEnvelope.getHeader().addChildElement(soapHeaderElement);
}
}
message.saveChanges();
System.out.println("header" + header.getAttribute("token"));
} catch (Exception e) {
logger.error("Error occurred while adding credentials to SOAP header.",
e);
}
return true;
}
The problem is that my header is fetched as null here . can anyone please suggest how to get the header here . For the reference , here is my sample SOAP request :
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:bal="http://balance.api.ccs.cerillion.com/">
<soapenv:Header>
<token>187328364</token>
<soapenv:Header/>
<soapenv:Body>
<bal:getBalances>
<subscriptionId>664</subscriptionId>
</bal:getBalances>
</soapenv:Body>
</soapenv:Envelope>
While extracting token , am getting null in my code .

Sending ArrayList From android to SOAP and getting error: org.kxml2.kdom.Element.write(org.xmlpull.v1.XmlSerializer)

I was testing an android application wich uses a KSOAP2 library and im trying to send an object ArrayList to my web service application wich is in netbeans with a method who receive this List and return a response.
i was searching information about how to test the web service, because netbeans uses a default server (glassfish) and the netbeans project that i have uses tomcat, so i found the SOAP UI programm to test this method and when i pass the list with the SOAP UI request, the method response is successfull it should return a LIST of objects too, and that's ok from now BUT,
in android i tried to send this ArrayList like this:
private final String SOAP_NAMESPACE = "http://ws.soap.net/";
private final String URL_SOAP="http://MI_IP:PORT/GetSomeRest/WebServiceTest";
private final String SOAP_SOMETHING = "GetSomething";
private final String SOAP_ACTION_GETSOMETHING = "http://ws.soap.net/" + SOAP_SOMETHING;
public SoapObject SendSigns(ArrayList<Signs> paramSigns)
{
SoapObject request = new SoapObject(SOAP_NAMESPACE, SOAP_SOMETHING);
request.addSoapObject(buildArray(paramSigns));
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(
SoapEnvelope.VER11);
new MarshalBase64().register(envelope);
envelope.bodyOut = request;
envelope.setOutputSoapObject(request);
envelope.setAddAdornments(false);
envelope.implicitTypes= true;
envelope.dotNet=true;
envelope.headerOut = new org.kxml2.kdom.Element[1];
HttpTransportSE androidHttpTransport = new HttpTransportSE(URL_SOAP);
try {
androidHttpTransport.debug = true;
androidHttpTransport.call(SOAP_ACTION_GETSOMETHING, envelope);
SoapObject Object = (SoapObject) envelope.getResponse();
if(Object!=null)
{
return Object;
}
} catch (Exception e) {
Log.d("CALL DUMP", "requestError: "+androidHttpTransport.requestDump);
Log.d("CALL DUMP", "responseEror: "+androidHttpTransport.responseDump);
Log.e("ERROR: ", String.valueOf(e));
}
return null;
}
Here is the buildArray Method which returns a SoapObject with the List filled:
protected SoapObject buildArray(ArrayList<Signs> paramSigns) {
SoapObject soapSigns = new SoapObject(SOAP_NAMESPACE, "List");
for (int i = 0; i < Signs.size(); i++) {
paramSigns.addProperty("id",Signs.get(i).getId());
paramSigns.addProperty("type",Signs.get(i).getType());
}
return soapSigns;
}
So when i run my application I got the following error:
java.lang.NullPointerException: Attempt to invoke virtual method 'void org.kxml2.kdom.Element.write(org.xmlpull.v1.XmlSerializer)' on a null object reference
BUT IF,
If i delete this following line:
envelope.headerOut = new org.kxml2.kdom.Element[1];
I receive a response from web service, but with a soapObject Null, and i put this line:
androidHttpTransport.debug = true;
And i saw the requestDump was filled with a XML like this:
<v:Envelope xmlns:i="http://www.w3.org/2001/XMLSchema-instance"
xmlns:d="http://www.w3.org/2001/XMLSchema"
xmlns:c="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:v="http://schemas.xmlsoap.org/soap/envelope/">
<v:Header />
<v:Body>
<GetSomething xmlns="http://ws.soap.net/">
<List>
<id>386661006</id>
<tipo>sign</tipo>
<id>68235000</id>
<tipo>sign</tipo>
<id>25064002</id>
<tipo>sign</tipo>
</List>
</GetSomething>
</v:Body>
</v:Envelope>
And i paste this XML in the SOAP UI request and i didn't have a response...
So how could i face the java.lang.NullPointerException: Attempt to invoke virtual method 'void org.kxml2.kdom.Element.write(org.xmlpull.v1.XmlSerializer)' on a null object reference ???
I would be grateful by all kind of help!
Best regards
Ok guys, the problem was precisely this line:
envelope.headerOut = new org.kxml2.kdom.Element[1];
Because i think that my Web Service doesn't have a Header!
That was the way to avoid the error...
Best regards!

How to send a SOAP request using WebServiceTemplate?

I am trying to send a request to a SOAP webservice. I read this tutorial and prepared the following code. However, I am going to send different requests to multiple SOAP webservices, whereas the tutorial focused on one request. How can I send SOAP request using WebserviceTemplate?
WebServiceTemplate
SoapMessage soapMsg = new SoapMessage();
soapMsg.setUsername("Requester");
soapMsg.setPassword("Pass");
soapMsg.setLanguageCode("EN");
Request request = new Request();
request.setDeparture("FDH");
request.setDestination("HAM");
Date date = new Date();
SimpleDateFormat frm2 = new SimpleDateFormat("yyyy-MM-dd");
request.setDepartureDate(frm2.parse(frm2.format(date)));
request.setNumADT(1);
request.setNumCHD(0);
request.setNumInf(0);
request.setCurrencyCode("EUR");
request.setWaitForResult(true);
request.setNearByDepartures(true);
request.setNearByDestinations(true);
request.setRronly(false);
request.setMetaSearch(false);
soapMsg.setRequest(request);
WebServiceTemplate webServiceTemplate = new WebServiceTemplate(). //how to create object and send request!
Object response = webServiceTemplate.marshalSendAndReceive(
"https://aaa5.elsyarres.net", soapMsg);
Response msg = (Response) response;
System.err.println("size of results of wogolo:"
+ msg.getFlights().getFlight().size());
You can use following code, you do not need to define anything in xml file.
try {
SaajSoapMessageFactory messageFactory = new SaajSoapMessageFactory(
MessageFactory.newInstance());
messageFactory.afterPropertiesSet();
WebServiceTemplate webServiceTemplate = new WebServiceTemplate(
messageFactory);
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setContextPath("PACKAGE");
marshaller.afterPropertiesSet();
webServiceTemplate.setMarshaller(marshaller);
webServiceTemplate.afterPropertiesSet();
Response response = (Response) webServiceTemplate
.marshalSendAndReceive(
"address",
searchFlights);
Response msg = (Response) response;
} catch (Exception s) {
s.printStackTrace();
}
To send different SOAP requests to different SOAP services, you just need to make your WebServiceTemplate aware of all requests and responses it will have to process.
Create a Java class for each request and response like so:
package models;
import javax.xml.bind.annotation.XmlRootElement;
import java.io.Serializable;
#XmlRootElement
public class FlyRequest implements Serializable {
private boolean nearByDeparture;
public FlyRequest() {}
public boolean isNearByDeparture() {
return nearByDeparture;
}
public void setNearByDeparture(boolean nearByDeparture) {
this.nearByDeparture = nearByDeparture;
}
}
(The #XmlRootElement is because we use JAXB marshaller below; see Jaxb reference for more info).
The setup of the template is done for example like so:
SaajSoapMessageFactory messageFactory = new SaajSoapMessageFactory(MessageFactory.newInstance());
messageFactory.afterPropertiesSet();
WebServiceTemplate webServiceTemplate = new WebServiceTemplate(messageFactory);
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setContextPath("models");
marshaller.afterPropertiesSet();
webServiceTemplate.setMarshaller(marshaller);
webServiceTemplate.afterPropertiesSet();
"models" is the name of the package where the Request/Responses classes are, so that jaxb can find them.
Then you just instantiate the request of the class you want to perform the call, like so:
// call fly service:
FlyRequest flyRequest = new FlyRequest();
flyRequest.setNearByDeparture(false);
Object flyResponse = webServiceTemplate.marshalSendAndReceive("https://example.net/fly", flyRequest);
// call purchase service:
PurchaseRequest purchaseRequest = new PurchaseRequest();
purchaseRequest.setPrice(100);
Object purchaseResponse = webServiceTemplate.marshalSendAndReceive("https://example.net/purchase", purchaseRequest);
Similarly, you can cast the response objects into your JAXB classes defined above.
Here is an Example what you should be looking for
Soap has a lot of restriction unlike REST, It follows some standards which have to be meet before you get Network call to work,
But unlike Rest, in Soap if you have WSDL URL you can get all the information needed to call the Soap call
private final String NAMESPACE = "http://www.w3schools.com/webservices/";
private final String URL = "http://www.w3schools.com/webservices/tempconvert.asmx?WSDL";
private final String SOAP_ACTION = "http://www.w3schools.com/webservices/CelsiusToFahrenheit";
private final String METHOD_NAME = "CelsiusToFahrenheit";
this code was written in Android so you can ignore some part of it but I still kept it in answer so someone from android background can put a good use to it
Open [WSDL][1] in browser and check for the things which matter to call a remote method on server.
1
you will see an attribute targetNamespace whose value would be Namespace which you will use in this case Namespace is http://www.w3schools.com/webservices/
2
Now you require the name of the method this WSDL has four method each of the are int attribute s:element with the value is the name of the Method in this case four methods are FahrenheitToCelsius, FahrenheitToCelsiusResponse, CelsiusToFahrenheit, CelsiusToFahrenheitResponse
3
Now you have to fure out the SOAP Action which is NAMESPACE+METHOD
but WSDL also gives information about that as well, look for the tag soap:operation and it's soapAction attribute havs the Soap action as it's value in this case which we want to call is http://www.w3schools.com/webservices/CelsiusToFahrenheit
private class MyTask extends AsyncTask<Void, Void, String> {
#Override
protected void onPreExecute() {
super.onPreExecute();
progressDialog.show();
}
#Override
protected String doInBackground(Void... params) {
try {
SoapObject soapObject = new SoapObject(NAMESPACE, METHOD_NAME);
soapObject.addProperty("Celsius","12");
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.dotNet = true;
envelope.setOutputSoapObject(soapObject);
HttpTransportSE httpTransportSE = new HttpTransportSE(URL);
httpTransportSE.call(SOAP_ACTION, envelope);
SoapPrimitive soapPrimitive = (SoapPrimitive)envelope.getResponse();
Log.d("TAG", "doInBackground: "+soapPrimitive.toString());
return soapObject.toString();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(String aVoid) {
super.onPostExecute(aVoid);
progressDialog.dismiss();
textView.setText(""+aVoid);
}
}
Assuming that your SoapMessage is marhsallable
To send the same message to multiple endpoints you only need to loop on the sending code and the request handler.
Something like this:
{
String endpoint = "https://aaa5.elsyarres.net"
WebServiceTemplate webServiceTemplate = new WebServiceTemplate().
webServiceTemplate.setDefaultUri(endpoint);
Object response = webServiceTemplate.marshalSendAndReceive(soapMsg);
// handle you are response as you are currently doing.
// Loop changing the endpoint as you need.
}
This code uses the Spring WebServiceTemplate
I tried many options and finally below one worked for me if you have to send soap header with authentication(Provided authentication object created by wsimport) and also need to set soapaction.
public Response callWebService(String url, Object request)
{
Response res = null;
log.info("The request object is " + request.toString());
try {
res = (Response) getWebServiceTemplate().marshalSendAndReceive(url, request,new WebServiceMessageCallback() {
#Override
public void doWithMessage(WebServiceMessage message) {
try {
// get the header from the SOAP message
SoapHeader soapHeader = ((SoapMessage) message).getSoapHeader();
// create the header element
ObjectFactory factory = new ObjectFactory();
Authentication auth =
factory.createAuthentication();
auth.setUser("****");
auth.setPassword("******");
((SoapMessage) message).setSoapAction(
"soapAction");
JAXBElement<Authentication> headers =
factory.createAuthentication(auth);
// create a marshaller
JAXBContext context = JAXBContext.newInstance(Authentication.class);
Marshaller marshaller = context.createMarshaller();
// marshal the headers into the specified result
marshaller.marshal(headers, soapHeader.getResult());
} catch (Exception e) {
log.error("error during marshalling of the SOAP headers", e);
}
}
});
} catch (Exception e) {
e.printStackTrace();
}
return res;
}

How to enable WS-Addresing in client SOAP request for Grails

I have a problem with WS-Addresing in SOAP header. I succesfully imported classes from xsd file with configuration, but server require WS-Addressing attributes in soap header("wsa:action", "wsa:to"). Unfortunettly client service dont inject these attributes and server return http code 400 "Bad Request".
How can I automatically inject a proper SOAP header for requests?
I tried with #Addressing(enabled=true, required=true) annotation, but header was wrong for webservice
Configuration in Config.groovy
Service endpoint: https://wyszukiwarkaregontest.stat.gov.pl/wsBIR/UslugaBIRzewnPubl.svc
Main xsd file: https://wyszukiwarkaregontest.stat.gov.pl/wsBIR/wsdl/UslugaBIRzewnPubl.xsd
I use Grails 2.5.0 and plugin grails-cfx
Grails-cfx configuration in Config.groovy
birCompanyDataEndPoint {
wsdl = "wsdl/UslugaBIRzewnPubl.xsd"
namespace = "pl.truesoftware.crm.company.regon"
client = true
contentType = "application/soap+xml"
mtomEnabled = true
exsh = true
or = true
wsdlArgs = ['-autoNameResolution']
// outInterceptors = 'smartApiMetaOutInterceptor'
clientInterface = IUslugaBIRzewnPubl
serviceEndpointAddress = "https://wyszukiwarkaregontest.stat.gov.pl/wsBIR/UslugaBIRzewnPubl.svc"
}
Example
Plain SOAP request from client service
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<ns2:DaneKomunikat xmlns="http://CIS/BIR/PUBL/2014/07/DataContract" xmlns:ns2="http://CIS/BIR/PUBL/2014/07" xmlns:ns3="http://CIS/BIR/2014/07" xmlns:ns4="http://schemas.microsoft.com/2003/10/Serialization/"/>
</soap:Body>
</soap:Envelope>
With using annotation #Addressing(enabled=true, required=true)
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header>
<Action xmlns="http://www.w3.org/2005/08/addressing">http://CIS/BIR/PUBL/2014/07/IUslugaBIRzewnPubl/DaneKomunikat</Action>
<MessageID xmlns="http://www.w3.org/2005/08/addressing">urn:uuid:f43e7c86-99dd-42fc-a626-ccbd44136682</MessageID>
<To xmlns="http://www.w3.org/2005/08/addressing">https://wyszukiwarkaregontest.stat.gov.pl/wsBIR/UslugaBIRzewnPubl.svc</To>
<ReplyTo xmlns="http://www.w3.org/2005/08/addressing">
<Address>http://www.w3.org/2005/08/addressing/anonymous</Address>
</ReplyTo>
</soap:Header>
<soap:Body>
<ns2:DaneKomunikat xmlns="http://CIS/BIR/PUBL/2014/07/DataContract" xmlns:ns2="http://CIS/BIR/PUBL/2014/07" xmlns:ns3="http://CIS/BIR/2014/07" xmlns:ns4="http://schemas.microsoft.com/2003/10/Serialization/"/>
</soap:Body>
</soap:Envelope>
Expected
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:ns="http://CIS/BIR/PUBL/2014/07">
<soap:Header xmlns:wsa="http://www.w3.org/2005/08/addressing">
<wsa:To>https://wyszukiwarkaregontest.stat.gov.pl/wsBIR/UslugaBIRzewnPubl.svc</wsa:To>
<wsa:Action>http://CIS/BIR/PUBL/2014/07/IUslugaBIRzewnPubl/DaneKomunikat</wsa:Action>
</soap:Header>
<soap:Body>
<ns:DaneKomunikat/>
</soap:Body>
</soap:Envelope>
Update with solution
Created two cfx interceptor. First convert soap addressing tags(Action, To) to acceptable format
public class BirSoapHeaderInterceptor extends AbstractSoapInterceptor
{
static String birSID = ""
public BirSoapHeaderInterceptor() {
super(Phase.PRE_PROTOCOL);
}
#Override
public void handleMessage(SoapMessage message) throws Fault
{
try
{
message.put("disable.outputstream.optimization", true)
List<Header> soapHeaders = message.getHeaders()
//----------------- copy values from old header
String wsaAction = ""
String wsaTo = ""
soapHeaders.each { tag ->
log.debug("Soap request header tag: ${tag.name} ${tag.dataBinding}")
String tagName = (tag.name as String)
def objectValue = tag.object?.value
if (!wsaAction && tagName.contains("Action"))
wsaAction = objectValue?.value
if (!wsaTo && tagName.contains("To"))
wsaTo = objectValue?.value
}
soapHeaders.clear()
//-----------------wsa:To
Header headTo = new Header(new QName("http://www.w3.org/2005/08/addressing", "To", "wsa"), wsaTo, new JAXBDataBinding(String.class))
soapHeaders.add(headTo)
//-----------------wsa:Action
Header headAction = new Header(new QName("http://www.w3.org/2005/08/addressing", "Action", "wsa"), wsaAction, new JAXBDataBinding(String.class))
soapHeaders.add(headAction)
message.put(Header.HEADER_LIST, soapHeaders)
//Session identyficator in HTTP Header
if(birSID.length())
{
Map<String, List<String>> outHeaders = (Map<String, List<String>>) message.get(Message.PROTOCOL_HEADERS)
outHeaders.put("sid", Arrays.asList(birSID));
message.put(Message.PROTOCOL_HEADERS, outHeaders);
}
} catch (SOAPException e)
{
log.error(e)
}
}
}
Second interceptor converts attributes 'xmlns:soap', 'xmlns:wsa', 'xmlns:soap' with acceptable namespaces
class BirSoapContextInterceptor implements SOAPHandler<SOAPMessageContext>
{
/*
Based on https://stackoverflow.com/questions/10678723/changing-jax-ws-default-xml-namespace-prefix
*/
public boolean handleMessage(final SOAPMessageContext context)
{
try
{
SOAPMessage soapMsg = context.getMessage();
SOAPEnvelope envelope = soapMsg.getSOAPPart().getEnvelope()
soapMsg.getSOAPPart().getEnvelope().removeAttributeNS("http://schemas.xmlsoap.org/soap/envelope/", "soap");
soapMsg.getSOAPPart().getEnvelope().removeAttributeNS("http://www.w3.org/2000/xmlns/", "soap");
soapMsg.getSOAPPart().getEnvelope().removeAttribute("xmlns:soap");
soapMsg.getSOAPPart().getEnvelope().removeNamespaceDeclaration("xmlns:soap")
envelope.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:soap", "http://www.w3.org/2003/05/soap-envelope");
envelope.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:ns", "http://CIS/BIR/PUBL/2014/07");
soapMsg.getSOAPHeader().setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:wsa", "http://www.w3.org/2005/08/addressing")
soapMsg.getSOAPHeader().setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:soap", "http://www.w3.org/2003/05/soap-envelope");
soapMsg.saveChanges()
context.setMessage(soapMsg)
} catch (SOAPException e)
{
e.printStackTrace();
}
return true;
}
#Override
boolean handleFault(SOAPMessageContext context) {
return false
}
#Override
void close(MessageContext context) {
log.debug("Closing...")
}
#Override
Set<QName> getHeaders() {
return null
}
}

Spring WS: Add custom SOAP header

What's my goal?
I'm rather new to Spring WS, I got a WSDL (and along some XSDs, ofcourse) and i want to add some custom header elements to the SOAP response.
I've been searching the web, tried various code pieces, but it's all without any luck... nothing seems to work properly .
What's the problem?
The response SOAP message has a body what spring calls a Payload and my SOAP client (SOAPUI) receives the response rather well.
But here it comes: how should I add new (custom) SOAP headers to the response message?
What's the response xml expected?
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header>
<aud:HeaderInfo xmlns:bd="http://www.myws.com/">
<bd:ID>123</bd:ID>
<bd:Type>text</bd:Type>
</aud:HeaderInfo>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<ne:myWS xmlns:ne="http://www.iways.com/">
<ne:INFO>
<ne:NAME>JOHN</ne:NAME>
<ne:DESIGNATION>ITA</ne:DESIGNATION>
<ne:MOBILE>9841011113</ne:MOBILE>
</ne:INFO>
</ne:myWS>
My payload
#PayloadRoot(localPart = "myWSRequest", namespace = TARGET_NAMESPACE)
public #ResponsePayload myWSResponse getInfo(#RequestPayload myWSRequest request)
{
myWSResponse response = new myWSResponse();
Person person = personService_i.getAccountDetails(request.getID());
response.setPersonDetails(person);
return response;
}
Any side info?
i use xsd which generates a load of classes based upon the XSDs I don't know how to add those custom headers to the response message,
You could implement a endpointInterceptorAdapter and do the following:
public final class MyEndpointInterceptorAdapter extends EndpointInterceptorAdapter {
#Override
public boolean handleResponse(MessageContext messageContext_, Object endpoint_)
throws IOException {
WebServiceMessage _webServiceMessage = messageContext_.getResponse();
SoapMessage _soapMessage = (SoapMessage) _webServiceMessage;
if (_soapMessage != null) {
SoapEnvelope _soapEnvelope = _soapMessage.getEnvelope();
// create your qname object
QName _myQName = ....
// adding your quname to the header
_soapEnvelope.getHeader().addHeaderElement(myQName );
}
}
}
and in your spring configuration file, just add the interceptor:
<sws:interceptors>
<ref bean="myEndpointInterceptorAdapter"/>
</sws:interceptors>

Categories

Resources