Mark Pope
Mark Pope

Reputation: 11264

Add SoapHeader to org.springframework.ws.WebServiceMessage

How can I add an object into the soap header of a org.springframework.ws.WebServiceMessage

This is the structure I'm looking to end up with:

 <soap:Header>
    <credentials xmlns="http://example.com/auth">
      <username>username</username>
      <password>password</password>
    </credentials>
  </soap:Header>

Upvotes: 29

Views: 58904

Answers (6)

SumataPatil
SumataPatil

Reputation: 97

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;

}

Upvotes: 5

Pascal Thivent
Pascal Thivent

Reputation: 570285

Basically, you need to use a WebServiceMessageCallback in your client to modify the message after its creation but before it is sent. To rest of the code has been described pretty accurately by @skaffman so the whole stuff might look like this:

public void marshalWithSoapActionHeader(MyObject o) {

    webServiceTemplate.marshalSendAndReceive(o, new WebServiceMessageCallback() {

        public void doWithMessage(WebServiceMessage message) {
            try {
                SoapMessage soapMessage = (SoapMessage)message;
                SoapHeader header = soapMessage.getSoapHeader();
                StringSource headerSource = new StringSource("<credentials xmlns=\"http://example.com/auth\">\n +
                        <username>"+username+"</username>\n +
                        <password>"+password"+</password>\n +
                        </credentials>");
                Transformer transformer = TransformerFactory.newInstance().newTransformer();
                transformer.transform(headerSource, header.getResult());
            } catch (Exception e) {
                // exception handling
            }
        }
    });
}

Personally, I find that Spring-WS sucks hard for such a basic need, they should fix SWS-479.

Upvotes: 43

sundeep katiyar
sundeep katiyar

Reputation: 1

Response response = (Response)getWebServiceTemplate() .marshalSendAndReceive(request, new HeaderModifier());

Create class HeaderModifier and override doWithMessage

public class HeaderModifier implements WebServiceMessageCallback {

     private static PrintStream out = System.out;
     
    @Override
    public void doWithMessage(WebServiceMessage message) throws IOException {
          SaajSoapMessage soapMessage = (SaajSoapMessage) message;

                SoapEnvelope soapEnvelope = soapMessage.getEnvelope();
                SoapHeader soapHeader = soapEnvelope.getHeader();
                
                //Initialize QName for Action and To 
                QName action = new QName("{uri}","Action","{actionname}");
                QName to = new QName("{uri}","To","{actionname}");
                
                
                soapHeader.addNamespaceDeclaration("{actionname}", "{uri}");
                
            
                SoapHeaderElement soapHeaderElementAction = soapHeader.addHeaderElement(action);
                SoapHeaderElement soapHeaderElementTo =  soapHeader.addHeaderElement(to);
                
                
            
                soapHeaderElementAction.setText("{text inside the tags}");
                
            
                soapHeaderElementTo.setText("{text inside the tags}");
                
            
                soapMessage.setSoapAction("{add soap action uri}");
                
            
                soapMessage.writeTo(out);
        
    }
}

Upvotes: -1

mareck_ste
mareck_ste

Reputation: 517

You can achieve it by creating key-value map of child elements as well:

final Map<String, String> elements = new HashMap<>();
elements.put("username", "username");
elements.put("password", "password");

Set up namespace and prefix of your child element within the soap header:

final String LOCAL_NAME = "credentials";
final String PREFIX = "";
final String NAMESPACE = "http://example.com/auth";

Then, you can invoke WebServiceTemplate's method marshalSendAndReceive where you override WebServiceMessageCallback's method doWithMessage as follows:

Object response = getWebServiceTemplate().marshalSendAndReceive(request, (message) -> {
    if (message instanceof SaajSoapMessage) {
        SaajSoapMessage saajSoapMessage = (SaajSoapMessage) message;
        SOAPMessage soapMessage = saajSoapMessage.getSaajMessage();
        SOAPPart soapPart = soapMessage.getSOAPPart();

        if (Objects.nonNull(elements)) {
            try {
                SOAPEnvelope soapEnvelope = soapPart.getEnvelope();
                SOAPHeader soapHeader = soapEnvelope.getHeader();
                Name headerElementName = soapEnvelope.createName(
                        LOCAL_NAME,
                        PREFIX,
                        NAMESPACE
                );
                SOAPHeaderElement soapHeaderElement = soapHeader.addHeaderElement(headerElementName);

                elements.forEach((key, value) -> {
                    try {
                        SOAPElement element = soapHeaderElement.addChildElement(key, PREFIX);
                        element.addTextNode(value);
                    } catch (SOAPException e) {
                        // error handling
                    }
                });

                soapMessage.saveChanges();
            } catch (SOAPException e) {
                // error handling
            }
        }
    }
});

The above steps result in:

<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope">
   <env:Header>
      <credentials xmlns="http://example.com/auth">
         <password>password</password>
         <username>username</username>
      </credentials>
   </env:Header>
   <env:Body>
      <!--  your payload -->
   </env:Body>
</env:Envelope>

Upvotes: 0

pranav kumar
pranav kumar

Reputation: 181

You can do as below:

public class SoapRequestHeaderModifier implements WebServiceMessageCallback {
 private final String userName = "user";
 private final String passWd = "passwd";

 @Override
 public void doWithMessage(WebServiceMessage message) throws IOException, TransformerException {
  if (message instanceof SaajSoapMessage) {
   SaajSoapMessage soapMessage = (SaajSoapMessage) message;
   MimeHeaders mimeHeader = soapMessage.getSaajMessage().getMimeHeaders();
   mimeHeader.setHeader("Authorization", getB64Auth(userName, passWd));
  }
 }

 private String getB64Auth(String login, String pass) {
  String source = login + ":" + pass;
  String retunVal = "Basic " + Base64.getUrlEncoder().encodeToString(source.getBytes());
  return retunVal;
 }
}

Then

Object response = getWebServiceTemplate().marshalSendAndReceive(request, new SoapRequestHeaderModifier());

Upvotes: 18

skaffman
skaffman

Reputation: 403441

You need to cast the WebServiceMessage to SoapMessage, which has a getSoapHeader() method you can use to modify the header. In turn, SoapHeader has various methods for adding elements, including getResult() (which can be used as the output of a Transformer.transform() operation).

Upvotes: 5

Related Questions