Dipankar
Dipankar

Reputation: 21

How to add soap header with jaxws to soap request

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 header along with the soap body.

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

<execution>
                            <id>wsimport-profile</id>
                            <goals>
                                <goal>wsimport</goal>
                            </goals>
                            <configuration>
                                <wsdlDirectory>src/main/resources/wsdl/GPP</wsdlDirectory>
                                <wsdlFiles>
                                    <wsdlFile>LoadProfileService.wsdl</wsdlFile>
                                </wsdlFiles>
                                <packageName>com.soapbinding.service</packageName>
                                 <extension>true</extension>
                                <protocol>Xsoap1.2</protocol>
                                <xadditionalHeaders>true</xadditionalHeaders>
                            </configuration>
                        </execution>

I have trying this using JAX-WS. It does almost the same, modifies the header to add the user credentials:

public class LoadProfileSOAPHandler implements SOAPHandler<SOAPMessageContext> {

    @Log
    private Logger LOGGER;
    private String username;

    /**
     * Handles SOAP message. If SOAP header does not already exist, then method will created new SOAP header. The
     * username  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 {
                String uri = "http:/SCL/CommonTypes";
                String prefix = "q2";
                SOAPMessage message = context.getMessage();
                SOAPHeader header = message.getSOAPHeader();
                SOAPEnvelope envelope = message.getSOAPPart().getEnvelope();
                if (header == null) {
                    header = envelope.addHeader();
                }


                QName qNameFndtHeader = new QName(uri,prefix, "FndtHeader");
                SOAPHeaderElement fndtHeader = header.addHeaderElement(qNameFndtHeader);

                QName qNamecredentials = new QName(prefix, "credentials");

                QName qNameuser = new QName(prefix, "UserID");
                SOAPHeaderElement userHeader = header.addHeaderElement(qNameuser);
                userHeader.addTextNode(this.username);

                fndtHeader.addChildElement(qNameFndtHeader);
                fndtHeader.addChildElement(qNamecredentials);
                fndtHeader.addChildElement(userHeader );
                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.getMessage());
            } catch (IOException e) {
                LOGGER.error("Error occurred while writing message to output stream.", e.getMessage());
            }
            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;
    }
}

@Component("loadProfileHandlerResolver")

/**
 * Overrode in order to load custom handlers.
 * @see javax.xml.ws.handler.HandlerResolver#getHandlerChain(javax.xml.ws.handler.PortInfo)
 */
public class LoadProfileHandlerResolver implements org.springframework.context.ApplicationContextAware, HandlerResolver  {

    /*@Autowired
    LoadProfileSOAPHandler loadProfileSOAPHandler;
    */
    @Override
    public void setApplicationContext(ApplicationContext arg0)
            throws BeansException {
        ListableBeanFactory lb = (ListableBeanFactory) arg0;
        System.out.println(Arrays.toString(lb.getBeanDefinitionNames()));
    }

    public LoadProfileHandlerResolver() {
        // TODO Auto-generated constructor stub
        System.out.println("");
    }

    @Override
    public List<Handler> getHandlerChain(PortInfo arg0) {
        List<Handler> handlerChain = new ArrayList<Handler>();
        LoadProfileSOAPHandler loadProfileSOAPHandler =new LoadProfileSOAPHandler();
        handlerChain.add(loadProfileSOAPHandler);
        return handlerChain;
    }

ALSO ADDED DEPENDENCY IN APPLICATION CONFIG FILE.And I define this handler in Spring configuration like above

<bean id="loadProfilePortProxy"
    class="org.springframework.remoting.jaxws.JaxWsPortProxyFactoryBean">
    <property name="serviceInterface"
        value="com.soapbinding.gpppservice.LoadProfileServicePortType" />

    <property name="wsdlDocumentUrl" value="classpath:wsdl/GPP/LoadProfileService.wsdl" />
    <property name="namespaceUri" value="http://SCL/LoadProfileService" />
    <property name="serviceName" value="LoadProfileService" />
    <property name="endpointAddress" value="${service.loadCalenderdata}" />
    <property name="handlerResolver" ref="loadProfileHandlerResolver"/> 
</bean>

I AM GETTING AN ISSUE BELOW:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'loadProfilePortProxy' defined in class path resource [application-config.xml]: Invocation of init method failed; nested exception is java.lang.NullPointerException

due to the property name="handlerResolver" ref="loadProfileHandlerResolver" in spring application.xml

and also let me know why my wsimport is not working with xadditionalHeaders as it is not giving me the stub class with soap header which may solve the issue in other way.

<xadditionalHeaders>true</xadditionalHeaders>

Upvotes: 2

Views: 2067

Answers (1)

Dipankar
Dipankar

Reputation: 21

resolved the issue ,we are getting some what null at time of spring injection of the property ref loadProfileHandlerResolver

Thanks...

Upvotes: 0

Related Questions