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 Eclipse Implementation of Jakarta XML Web Services
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 create a
SOAPHandler
and mess with Jakarta SOAP with Attachments,
but the Eclipse Implementation of Jakarta XML Web Services provides a
better way of doing this.
When you create a proxy or dispatch object, they implement
BindingProvider
interface. When you use the Eclipse
Implementation of Jakarta XML Web Services,
you can downcast to WSBindingProvider
which
defines a few more methods provided only by the Eclipse
Implementation of Jakarta XML Web Services.
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 Jakarta
XML Web Services 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
wsimport has an 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);
SOAP messages are not validated against schemas by default with
the Eclipse Implementation of Jakarta XML Web Services. However, this
can be enabled for doc/lit cases. The Eclipse Implementation of Jakarta
XML Web Services 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