Links: Table of Contents | Single HTML | Single PDF

Chapter 4. SOAP

Table of Contents

4.1. SOAP headers
4.1.1. Adding SOAP headers when sending requests
4.1.2. Accessing SOAP headers for incoming messages
4.1.3. Adding SOAP headers when sending replies
4.1.4. Mapping additional WSDL headers to method parameters
4.2. Schema Validation
4.2.1. Server Side Schema Validation
4.2.2. Client Side Schema Validation

4.1. SOAP headers

When the WSDL you are compiling specifies that some parts of a message are bound to SOAP headers, wsimport generates the right stuff (@WebParam (header=true)), so you can pass headers as arguments to the method invocation. When starting from Java, you can use this same annotation to indicate that some parameters be sent as headers.

That said, there are many WSDLs out there that do not specify SOAP headers explicitly, yet the protocol still requires such headers to be sent, so the JAX-WS RI offers convenient ways for you to send/receive additional headers at runtime.

4.1.1. Adding SOAP headers when sending requests

The portable way of doing this is that you creaate a SOAPHandler and mess with SAAJ, but the RI provides a better way of doing this.

When you create a proxy or dispatch object, they implement BindingProvider interface. When you use the JAX-WS RI, you can downcast to WSBindingProvider which defines a few more methods provided only by the JAX-WS RI.

This interface lets you set an arbitrary number of Header object, each representing a SOAP header. You can implement it on your own if you want, but most likely you'd use one of the factory methods defined on Headers class to create one.

Example 4.1. Adding custom headers

import com.sun.xml.ws.developer.WSBindingProvider;

HelloPort port = helloService.getHelloPort();  // or something like that...
WSBindingProvider bp = (WSBindingProvider) port;

bp.setOutboundHeader(
        // simple string value as a header, 
        // like <simpleHeader>stringValue</simpleHeader>
        Headers.create(new QName("simpleHeader"), "stringValue"),
        // create a header from JAXB object
        Headers.create(jaxbContext, myJaxbObject)
);

Once set, it will take effect on all the successive methods. If you'd like to see more factory methods on Headers, please let us know.

4.1.2. Accessing SOAP headers for incoming messages

Server can access all the SOAP headers of the incoming messages by using the JAXWSProperties#INBOUND_HEADER_LIST_PROPERTY property like this:

Example 4.2. Accessing incoming headers

@WebService
public class FooService {
    @Resource
    WebServiceContext context;

    @WebMethod
    public void sayHelloTo(String name) {
        HeaderList hl = context.getMessageContext().get(JAXWSProperties
                .INBOUND_HEADER_LIST_PROPERTY);
        Header h = hl.get(MYHEADER);
    }

    private static final QName MYHEADER = new QName("myNsUri", "myHeader");
}

Clients can similarly access all the SOAP headers of the incoming messages:

Example 4.3. Accessing incoming headers

HelloPort port = helloService.getHelloPort();  // or something like that...
port.sayHelloTo("duke");
HeaderList hl = port.getResponseContext().get(JAXWSProperties
        .INBOUND_HEADER_LIST_PROPERTY);
Header h = hl.get(MYHEADER);

See the Header interface for more details about how to access the header values.

4.1.3. Adding SOAP headers when sending replies

Servers tend to be developed "from-Java" style, so we feel the necessity of adding out-of-band headers is smaller (you can just define headers as method @WebParam(mode=OUT,header=true) parameters.) Therefore, currently there's no support for adding out-of-band SOAP headers into response messages.

If you'd like us to improve on this front, please let us know.

4.1.4. Mapping additional WSDL headers to method parameters

Sometimes WSDLs in the binding section reference soap:header messages that are not part of the input or output contract defined in the portType operation. For example:

Example 4.4. Sample WSDL with additional header bindings

<message name="additionalHeader">
   <part name="additionalHeader" element="types:additionalHeader"/>
</message>

