How to read SOAP Header information from request and add it to response in spring web services
Asked Answered
B

4

8

I am working on spring web services. I need to add some custom elements in the request and response message.which should look like this:

<soapenv:Envelope>
   <soapenv:Header>
      <tid:SplsTID>
         <tid:Trantype>123</tid:Trantype>
         <tid:Tranver>234</tid:Tranver>
      </tid:SplsTID>
   </soapenv:Header>
   <soapenv:Body>
      <get:GetOrderNumberRequest LoggingLevel="REGULAR" MonitorFlag="Y">
         <get:Header>
            <get:TransactionId>111</get:TransactionId>
            <get:SourceSystemId>SOMS</get:SourceSystemId>
            <get:DateTime>2011-11-11T11:11:11</get:DateTime>
         </get:Header>
         <get:Body>
            <get:StaplesOrderNumber RangeFlag="N" ReleaseFlag="N">
               <get:OrderNumber Count="1" End="11" Start="9"/>
            </get:StaplesOrderNumber>
         </get:Body>
      </get:GetOrderNumberRequest>
   </soapenv:Body>
</soapenv:Envelope>

i am able to append <tid:SplsTID> under <soapenv:Header> in request by modifying the WSDL file. which looks like this:

<wsdl:message name="GetOrderNumberRequest">
        <wsdl:part element="tns:GetOrderNumberRequest" name="GetOrderNumberRequest">
        </wsdl:part>
        <wsdl:part element="sch1:SplsTID" name="SplsTID">
        </wsdl:part>
    </wsdl:message>
    <wsdl:message name="GetOrderNumberResponse">
        <wsdl:part element="tns:GetOrderNumberResponse" name="GetOrderNumberResponse">
        </wsdl:part>
        <wsdl:part element="sch1:SplsTID" name="SplsTID">
        </wsdl:part>
    </wsdl:message>
    <wsdl:portType name="ONAS">
        <wsdl:operation name="GetOrderNumber">
            <wsdl:input message="tns:GetOrderNumberRequest" name="GetOrderNumberRequest">
            </wsdl:input>
            <wsdl:output message="tns:GetOrderNumberResponse" name="GetOrderNumberResponse">
            </wsdl:output>
        </wsdl:operation>
    </wsdl:portType>

The problem is, i want to read <tid:SplsTID> part from the request and wanted to append it under soap header part of the response, which is not happening. i am using annotation based end point. what is the code which will read the soap header and will append the same in the response.

currently my end point class is:

@Endpoint
public class OrderNumberServiceEndPoint {
    public static final String NAMESPACE_URI = "http://schemas.staples.com/onas/getOrderNumber";

    /**
     * The local name of the expected request.
     */
    public static final String REQUEST_LOCAL_NAME = "GetOrderNumberRequest";

    /**
     * The local name of the created response.
     */
    public static final String RESPONSE_LOCAL_NAME = "GetOrderNumberResponse";

    private GetOrderNumberService getOrderNumberService;

    public void setGetOrderNumberService(
            GetOrderNumberService getOrderNumberService) {
        this.getOrderNumberService = getOrderNumberService;
    }

    @PayloadRoot(localPart = REQUEST_LOCAL_NAME, namespace = NAMESPACE_URI)
    public GetOrderNumberResponse processOrderNumberRequest(
            GetOrderNumberRequest request) throws Exception {
        GetOrderNumberResponse response = null;
        try{
        response = getOrderNumberService.executeRequest(request);
        }catch(CannotCreateTransactionException e){
            logger.error(ErrorConstants.ERROR_E17);
            throw new ServiceException(ErrorConstants.ERROR_E17);
        }
        return response;
    }

}

Let me know if more details are required. Any help would be appreciated.

Bingham answered 15/12, 2011 at 13:49 Comment(0)
B
18

Finally i succeeded in reading the soap header from request and append into response. This is how my end point method looks like now:

 @PayloadRoot(localPart = REQUEST_LOCAL_NAME, namespace = NAMESPACE_URI)
    @ResponsePayload
    public GetOrderNumberResponse processOrderNumberRequest(
            @RequestPayload GetOrderNumberRequest request,
            MessageContext messageContext) throws Exception {
        logger.info("Request Received");
        // read SOAP Header from request and append in response
        SaajSoapMessage soapRequest = (SaajSoapMessage) messageContext
                .getRequest();
        SoapHeader reqheader = soapRequest.getSoapHeader();
        SaajSoapMessage soapResponse = (SaajSoapMessage) messageContext
                .getResponse();
        SoapHeader respheader = soapResponse.getSoapHeader();
        TransformerFactory transformerFactory = TransformerFactory
                .newInstance();
        Transformer transformer = transformerFactory.newTransformer();
        Iterator<SoapHeaderElement> itr = reqheader.examineAllHeaderElements();
        while (itr.hasNext()) {
            SoapHeaderElement ele = itr.next();
            transformer.transform(ele.getSource(), respheader.getResult());
        }
        // process the request PayLoad
        GetOrderNumberResponse response = null;
        try {
            response = getOrderNumberService.executeRequest(request);
        } catch (CannotCreateTransactionException e) {
            logger.error(ErrorConstants.ERROR_E17);
            throw new ServiceException(ErrorConstants.ERROR_E17);
        }
        logger.info("Response Sent");
        return response;
    }
Bingham answered 22/12, 2011 at 12:6 Comment(5)
I'm glad you figured out based on what I've posted. I agree with you it's hard to figure all out (just like when using SOAP attachments for instance).Frederick
Is this not using SOAP attachments?Littlejohn
I'm facing the same issue, so I am very glad to see your solution, I will try it tomorrow. Thank you.Wartime
@Wartime Glad to see that my solution helped you !!Bingham
how i can read those values in the header into String ?Gerrilee
F
3

