Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add SOAP headers to a SOAP request using JAX-WS?

We need to consume webservices developed by other team. Using JAX-WS for generating the webservices. We are using wsimport to generate the client side stubs.

The problem is that i need to pass the following info as a header along with the SOAP body:

<soapenv:Header>
    <ns1:HeaderData xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" 
                    xmlns:ns1="http://www.example.com/esb/data_type/HeaderData/v1">
        <ChannelIdentifier>ABC</ChannelIdentifier>
    </ns1:HeaderData>
</soapenv:Header>


We are using:

BindingProvider.getRequestContext().put(
    BindingProvider.ENDPOINT_ADDRESS_PROPERTY,
    serviceConfig.getServiceEndPoint()
);

to set the endpoint.

Can anyone suggest how to pass headers with request?

Thanks, VK

like image 669
ikvenu2000 Avatar asked Sep 12 '12 12:09

ikvenu2000


2 Answers

use param header = true of @WebParam annotation

@WebMethod
@WebResult String method(
      @WebParam String anotherParam
      @WebParam(header = true, mode = Mode.OUT) Holder<String> headerParam)  

header = true, mode = Mode.OUT means that param headerParam will be only in output in header.
If you want this this param in input and in output, make Mode.INOUT

like image 187
Ilya Avatar answered Sep 27 '22 19:09

Ilya


I had to add user credentials into the header so I made it like this:

private void modifyRequest(String username, String password) {
    UserCredentials authHeader = new UserCredentials();
    authHeader.setUsername(username);
    authHeader.setPassword(password);
    ArrayList<Header> headers = new ArrayList<Header>(1);
    try {
        Header soapHeader = new Header(new QName(TQIntegrationV2.TQIntegrationV2Soap.getNamespaceURI(), "UserCredentials"), authHeader, new JAXBDataBinding(UserCredentials.class));
        headers.add(soapHeader);
    } catch (JAXBException ex) {
        LOGGER.error("Exception trying to serialize header: {}", ex);
    }
    ((BindingProvider) proxy).getRequestContext().put(Header.HEADER_LIST, headers);
}

And everything works fine. Every call to web service comes with username and password passed to this header. You can easily change this to work in your case.

EDIT

The code above is using CXF API to modify header. I have also done this using JAX-WS. It does almost the same, modifies the header to add the user credentials:

public class MyHandler implements SOAPHandler<SOAPMessageContext> {

    private static final Logger LOGGER = LoggerFactory.getLogger(MyHandler.class);

    private String username;

    private String password;

    /**
     * Handles SOAP message. If SOAP header does not already exist, then method will created new SOAP header. The
     * username and password is added to the header as the credentials to authenticate user. If no user credentials is
     * specified every call to web service will fail.
     *
     * @param context SOAP message context to get SOAP message from
     * @return true
     */
    @Override
    public boolean handleMessage(SOAPMessageContext context) {
        try {
            SOAPMessage message = context.getMessage();
            SOAPHeader header = message.getSOAPHeader();
            SOAPEnvelope envelope = message.getSOAPPart().getEnvelope();
            if (header == null) {
                header = envelope.addHeader();
            }
            QName qNameUserCredentials = new QName("https://your.target.namespace/", "UserCredentials");
            SOAPHeaderElement userCredentials = header.addHeaderElement(qNameUserCredentials);

            QName qNameUsername = new QName("https://your.target.namespace/", "Username");
            SOAPHeaderElement username = header.addHeaderElement(qNameUsername );
            username.addTextNode(this.username);
            QName qNamePassword = new QName("https://your.target.namespace/", "Password");
            SOAPHeaderElement password = header.addHeaderElement(qNamePassword);
            password.addTextNode(this.password);

            userCredentials.addChildElement(username);
            userCredentials.addChildElement(password);

            message.saveChanges();
            //TODO: remove this writer when the testing is finished
            StringWriter writer = new StringWriter();
            message.writeTo(new StringOutputStream(writer));
            LOGGER.debug("SOAP message: \n" + writer.toString());
        } catch (SOAPException e) {
            LOGGER.error("Error occurred while adding credentials to SOAP header.", e);
        } catch (IOException e) {
            LOGGER.error("Error occurred while writing message to output stream.", e);
        }
        return true;
    }

    //TODO: remove this class after testing is finished
    private static class StringOutputStream extends OutputStream {

        private StringWriter writer;

        public StringOutputStream(StringWriter writer) {
            this.writer = writer;
        }

        @Override
        public void write(int b) throws IOException {
            writer.write(b);
        }
    }

    @Override
    public boolean handleFault(SOAPMessageContext context) {
        LOGGER.debug("handleFault has been invoked.");
        return true;
    }

    @Override
    public void close(MessageContext context) {
        LOGGER.debug("close has been invoked.");
    }

    @Override
    public Set<QName> getHeaders() {
        LOGGER.debug("getHeaders has been invoked.");
        return null;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

And I define this handler in Spring configuration like this:

<bean id="soapHandler" class="your.package.MyHandler">
    <property name="username" value="testUser"/>
    <property name="password" value="testPassword"/>
</bean>

<jaxws:client "...">
    <jaxws:handlers>
        <ref bean="soapHandler"/>
    </jaxws:handlers>
</jaxws:client>

All you need to do is to implement SOAPHandler<SOAPMessageContext> interface, override its methods and then you can do what ever you want with a SOAP message.

like image 28
Paulius Matulionis Avatar answered Sep 27 '22 20:09

Paulius Matulionis