I have requirements where I have to add response details in Body tag instead of Header. For now details are added in Header tag of soap response.
#XmlType
public class CheckBalanceResponse {
private String checkBalanceResult;
#XmlElement(name="CheckBalanceResult")
public String getCheckBalanceResult() {
return checkBalanceResult;
}
public void setCheckBalanceResult(String checkBalanceResult) {
this.checkBalanceResult = checkBalanceResult;
}
}
Generated response is below:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header>
<CheckBalanceResponse xmlns="http://charginggw.org/">
<CheckBalanceResult>Incorrect PIN</CheckBalanceResult>
</CheckBalanceResponse>
</soap:Header>
<soap:Body/>
</soap:Envelope>
I want CheckBalanceResponse tag to be in Body instead of Header. Please suggest what should be done?
Related
Below are my web-service request, Route and Request-Validator,
Web-service request:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header>
<stlh:SabreHeader xmlns:stlh="http://services.sabre.com/STL_Header/v02_01">
<stlh:Service version="1.0.0">GetHotelMediaRQ</stlh:Service>
<stlh:Identification>
<stlh:CustomerID>CID12345</stlh:CustomerID>
<stlh:CustomerAppID>AppTest</stlh:CustomerAppID>
<stlh:ConversationID>05EFPElI2A4KudU75863JIxqAhQJtAx0</stlh:ConversationID>
<stlh:MessageID>4DTTQaHGSifFUtmSoMHAiq</stlh:MessageID>
<stlh:TimeStamp>2014-11-07T14:45:42.725-06:00</stlh:TimeStamp>
</stlh:Identification>
</stlh:SabreHeader>
<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-wssecurity-utility-1.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:BinarySecurityToken EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" wsu:Id="athId">${athId}</wsse:BinarySecurityToken>
</wsse:Security>
</soap:Header>
<soap:Body>
<GetHotelMediaRQ xmlns="http://services.sabre.com/hotel/media/v1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.0.0" xsi:schemaLocation="http://services.sabre.com/hotel/media/v1 GetHotelMediaRQ.xsd">
<HotelRefs>
<HotelRef HotelCode="184769" CodeContext="Sabre">
<ImageRef MaxImages="1">
<Images>
<Image Type="ORI"/>
</Images>
<AdditionalInfo>
<Info Type="CAPTION">true</Info>
</AdditionalInfo>
<Languages>
<Language Code="EN"/>
</Languages>
</ImageRef>
</HotelRef>
</HotelRefs>
</GetHotelMediaRQ>
</soap:Body>
</soap:Envelope>
RequestValidator:
public void validate(GetHotelMediaRQ request, Exchange exchange) throws Exception {
TransactionContext context = BusExtensions.getTransactionContext(exchange);
Collection<HotelRef> hotelRefList = getInstance().convert(request, Collection.class);
Set<Property> properties = new HashSet<>();
String customerAppId = exchange.getIn().getHeader("customerAppID", String.class);
String customerId = exchange.getIn().getHeader("customerID", String.class);
But customerAppId(AppTest) and CustomerId(CI12345) is coming as null when I try to access via Exchange object.
"Custom" Soap headers are not copied to camel header . you have to manually add soap header into camel exchange header .
Approach 1 )
CamelCxfMessage - you can extract/process custom soap header camel cxf message which is present in camel exchange header
in camel -
SoapMessage soapMessage = (SoapMessage)exchange.getIn().getHeader("CamelCxfMessage");
this will give you soap message and its soapMessage.getExchange and try to get soap headers from soap message and process it .
Approach 2)
Camel Cxf Binding -you can use camel cxf binding feature in endpoint definition like cxfBinding=#bindingName .
Create a class and extend with org.apache.camel.component.cxf.DefaultCxfBinding and bean name should be bindingName .
it has one method which you have to overwrite - propagateHeadersFromCxfToCamel(camelmessage ,cxfmessage ,exchage ).
Here get your soap header and put it in camel header with identifier and access header in camel exchange header in processor or routes with same identifier.
Set logging for org.apache.camel to DEBUG and the header values will be logged, and you can determine if the component is dropping them or not.
Also, it looks like you might be using the cxf soap endpoint. Look into the [Description of relayHeaders option] section of the docs here:
http://camel.apache.org/cxf.html
i had to extract header information but got null in the object at the first attempt. then after a while i could fish it out. here is how (in a processor):
#Override
public void process(Exchange exc) throws Exception {
#SuppressWarnings("unchecked")
List<SoapHeader> headers = exc.getIn().getHeader(Header.HEADER_LIST, List.class);
for (int i=0; i < headers.size(); i++) {
if (headers.get(i).getObject() instanceof ElementNSImpl) {
ElementNSImpl elementNSImpl = (ElementNSImpl) headers.get(i).getObject();
Node firstChild = elementNSImpl.getFirstChild();
log.trace("header: name=" + elementNSImpl.getLocalName() + ", value=" + firstChild.getNodeValue());
}
}
Below is the SOAP Response that need to convert to Java Objects
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<ns0:HelpDesk_Query_ServiceResponse xmlns:ns0="urn:XXXX_HPD_IncidentInterface_WS__XXXXX" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ns0:Assigned_Group>TIM-CSDWINDOWS-ADMIN</ns0:Assigned_Group>
<ns0:Assigned_Group_Shift_Name/>
<ns0:Assigned_Support_Company>India Ltd</ns0:Assigned_Support_Company>
<ns0:Assigned_Support_Organization>TIM-CSD</ns0:Assigned_Support_Organization>
<ns0:Assignee>Akshay Patwardhan</ns0:Assignee>
<ns0:Categorization_Tier_1>TIM</ns0:Categorization_Tier_1>
<ns0:Categorization_Tier_2>ATT</ns0:Categorization_Tier_2>
<ns0:Categorization_Tier_3>C Drive Enablement</ns0:Categorization_Tier_3>
<ns0:City>HYDERABAD</ns0:City>
<ns0:Closure_Manufacturer/>
<ns0:Closure_Product_Category_Tier1/>
<ns0:Closure_Product_Category_Tier2/>
<ns0:Closure_Product_Category_Tier3/>
<ns0:Closure_Product_Model_Version/>
<ns0:Closure_Product_Name/>
<ns0:Company>India Ltd</ns0:Company>
<ns0:Contact_Company>India Ltd</ns0:Contact_Company>
<ns0:Contact_Sensitivity>Standard</ns0:Contact_Sensitivity>
<ns0:Country>India</ns0:Country>
<ns0:Department>TIM-India </ns0:Department>
<ns0:Summary>Test</ns0:Summary>
<ns0:Notes>Host Name: INHYTZPC03456 Detailed Business Justification: test Project/ODC Name: TIM Your Current Location Details: </ns0:Notes>
<ns0:First_Name>Venkata</ns0:First_Name>
<ns0:Impact>4-Minor/Localized</ns0:Impact>
<ns0:Last_Name>Sabbarapu</ns0:Last_Name>
<ns0:Manufacturer/>
<ns0:Middle_Initial/>
<ns0:Organization>XXX_TIM</ns0:Organization>
<ns0:Phone_Number>XXXXXX Extn: 67 -XXXXXX</ns0:Phone_Number>
<ns0:Priority>Medium</ns0:Priority>
<ns0:Priority_Weight>10</ns0:Priority_Weight>
<ns0:Product_Categorization_Tier_1/>
<ns0:Product_Categorization_Tier_2/>
<ns0:Product_Categorization_Tier_3/>
<ns0:Product_Model_Version/>
<ns0:Product_Name/>
<ns0:Region>India</ns0:Region>
<ns0:Reported_Source>Self Service</ns0:Reported_Source>
<ns0:Resolution/>
<ns0:Resolution_Category/>
<ns0:Resolution_Category_Tier_2/>
<ns0:Resolution_Category_Tier_3/>
<ns0:Service_Type>User Service Request</ns0:Service_Type>
<ns0:Site>BHD-SEZ</ns0:Site>
<ns0:Site_Group>HYDERABAD</ns0:Site_Group>
<ns0:Status>Assigned</ns0:Status>
<ns0:Status_Reason xsi:nil="true" />
<ns0:Urgency>3-Medium</ns0:Urgency>
<ns0:VIP>No</ns0:VIP>
<ns0:ServiceCI/>
<ns0:ServiceCI_ReconID/>
<ns0:HPD_CI/>
<ns0:HPD_CI_ReconID/>
<ns0:HPD_CI_FormName/>
<ns0:z1D_CI_FormName/>
</ns0:HelpDesk_Query_ServiceResponse>
</soapenv:Body>
</soapenv:Envelope>
This is my pojo
#XmlAccessorType(XmlAccessType.FIELD)
public class Response {
String Assigned_Group;
String Assigned_Group_Shift_Name;
String Assigned_Support_Company;
String Assigned_Support_Organization;
String Assignee;
String Categorization_Tier_1;
String Categorization_Tier_2;
String Categorization_Tier_3;
String City;
public String getAssigned_Group() {
return Assigned_Group;
}
public void setAssigned_Group(String assigned_Group) {
Assigned_Group = assigned_Group;
}
public String getAssigned_Group_Shift_Name() {
return Assigned_Group_Shift_Name;
}
public void setAssigned_Group_Shift_Name(String assigned_Group_Shift_Name) {
Assigned_Group_Shift_Name = assigned_Group_Shift_Name;
}
public String getAssigned_Support_Company() {
return Assigned_Support_Company;
}
This is UnMarshall code
Unmarshaller unmarshaller = JAXBContext.newInstance(Response.class).createUnmarshaller();
Document bodyDoc = soapResponse.getSOAPBody().extractContentAsDocument();
Response request = (Response) unmarshaller.unmarshal(bodyDoc);
its giving javax.xml.bind.UnmarshalException.
Can some help me in creating Java POJO and UnMarshall the above soap XML response to java Object.
I recommend to use wsimport to generate SOAP clients. There is also a Maven Plugin.
Or the tools wsdl2java , it will create the classes for you. Use the tools of your soap stack (cxf, axis2...)
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
}
}
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>
Here is my SOAP request:
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:str="http://app.strategyblocks.com/ws/schema/strategyblocks">
<soapenv:Header>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" soapenv:mustUnderstand="1">
<wsse:UsernameToken xmlns:wsu="...">
<wsse:Username>admin</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">secret</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
</soapenv:Header>
<soapenv:Body>
<str:updateKpiRequest>
<str:company_id>1</str:company_id>
<str:kpi>
<str:external_id>1134511</str:external_id>
<str:title>title</str:title>
<str:description>description</str:description>
</str:kpi>
</str:updateKpiRequest>
</soapenv:Body>
</soapenv:Envelope>
Here is my Endpoint class:
#Endpoint
public class UpdateKpiEndpoint {
// The namespace of both request and response as declared in the XSD file
public static final String NAMESPACE_URI = "http://app.strategyblocks.com/ws/schema/strategyblocks";
// The local name of the expected request.
public static final String REQUEST_LOCAL_NAME = "updateKpiRequest";
#PayloadRoot(localPart = REQUEST_LOCAL_NAME, namespace = NAMESPACE_URI)
#ResponsePayload
public UpdateKpiResponse processUpdateKpi(#RequestPayload UpdateKpiRequest updateKpiRequest) {
try {
} catch (Exception e) {
UpdateKpiResponse response = new UpdateKpiResponse();
response.setCode("FAILURE");
response.setDescription("Problem with update kpi request");
return response;
}
UpdateKpiResponse response = new UpdateKpiResponse();
response.setCode("SUCCESS");
response.setDescription("Kpi has been updated");
return response;
}
}
At the moment I am passing a UsernameToken for authentication in the soap request, that is all working well and I have no problems with it what so ever. What I want to be able to achieve is to retrieve that username from the header in the body of processUpdateKpi method in my endpoint class, so that I can use it to find existing data for that user, I have tried to find examples of it being done and so far I have been unsuccessful, is it possible to do it? I have thought about also passing the username in the SOAP body as well, but I want to avoid it.
someone in the spring forums had a clear explanation on how to read the header from the endpoint class:
http://forum.springsource.org/showthread.php?109560-Unable-to-read-SoapHeader-in-Endpoint-class