This is probably only half the answer you need but I think you can read the soapheaders by getting the (Saaj)SoapMessage from the messagecontext, like this:

@PayloadRoot(
    localPart = "GetHiredCandidatesRequest", 
    namespace = DEFAULT_NAMESPACE
)
@ResponsePayload
public GetHiredCandidatesResponse getKandidaat (
    @RequestPayload GetHiredCandidatesRequest getCandidate,
    MessageContext messageContext) {

    SaajSoapMessage request = (SaajSoapMessage) messageContext.getRequest();
    SoapHeader header = request.getSoapHeader();

    GetHiredCandidatesResponse response = objectFactory.createGetHiredCandidatesResponse();
    response.getCandidate().addAll(
        candidateService.getHiredCandidates(
            getCandidate.getFrom(), 
            getCandidate.getTo()
        )
    );

    return response;
}

Since version 2 you can automatically 'add' some objects to your method's signature, like I add the MessageContext here. I have used this to get the attachments from a soap message for instance. You can probably use other subclasses of AbstractSoapMessage as well since the the getSoapHeder method is in that class.

[edit] BTW: Perhaps you can use Interceptors as well since the request / response is provided there. Take a look at the org.springframework.ws.soap.server.endpoint.interceptor package for some default examples. [/edit]

Frederick answered 19/12, 2011 at 14:46 Comment(4)
i have referred the spring docs link.i got success in reading SOAP header inside my method.i have changed my endpoint class method like this: @PayloadRoot(localPart=REQUEST_LOCAL_NAME,namespace=NAMESPACE_URI) @ResponsePayload public SaajSoapMessage processOrderNumberRequest(@RequestPayload GetOrderNumberRequest request,SoapHeader header).now it throws error java.lang.IllegalStateException:No adapter for endpoint because i have changed method return type to SaajSoapMessage from GetOrderNumberResponse. didnt workBingham
I think you cannot use SaajSoapMessage as the return type. You probably need to use GetOrderNumberResponse to match your WSDL. In my example I get the request from the MessageContext but you can get the response object as well and probably set some soap headers there.Frederick
In your example, method return type is Response. Is it the PayLoad part of the response message? I am wondering if we return the Payload part of the response which comes actually under Soap Body portion, then how the header part will be appended in the response? Moreover not getting any working code which solves this requirement. I don't want to do anything with header part, whatever comes in the request just send as it is in the response. the logic is only for calculating Payload part of the body. It sounds very general requirement for web services but very poorly documented for springWS.Bingham
Response and Request are Jaxb types. I updated my example with less confusing object names.Frederick
G
0

Much easier if you using jaxb marshaller. And this working if body and header has different namespace.

import org.springframework.ws.soap.server.endpoint.annotation.SoapHeader;//@SoapHeader

@PayloadRoot(namespace = "http://body.namespace", localPart = "getRequest")
@ResponsePayload
public JAXBElement<GetResponse> getSomething(@RequestPayload JAXBElement<GetRequest> request
        //SOAPHeader is element name from header.xsd: <xsd:element name="SOAPHeader" type="tns:HeaderType"/>
        ,@SoapHeader(value = "{http://namespace.x.com/Header/}SOAPHeader") SoapHeaderElement headerElem
        ,MessageContext messageContext) {

    try {
        JAXBContext context = JAXBContext.newInstance(HeaderType.class);
        Unmarshaller unmarshaller = context.createUnmarshaller();

        //get soapheader from request
        DOMSource headerSource = (DOMSource) headerElem.getSource();
        //unmarshall to HeaderType object, headerSource.getNode() because header has different namespace from body namespace
        //HeaderType is an xml annotated class
        HeaderType headerRequest = ((JAXBElement<HeaderType>) unmarshaller.unmarshal(headerSource.getNode(), HeaderType.class)).getValue();

        //get soapheader from response
        SaajSoapMessage soapResponse = (SaajSoapMessage) messageContext.getResponse();
        org.springframework.ws.soap.SoapHeader soapResponseHeader = soapResponse.getSoapHeader();

        //marshall headerRequest to response soapheader
        Marshaller marshaller = context.createMarshaller();
        marshaller.marshal(headerRequest, soapResponseHeader.getResult());
    } catch (JAXBException e) {
        e.printStackTrace();
    }

    //create response body message
    ObjectFactory objectFactory = new ObjectFactory();
    JAXBElement<GetResponse> response = objectFactory.createGetResponse(new GetResponse());
    response.getValue().setErrorMessage("ok");

    return response;
}
Garrity answered 29/4, 2020 at 15:0 Comment(1)
I tried to only create the JAXBContext and create the JAXBElement<T> just to see but got “Type mismatch: cannot convert from MyResponse to JAXBElement<MyResponse>.Apogee
T
0

I was setting my headers using SoapUI and trying to retrieve them in my Spring Boot Soap Web Service. Above mentioned ways did not help me. But I was able to retrieve them as MimeHeaders.

//You can simply inject MessageContext. It is Spring's MessageContext, so do not use Xml or Jakarta MessageContext. Only use Spring MessageContext
    @PayloadRoot(namespace="http://anyuriyouwant.com", localPart="getEmployeeRequest")
@ResponsePayload public JAXBElement<Employee> getEmpDetails(@RequestPayload JAXBElement<String>empCode, MessageContext messageContext){
        SaajSoapMessage request=(SaajSoapMessage) messageContext.getRequest();
        MimeHeaders headers=request.getSaajMessage().getMimeHeaders();
        String appId=headers.getHeader("your-header-name")[0];
        System.out.println("App Id from headers: "+appId);
    }
Tote answered 5/7, 2023 at 18:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.