<wsdl:portType name="HelloPortType">
   <wsdl:operation name="echo">
      <wsdl:input message="tns:echoRequest"/>
      <wsdl:output message="tns:echoResponse"/>
   </wsdl:operation>
</wsdl:portType>

<wsdl:binding name="HelloBinding" type="tns:HelloPortType">
   <soap:binding style="document"
                 transport="http://schemas.xmlsoap.org/soap/http"/>
   <wsdl:operation name="echo">
      <soap:operation/>
      <wsdl:input>
         <soap:body message="tns:echoRequest"/>
         <soap:header message="tns:additionalHeader"
                      part="additionalHeader"/>
      </wsdl:input>
      <wsdl:output>
         <soap:body message="tns:echoResponse"/>
      </wsdl:output>
   </wsdl:operation>
</wsdl:binding>

In the above schema in the wsdl:binding section tns:additionalHeader is bound but if you see this header is not part of the echo abstract contract (i.e., the wsdl:portType section). According to JAX-WS 2.1 specification only the wsdl:part's from the abstract portion are mapped to Java method parameters.

Running wsimport on this wsdl will generate this method signature:

wsimport sample.wsdl

Example 4.5. Default mapping

public String echo(String request);

Note

Since JAX-WS RI 2.1.3, wsimport has a new option -XadditionalHeaders, this option will map such additional headers as method parameters.

wsimport -XadditionalHeaders sample.wsdl

Example 4.6. WSDL to Java mapping with -XadditionalHeaders switch

public String echo(String request, String additionalHeader);

4.2. Schema Validation

SOAP messages are not validated against schemas by default with the JAX-WS RI. However, this can be enabled for doc/lit cases. The JAXWS-RI uses JAXP's SchemaFactory API to do the validation.

4.2.1. Server Side Schema Validation

The @SchemaValidation annotation needs to be specified on the endpoint implementation to enable server side validation. Both the incoming SOAP request and outgoing SOAP response will be validated, with exceptions returned to the client for any validation errors that occur.

Example 4.7. Enabling Schema Validation for an Endpoint

import com.sun.xml.ws.developer.SchemaValidation;
...

@SchemaValidation
@WebService
public class HelloImpl {
}

If a application wants to have complete control over validation error handling, it can set up a ValidationErrorHandler to receive notification of errors. The handler has access to the Packet and can store any information in its invocationProperties. These properties are accessible from the endpoint's MessageContext.

Example 4.8. Customizing Schema Validation

@SchemaValidation(handler = MyErrorHandler.class)
@WebService
public class HelloImpl {
}

import com.sun.xml.ws.developer.ValidationErrorHandler;
import org.xml.sax.SAXParseException;
import org.xml.sax.SAXException;

public class MyErrorHandler extends ValidationErrorHandler {
    public void warning(SAXParseException e) throws SAXException {
        // Store warnings in the packet so that they can be retrieved 
        // from the endpoint
        packet.invocationProperties.put("error", e);
    }

    public void error(SAXParseException e) throws SAXException {
        throw e;
    }

    public void fatalError(SAXParseException e) throws SAXException {
        ; // noop
    }
}

4.2.2. Client Side Schema Validation

Proxy needs to be created with SchemaValidationFeature to enable client side validation. Both the outgoing SOAP request and incoming SOAP response will be validated.

Example 4.9. Enabling Proxy with Schema Validation

import com.sun.xml.ws.developer.SchemaValidationFeature;
...

SchemaValidationFeature feature = new SchemaValidationFeature();
HelloPort port = new HelloService.getHelloPort(feature);
// All invocations on this port are validated

If a client application wants to have complete control over validation error handling, it can set up a ValidationErrorHandler to receive notification of errors. The handler has access to the Packet and can store any information in its invocationProperties. These properties are accessible from proxy's response context.

Example 4.10. Customizing Schema Validation

SchemaValidationFeature feature =
        new SchemaValidationFeature(MyErrorHandler.class);
HelloPort port = new HelloService.getHelloPort(feature);
// All invocations on this port will be validated