I am required to develop Web Service using the Spring Framework. Scenario is like this:
My program will send a SOAP request (header + payload) to a service and expects a response (header + payload) back from the service. Both the payload and header are important and needed by the program.
Problem is that I am unable to find any example in Spring WS where both header and payload are sent as part of request and header and payload extracted from response.
I am using WebServiceGatewaySupport
and WebServiceTemplate
for sending of request and fetching of response.
WebServiceTemplate
provides 2 methods for sending request:
marshalSendAndReceive
sendAndReceive
Problem with marshalSendAndReceive
is that I will not get back the response header though I can send the request header.
Problem with sendAndReceive
is that I will not be able to send the request header though I will be able to extract the response header.
The only solution currently available right now is to use Interceptors but it seems that this is not the proper way of handling the headers as header is intercepted before it reaches the calling function. To have the calling function access to response header, we will need to make the Interceptor as stateful which is not desirable.
I will really appreciate guidance and help from anyone who can provide me with an example of how to properly achieve this.
Please find my code below when using sendAndReceive:
public class ClientAccountInformation extends WebServiceGatewaySupport {
public ClientAccountInformation() {
}
public FIGetAcctsInfoCallBackRs sendRequest(GetAcctInfoRq request, HeaderRq headerRq) {
WebServiceTemplate webServiceTemplate = getWebServiceTemplate();
try {
ResponseAndHeader responseAndHeader = webServiceTemplate.sendAndReceive(Constants.WEBSERVICE_URL,
new WebServiceMessageCallback() {
public void doWithMessage(WebServiceMessage message) throws IOException {
try {
Jaxb2Marshaller marshallerRq = new Jaxb2Marshaller();
marshallerRq.setContextPath("com.abc.domain..getacctinfo");
marshallerRq.afterPropertiesSet();
MarshallingUtils.marshal(marshallerRq, request, message);
SoapHeader soapHeader = ((SoapMessage)message).getSoapHeader();
JAXBContext context = JAXBContext.newInstance(HeaderRq.class);
Marshaller marshaller = context.createMarshaller();
marshaller.marshal(HeaderRq, soapHeader.getResult());
} catch (Exception e) {
e.printStackTrace();
}
}
},
new WebServiceMessageExtractor<ResponseAndHeader>() {
public ResponseAndHeader extractData(WebServiceMessage message) throws IOException {
SoapHeader header = ((SoapMessage)message).getSoapHeader();
Iterator<SoapHeaderElement> it = header.examineHeaderElements(new QName("urn:test", "HeaderRs"));
return new ResponseAndHeader(
it.hasNext() ? (HeaderRs)jaxb2Marshaller().unmarshal(it.next().getSource())
: null,
(GetAcctInfoRs) MarshallingUtils.unmarshal(jaxb2Marshaller(), message));
}
});
return null;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
Jaxb2Marshaller jaxb2Marshaller() {
Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller();
jaxb2Marshaller.setContextPath("com.abc.domain.getacctinfo");
return jaxb2Marshaller;
}
}
The above code always returns null for the response header.
I have solved the issue. I can send the SOAP header to a service and extract the response header from response also. No need for interceptors.
Main help was from blog post from Andreas Veithen. Thanks.
public class ClientSamaAccountInformation extends WebServiceGatewaySupport {
public ClientSamaAccountInformation() {
}
public FIGetAcctsInfoCallBackRs sendRequest(FIGetAcctsInfoCallBackRq request, MsgHdrRq msgHdrRq) {
WebServiceTemplate webServiceTemplate = getWebServiceTemplate();
try {
ResponseAndHeader responseAndHeader = webServiceTemplate.sendAndReceive(Constants.WEBSERVICE_URL,
new WebServiceMessageCallback() {
public void doWithMessage(WebServiceMessage message) throws IOException {
try {
Jaxb2Marshaller marshallerRq = new Jaxb2Marshaller();
marshallerRq.setContextPath("com.abc.domain..getacctinfo");
marshallerRq.afterPropertiesSet();
MarshallingUtils.marshal(marshallerRq, request, message);
SoapHeader soapHeader = ((SoapMessage)message).getSoapHeader();
JAXBContext context = JAXBContext.newInstance(MsgHdrRq.class);
Marshaller marshaller = context.createMarshaller();
marshaller.marshal(msgHdrRq, soapHeader.getResult());
} catch (Exception e) {
e.printStackTrace();
}
}
},
new WebServiceMessageExtractor<ResponseAndHeader>() {
public ResponseAndHeader extractData(WebServiceMessage message) throws IOException {
//Extract response payload
FIGetAcctsInfoCallBackRs response = null;
try {
Jaxb2Marshaller marshallerRs = new Jaxb2Marshaller();
marshallerRs.setContextPath("com.abc.domain..getacctinfo");
marshallerRs.afterPropertiesSet();
response = (FIGetAcctsInfoCallBackRs) MarshallingUtils.unmarshal(marshallerRs, message);
} catch (Exception e) {
e.printStackTrace();
}
//Extract response header
MsgHdrRs msgHdrRs = null;
try {
JAXBContext context = JAXBContext.newInstance(MsgHdrRs.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
SoapHeader header = ((SoapMessage)message).getSoapHeader();
Iterator<SoapHeaderElement> it = header.examineHeaderElements(new QName("http://www.abc.def.com/common/Header", "MsgHdrRs"));
while(it.hasNext()) {
msgHdrRs = (MsgHdrRs) unmarshaller.unmarshal(it.next().getSource());
System.out.println(msgHdrRs);
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
});
return null;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}