Search code examples
javahttp-headersjax-wswebservice-client

Cannot modify http accept header in SOAP WebService client - JAX-WS 2.2.10 - JDK1.7


I migrated a webservice client from jdk1.6 jax-ws (v1 ? An old one - 2005) to jdk1.7 jax-ws 2.2.10. The old one was functional, but I have a problem with the new one : The service (from another society, php server) responds to me : http 406 error, not acceptable.

The accept header I send is :

Accept: text/xml, multipart/related
Content-Type: text/xml; charset=utf-8

With the old version, I had :

Accept: text/xml, multipart/related, text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
Content-type: text/xml;charset="utf-8"

So I tried to modify the http header like this (inside a new handler in my binding handler chain):

In my client :

    javax.xml.ws.Binding binding = ((BindingProvider) ServiceXXX).getBinding();
    List<Handler> hchain = binding.getHandlerChain();
    if (hchain == null) {hchain = new ArrayList<Handler>();}
    hchain.add(new HTTPUserAgentHandler());
    binding.setHandlerChain(hchain);

In my new handler :

Map<String, List<String>> headers = (Map<String, List<String>>) context.get(MessageContext.HTTP_REQUEST_HEADERS);
if (null == headers) {headers = new HashMap<String, List<String>>();}
headers.put("Accept", Arrays.asList("text/xml", "multipart/related", "*/*"));
context.put(MessageContext.HTTP_REQUEST_HEADERS, headers);

My http header is now correct but in HttpTransportPipe class, it's overwritten :

        reqHeaders.put("Content-Type", Collections.singletonList(ct.getContentType()));
        if (ct.getAcceptHeader() != null) {
            reqHeaders.put("Accept", Collections.singletonList(ct.getAcceptHeader()));
        }
        if (binding instanceof SOAPBinding) {
            writeSOAPAction(reqHeaders, ct.getSOAPActionHeader());
        }

The server, apparently 1.1, needs I send an accept with "*/*" Any Idea of how I can do this ?


Solution

  • I think I found a way, it's not the perfect solution ... (If someone has better ..) So : I added a file named com.sun.xml.ws.api.pipe.TransportTubeFactory in ./src/META-INF/services in which there is:

    com.YYY.XXX.MonHttpTransportTubeFactory
    

    I added this class:

    package com.YYY.XXX;
    
    import com.sun.xml.ws.api.pipe.ClientTubeAssemblerContext;
    import com.sun.xml.ws.api.pipe.TransportTubeFactory;
    import com.sun.xml.ws.api.pipe.Tube;
    import com.sun.xml.ws.transport.http.client.HttpTransportPipe;
    
    public class MonHttpTransportTubeFactory extends TransportTubeFactory{
    
        @Override
        public Tube doCreate(ClientTubeAssemblerContext context) {
            context.setCodec(new MonSOAPBindingCodec(context.getBinding().getFeatures()));
            return new HttpTransportPipe(context.getCodec(), context.getBinding());
        }
    }
    

    and this one : (copy of existing SOAPBidingCodec jaxws-ri src) :

    public class MonSOAPBindingCodec extends MonMimeCodec implements com.sun.xml.ws.api.pipe.SOAPBindingCodec {
    ...
        public MonSOAPBindingCodec(WSFeatureList features, StreamSOAPCodec xmlSoapCodec) {
            super(getSoapVersion(features), features);
    
            this.xmlSoapCodec = xmlSoapCodec;
            xmlMimeType = xmlSoapCodec.getMimeType();
    
            String clientAcceptedContentTypes = xmlSoapCodec.getMimeType() + ", */*";
    
            WebServiceFeature fi = features.get(FastInfosetFeature.class);
    ...
    

    So the service call my HttpTransportTubeFactory and includes my custom SOAP codec.

    It's not very beautiful, but it works ..