11
votes

I am trying to add implicit headers to WSDL and WADL responses for a CXF SOAP/REST web service (which is managed by Camel).

(These are not necessarily security headers....)

By "implicit header" I mean that hitting the WSDL/WADL URL of the service will show that it's expected of the client to provide the header in the request.

But I do not want to explicitly specify the header in the signature of the web service.

I have a CXF interceptor that adds an implicit header to every SOAP/REST response.

So since WSDL/WADL document are sent as a response to some GET request, I was thinking to somehow use a similar interceptor to add the header data to WSDL/WADL response. How could I carry out such a marvellous feat?

Here is the CXF interceptor that adds an implicit header to every SOAP/REST response:

public class MyInterceptor extends AbstractPhaseInterceptor<Message> {

    public MyInterceptor()
    {
        super(Phase.RECEIVE);
    }

    @Override
    public void handleMessage(Message message)
    {   
        try
        {
            //soap
            if (message instanceof SoapMessage)
            {               
                List<Header> headers = ((SoapMessage)message).getHeaders();

                Header dummyHeader = new Header(new QName("uri:org.apache.cxf", "dummy"), "decapitated", new JAXBDataBinding(String.class));

                headers.add(dummyHeader);
            }
            //rest
            else
            {
                Map<String, List> headers = (Map<String, List>) message.get(Message.PROTOCOL_HEADERS);

                String dummyHeader = "decapitated";

                headers.put("dummy", Collections.singletonList(dummyHeader));
            }

        }
        catch (JAXBException e)
        {
            throw new Fault(e);
        }
    }

    @Override
    public void handleFault(Message messageParam)
    {
    }
}
1
Do you mean : you want to modify the WSDL that would be returned by a GET call to yourService.wsdl to add an extra <wsdlsoap:header> element at the appropriate place ?GPI
Yes. In this project I create the WSDL automatically from the web service method signatures (Not WSDL to Java). However I want to avoid explicitly adding the header parameters to these methods and instead just showing (in the WSDL contract) to the clients of this service that specific headers should be included in the SOAP request.rapt

1 Answers

8
votes

CXF 2.7.4

In CXF, the WSDL is generated through an Interceptor in the in chain called the WSDLGetInterceptor, that is placed in the READ chain.

It's basic design is

  1. check if the call is a HTTP GET
  2. prepare an output message to return
  3. access the wsdl (from Java or from static ressource)
  4. write the wsdl to the output message
  5. interrupt the interceptor chain to provide the output message

The easiest way to act on this process is to preempt this interceptor from doing its job, either by registering your own implementation before.

Removing standard CXF interceptors is kind of a "hard thing to do" on a default Bus (easiest way is to register your own interceptor, put it first in the chain, and make it remove other interceptors like so message.getInterceptorChain().remove(removeInterceptor);

But adding your own just before the standard WSDL interceptor is easy :

public MyWSDLGetInterceptor() {
    super(Phase.READ);
    addBefore(WSDLGetInterceptor.class.getName());
}

The MyWSDLGetInterceptor would extend the standard WSDLGetInterceptor and you'd only override :

public Document getDocument(Message message,
                            String base,
                            Map<String, String> params,
                            String ctxUri,
                            EndpointInfo endpointInfo) {
    Document domDocument = super.getDocument(message, base, params, ctxUri, endpointInfo);
    domDocument.getChildNodes(); // Whatever you need to add remove
    return domDocument; // Once modified
}

You could modify the resulting DOM Document on the fly (add / create DOM nodes) or through XSLT, whatever suits you best, you're back to handling standard XML through a standard API.

CXF 2.7.x (where x is somewhere > 4 and < 10)

The principal is the same, but the interceptor works differently.

  1. It (in a private method) puts the WSDL, as a DOM Document as an out message property
  2. It cleans the output interceptor chain of all interceptors (except the absolute necessary)
  3. It registers a WSDLGetOutInterceptor in the output chain
  4. It stops the IN chain and proceeds to the stop chain
  5. The WSDLGetOutInterceptor does its serialization job

So it's a bit harder / less clean. But using the same principle of pre-empting the base interceptor (registering yourself just before), you could override the cleanUpOutInteceptors to manipulate the message, just as in the 2.7.4 case, by accessing the WSDL through outMessage.get(DOCUMENT_HOLDER)

WADL

Sorry, I have no expertise, but I guess CXF has the same kind of architecture for both...