In this article, we will look at JAX-WS server side looking at techniques for validation and fault processing in detail as well as Server Side Handlers and deployment with endpoints. This is fourth article on JAX-WS. This is part of a larger series of articles to help you prepare for the web service developer exam. You can review the all three articles on JAX-WS, “Tutorial:Review of JAX-WS Client Side for the Web Service Developer Exam”, “Tutorial:Review of JAX-WS Client Side for the Web Service Developer Exam II” and “Tutorial:Review of JAX-WS Server Side for the Web Service Developer Exam” if needed.

JAX-WS Server Side Processing

In the last article we focused on the JAX-WS API and runtime behaviour on the server side. We looked at how to use it for JAXB processing, DOM processing and in conjunction with legacy classes and a custom Java/XML mapping tool. We will continue our discussion on JAX-WS server side by looking at validation and fault processing.

Validation and Fault Processing

For any Web service, it is impossible to overlook both validation and fault processing. Validation is critical as it is much more efficient to reject an XML message as invalid based on its structure rather than allow an unpredictable failure to occur during the business logic processing of the bad data. Fault processing is also critical because any exception thrown in Java will in most cases, need to be translated into a SOAP fault in order to be returned to the client informing them as to why the Web service invocation failed. Without this fault processing layer already being provided, you would spend inordinate amounts of time, writing most of the low level code for this yourself. you had to write your own fault processing layer, you would be in for a lot of work. Fortunately SOAP fault processing is provided by JAX-WS in the SOAP/HTTP protocol binding. This is shown in the figure below:

Tutorial:Review of JAX-WS Server Side for the Web Service Developer Exam II-b8-jax-ws_ss_invoc_sys.jpg
Figure: JAX-WS Server Side Invocation System

We will cover how to implement validation and leverage existing JAX-WS fault processing infrastructure to handle fault processing.

What is Validation?

A service implementation bean development starts with a WSDL document. As as WSDL document is derived from XML Schema, it is possible for you to validate incoming SOAP messages against the WSDL types to ensure it’s validity. You can use JAXB outside of JAX-WS to turn on validation by using the setSchema() methods that are part of the Marshaller and Unmarshaller. The schema is provided as an instance of javax.xml.validation.Schema, and JAXB will validate against it when the SOAP message is marshalled or unmarshalled.

In JAX-WS 2.0 it is not possible to enable JAXB validation in this manner therefore you need to implement validation of the SOAP messages using WSDL documents yourself. In order do this, you will first need to access the associated WSDL. This is done via dependency injection to obtain an instance of the Web service context. The listing below shows how to use dependency injection:

Java Code: Dependency Injection
@Resource WebServiceContext webServiceContext;
Once you obtain the WebServiceContext, you can then obtain the WSDL. The process is that from the WebServiceContext, you can then obtain the MessageContext. As we will deploy the SEI as a servlet endpoint, in order to obtain the WSDL, we need to get the ServletContext which allows you to access WSDL that are located under WEB-INF directory. The listing below shows how to access the WSDL from the servlet endpoint:

Java Code: WebServiceContext Used to Access WSDL
if ( webServiceContext == null ) {
  throw new RuntimeException("WebServiceContext not injected.");
}
MessageContext mc = webServiceContext.getMessageContext();
ServletContext sc = (ServletContext) mc.get(MessageContext.SERVLET_CONTEXT);
if ( sc == null ) {
  throw new RuntimeException("ServletContext is null.");
}
InputStream wsdlStream = 
  sc.getResourceAsStream("/WEB-INF/wsdl/RequestOrder.wsdl");
Once you have the WSDL, you need to extract the XML schemas from its <types> section and use these for validation. This can be done using the DOM API. The process is to first access the InputStream wsdlStream and then load it into a DOM Document instance. Next we use the getElementsByTagNameNS method to extract the xs:schema nodes and then loop through the nodes and use the DOM API to copy the xs:schema nodes into an array. This is required because the xs:schema nodes when extracted from the WSDL’s DOM tree will not all have the required namespace prefix attributes. Therefore we take all the namespace declarations from the WSDL and add them to each xs:schema node copy in order to create a valid stand-alone schema. The listing below shows how this is done:

Java Code: Extract Schema from WSDL for SOAP Validation
DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = dbfac.newDocumentBuilder();
Document wsdlDoc = docBuilder.newDocument();
Transformer xformer = TransformerFactory.newInstance().newTransformer();
xformer.transform(new StreamSource(wsdlStream), new DOMResult(wsdlDoc));
NodeList schemaNodes = wsdlDoc.getElementsByTagNameNS(
XMLConstants.W3C_XML_SCHEMA_NS_URI, "schema");
int numOfSchemas = schemaNodes.getLength();
Source[] schemas = new Source[numOfSchemas];
Document schemaDoc;
Element schemaElt;
for (int i=0; i < numOfSchemas; i++) {
  schemaDoc = docBuilder.newDocument();
  NamedNodeMap nsDecls = getNamespaces((Element) schemaNodes.item(i));
  schemaElt = (Element) schemaDoc.importNode(schemaNodes.item(i), true);
  for (int j=0; j<nsDecls.getLength(); j++) {
Attr a = (Attr) schemaDoc.importNode(nsDecls.item(j), true);
schemaElt.setAttributeNodeNS(a);
  }
  schemaDoc.appendChild(schemaElt);
  schemas[i] = new DOMSource(schemaDoc);
}
SchemaFactory schemaFac = SchemaFactory.
newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = schemaFac.newSchema(schemas);
Validator validator = schema.newValidator();
if (!DOMSource.class.isInstance(payload) &&
!SAXSource.class.isInstance(payload) ) {
  Document payloadDoc = docBuilder.newDocument();
  xformer.transform(payload, new DOMResult(payloadDoc));
  payload = new DOMSource(payloadDoc);
}
try {
  validator.validate(payload);
} catch (SAXException se) {
  se.printStackTrace();
  return "validation error: " + se.getMessage();
} catch (IOException e) {
  e.printStackTrace();
  return "validation error: " + e.getMessage();
}
return null;
In the listing above once we have created an array of type Source[] that holds the schemas, we provide this array as an argument for the javax.xml.validation.SchemaFactory instance used to create a java.xml.validation.Schema instance. Now we are in a position to obtain the JAXP Validator. The class for this is javax.xml.validation.Validator. It is used to validate the XML payload. Note that as the Validator is guaranteed to work with either a DOMSource or SAXSource, a check is done to make sure it is a type with which it can work. If it was a StreamSource, the Validator wouldn’t work and would be transformed into a DOMSource if required. We will look at how to address situation where the validation fails using JAX-WS fault processing.

JAX-WS Fault Processing

There is a tag, wsdl:fault which is part of the WSDL specification used for specifying fault messages. The majority of SOAP faults that are emitted by a Web service will conform to one of the existing WSDL’s wsdl:fault message formats. There are other SOAP faults that don’t related to WSDL interface definitions that don’t include wsdl:fault declarations. In this case, you emit a SOAP fault of unspecified type when there is a problem. We distinguish between Java exceptions that we can be mapped to a wsdl:fault message (i.e. mapped exceptions) and those that we have to represent as generic SOAP faults (i.e. unmapped exceptions). For example, an exception thrown because of a input message validation failure would be considered a mapped exception since the creator of the WSDL could anticipate such an exception and define a wsdl:fault message for it. Otherwise for exceptions that result from unanticipated run-time errors, they will not have a corresponding wsdl:fault message and should be returned as generic SOAP faults.

The JAX-WS WSDL to Java mapping binds wsdl:fault messages to generate subclasses of java.lang.Exception. When you generate a SEI from a WSDL, these mapped exception classes are also generated. Therefore if you implement your Web service using a service endpoint interface mapped from a wsdl:portType, you can throw a mapped exception which the JAX-WS runtime will translate automatically into the corresponding wsdl:fault message and wrap it into a SOAP body so that it can be returned as a SOAP fault. This approach is shown in the listing below:.

Java Code: SEI Implementation with wsdl:fault being returned
InputMessageValidationFaultType ft = new InputMessageValidationFaultType();
if ( custNum == null ) {
  ft.setMsg("Customer Number cannot be null.");
  throw new InputFault("Input parameter failed validation.", ft);
}
if ( poNum == null && ccard == null ) {
  ft.setMsg("Must supply either a PO or a CCard.");
  throw new InputFault("Input parameter failed validation.", ft);
}
if ( itemList == null || itemList.isEmpty() ) {
  ft.setMsg("Must have a least one item.");
  throw new InputFault("Input parameter failed validation.", ft);
}
In the listing, there are two generated classes:
  • InputMessageValidationFaultType - which is mapped from the XML schema definition referenced by the wsdl:fault message.
  • InputFault - which is mapped from the wsdl:message corresponding to this wsdl:fault itself. In this class, InputFault is the name of this wsdl:message and JAX-WS has generated a mapped exception also called InputFault.

As the fault mapping can be confusing, we show below a listing with the part of the WSDL, where the wsdl:fault is defined inside the wsdl:portType definition.

XML Code: Section of WSDL showind wsdl:fault Definition
<wsdl:message name="inputFault">
    <wsdl:part name="parameters" element="faults:inputMessageValidationFault"/>
  </wsdl:message>
  <wsdl:portType name="RequestOrderPort">
    <wsdl:operation name="requestOrder">
      <wsdl:input message="req:request"/>
      <wsdl:output message="req:response"/>
      <wsdl:fault name="requestOrderInputFault" message="req:inputFault"/>
    </wsdl:operation>
  </wsdl:portType>
In this listing we have a wsdl:fault called requestOrderInputFault that references the message req:inputFault. Then we have the JAX-WS message called req:inputFault which is mapped to the mapped exception InputFault. JAX-WS is then used to generate the Java code for InputFault. The @WebFault annotation is used by JAX-WS to identify this class as a mapped exception. This class is a simple wrapper for the InputMessageValidationFaultType class. The wrapped Java type is considered as the fault bean by JAX-WS. The fault bean is a JavaBean mapped by JAX-WS to a global element declaration referred to by that wsdl:part’s element attribute. The wsdl:fault element inside a wsdl:portType refers to a wsdl:message containing a single wsdl:part with an element attribute. This is shown in the listing below:

Java Code: Mapped Exception Generated by JAX-WS
@WebFault(name = "inputMessageValidationFault", 
    targetNamespace = "http://www.acme.com/faults")
    public class InputFault
    extends Exception {
  
  private InputMessageValidationFaultType faultInfo;
  
  public InputFault(String message, InputMessageValidationFaultType faultInfo) {
    super(message);
    this.faultInfo = faultInfo;
}
If we look at the schema from which JAX-WS generates the fault bean, InputMessageValidationFaultType, we import the schema, http:// acme.com/faults/faults.xsd to leverage. This is shown in the listing below:

XML Code: Schema Referenced by wsdl:part of inputFault wsdl:message
<xs:schema targetNamespace="http://www.acme.com/faults"
  xmlns:faults="http://www.acme.com/faults" elementFormDefault="qualified"
  xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="inputMessageValidationFault"
    type="faults:InputMessageValidationFaultType"/>
  <xs:complexType name="InputMessageValidationFaultType">
    <xs:attribute name="msg" type="xs:string"/>
  </xs:complexType>
</xs:schema>
The schema only has one attribute called msg that holds an xs:string, intended to hold a description of the fault. In a production system, the schema would most likely be much more complex holding detailed information about the cause of a each fault. In that situation, what is important is the information the user receives via the InputMessageValidationFaultType, that there was a validation failure and that the SOAP message is not considered valid in relation to the WSDL. As we previously mentioned, JAX-WS generates the fault bean based on the schema. In the listing below is shown the fault bean generated from the schema shown above. It contains, just as our schema did, one property corresponding to the msg attribute in the schema. This is shown below:

Java Code: JAX-WS Generated InputMessageValidationFaultType fault bean
@XmlAccessorType(AccessType.FIELD)
@XmlType(name = "InputMessageValidationFaultType")
public class InputMessageValidationFaultType {
  
  @XmlAttribute
  protected String msg;
  
  public String getMsg() {
    return msg;
  }
  
  public void setMsg(String value) {
    this.msg = value;
  }
}
So in the listing showing the wsdl:fault from a service endpoint interface implementation, we can now see that first the different input validation failures (i.e., null customer number, missing purchasing information, an empty item list) that can occur are identified. For each validation failure, the msg property of the InputMessageValidationFaultType is set with an appropriate message. Next an instance of InputFault is constructed with the generic error message “Input parameter failed validation.” , from the fault bean. When JAX-WS marshals the InputFault exception out to a SOAP 1.1 fault message, the InputFault.getMessage() and the InputMessageValidationFaultType.getMsg() strings are mapped to different locations. There a numerous types of Java exceptions that are mapped to JAX-WS. In the figure below we show some of the main exceptions and their mappings:

Tutorial:Review of JAX-WS Server Side for the Web Service Developer Exam II-b8-mapping_jax-ws-exceptions.jpg
Figure: Mapping via JAX-WS of Exceptions to SOAP 1.1 Fault Message Structure

In the figure, we have numbered the components in order to facilitate your understanding of the mapping between the exceptions and the SOAP Fault message structure. This is described below:
  1. A SOAPFaultException wraps a javax.xml.soap.SOAPFault that is mapped directly to a SOAP 1.1 fault message. The getFaultString method maps to the faultstring element.
  2. The getFaultCodeAsQName method maps to the faultcode.
  3. The getFaultActor method maps to the faultactor element.
  4. The SOAPFault class references an instance of javax.xml.soap.Detail. This instance represents the detail element of a SOAP fault message. A Detail object is a container for javax.xml.soap.DetailEntry instances which map to a child element of the SOAP fault’s detail element.
  5. The fault bean is wrapped by the mapped exception corresponding to the detail element of the SOAP fault message.
  6. @WebFault annotates a mapped exception and the faultcode corresponding to a mapped exception is always SOAP-ENV:Server. There are other exceptions besides SOAPFaultExceptions and @WebFault mapped exceptions that are transformed by JAX-WS into SOAP fault messages. For a general exception, the faultcode also gets the default value of ENV:Server.
  7. The faultstring corresponding to a mapped exception or a general exception is mapped from the getMessage() method, unless the method returns null. In this case, it is mapped from getString().

There is an alternative means of doing fault processing that instead of using a fault bean, involves the construction of an instance of the SAAJ class javax.xml.ws.soap.SOAPFaultException. From within a service implementation, throwing a SOAPFaultException will cause the JAX-WS runtime to convert the exception to a SOAP fault message and return it to the client. This approach can be useful in two circumstances:
  • When you are not working with a SEI and cannot leverage any mapped exceptions.
  • When you are working with a SEI but must handle an exception that doesn’t have a corresponding wsdl:fault.

The listing below demonstrates when you are not working with a service endpoint interface. We are using a Provider implementation of the WSDL contract for this example and is useful when the mapped InputFault is not available. Instead the exception is transformed by JAX-WS into a SOAP fault message with the same structure. The listing is shown below:

Java Code: Provider T Implementation with wsdl:fault using SOAPFaultException
String errorMsg = validateAgainstWSDL(payload);
if ( errorMsg != null ) {
  SOAPFactory fac = SOAPFactory.newInstance(); 
  SOAPFault sf = fac.createFault(
"SOAP payload is invalid with respect to WSDL.",
new QName("http://schemas.xmlsoap.org/soap/envelope/", "Client"));
  Detail d = sf.addDetail();
  SOAPElement de = d.addChildElement(new QName(
"http://www.acme.com/faults", "inputMessageValidationFault"));
  de.addAttribute(new QName("", "msg"), errorMsg.replaceAll("\"",""));
  throw new SOAPFaultException(sf);
}
First we get the results of the validateAgainstWSDL() method. If the method returns a non-null string, the validation has failed and the string contains the error message. The message now needs to be transformed into a SOAP fault so we obtain a javax.xml.soap.SOAPFactory and use it to construct a SOAPFault. The fault string passed to the constructor is "SOAP payload is invalid with respect to WSDL.". This explains the general cause of the input validation failure. The second parameter passed to the constructor is the faultcode, ENV:Client which indicates that the client is responsible for the fault. Now that we have constructed a SOAPFault, we use the addDetail method to add detail. The addDetail() method to create an empty Detail object which will be filled by a newly created SOAPElement that contains the faults:inputMessageValidationFault shown as part of the schema referenced by the wsdl:part of the inputFault wsdl:message. This is all created by manipulating XML with the SAAJ API. If a SOAP client written with JAX-WS that uses the SEI generated from the WSDL, when it receives a SOAP fault message, the client will map the SOAP fault to the InputFault mapped exception. This is done irregardless of whether the SOAP fault comes from an InputFault instance or a SOAPFaultException. An example of a log from this type of Java client after receiving an exception is shown below:

XML Code: wsdl:fault Received by Client as InputFault
InputFault.getMessage() =

  SOAP payload is invalid with respect to WSDL.

InputFault.getFaultInfo.getMsg() =
  
  validation error: cvc-complex-type.2.4.a: Invalid content was found starting
  with element 'ns1:ccard'. One of '{http://www.acme.com/req:CUST_NO}' 
  is expected.
The listing shows that the InputFault.getFaultInfo.getMsg() returns the detail element with the error message from the server-side validation indicating a parse error because the SOAP request lacked the required element req:CUST_NO.

Another example of listing showing when a JAX-WS will return a SOAP fault message. In this case, the exception thrown is a general javax.xml.ws.WebServiceException. This is the base exception class for all JAX-WS run-time exceptions. This error is a business logic error because of an expired credit card. In this case, we would normally fault the designer of the WSDL since this type of exception could be anticipated and we would expect that an exception would map to one of the wsdl:fault messages. But it can happen that not all your business logic exceptions map neatly into a mapped exception. In this listing we get JAX-WS to produce a SOAP fault that conveys some of the information relevant to the business logic exception by constructing a WebServiceException with the fault string "Expired ccard."

Java Code: WebServiceException mapped to SOAP Fault by the Container
Element expireDateElt = (Element) ccardElt.getElementsByTagNameNS(
    OMS_NS, "CC_EXPIRE_DATE").item(0);
String expireDateStr =
  ((Text) expireDateElt.getFirstChild()).getNodeValue();
String today = dateAsString(new GregorianCalendar());
if (expireDateStr.compareTo(today) < 0 ) {
  throw new WebServiceException("Expired ccard.");
}
Below is the SOAP fault message generated by JAX-WS for this WebServiceException:

XML Code: SOAP Fault From WebServiceException
<SOAP-ENV:Fault xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
  <faultstring>Expired ccard.</faultstring>
  <faultcode>SOAP-ENV:Server</faultcode>
</SOAP-ENV:Fault>
Note that the faultcode is SOAP_ENV:Server, the default mapping for WebServiceException. But remember that the problem here was a client-side data issue due to an expired credit card being entered. To produce a more accurate SOAP fault message, you would use the SAAJ API to create a SOAPFaultException. The listing below demonstrates this:

Java Code: Mapping of Error to SOAP Fault with Detail Using SOAPFaultException
if ( hasExpired(ccard) ) {
  try {
    SOAPFactory fac = SOAPFactory.newInstance(); 
    SOAPFault sf = fac.createFault("Business logic exception",
  new QName("http://schemas.xmlsoap.org/soap/envelope/", "Client"));
    Detail d = sf.addDetail();
    DetailEntry de = d.addDetailEntry(
  new QName("", "expiredCC"));
    de.setValue("Credit card has expired");
    throw new SOAPFaultException(sf);
  } catch (SOAPException e) {
    throw new RuntimeException(
  "Failed to create SOAPFault: " + e.getMessage());
  }
}
This is a more reflection of the SOAP-ENV:Client as well as a detailed explanation that the problem is an expired credit card. The listing below shows the SOAP fault message that is produced:

Java Code: SOAP Fault Detailing a Credit Card Exception
<SOAP-ENV:Fault xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
  <faultstring>Business logic exception</faultstring>
  <faultcode>SOAP-ENV:Client</faultcode>
  <detail>
    <expiredCC>Credit card has expired</expiredCC>
  </detail>
</SOAP-ENV:Fault>
We have now covered using JAX-WS exception handling and SOAP fault mapping. It should be possible for you to use JAX-WS to generate SOAP faults consistent with high quality web service.

Working with Server-Side Handlers

Server-Side handlers are used to implement pre-processing and post-processing of a MessageContext before the invocation of the service implementation bean. In JAX-WS, the server-side handlers are configured with the @HandlerChain annotation. The @HandlerChain annotation references a configuration file that describes the handlers that are included in the chain. The listing below shows how the @HandlerChain annotation is used:

Java Code: Example of @HandlerChain
@HandlerChain(file="handlerchain.xml")
@WebService(targetNamespace = "http://www.acme.com/req", 
    endpointInterface="com.acme.req.RequestOrderPort",
    wsdlLocation="WEB-INF/wsdl/RequestOrder.wsdl")
public class RequestOrder implements RequestOrderPort {
In the listing, the @HandlerChain annotation is included in conjunction with either @WebService or @WebServiceProvider for the declaration of the service implementation bean. The file attribute references the configuration file specified by the WSEE and WS-Metadata specifications. The file attribute can reference the either the configuration file via a URL or a relative file location from the SIB class file. You could also package the configuration file anywhere that it is accessible as a resource from the classpath.

Similarly to what is done with filters with servlets or EJBs, you can configure a handler chain to treat SOAP requests and/or responses. The configuration file for a handler chain is a XML file which has a handler-chain element representing the handler chain. Each handler-chain element, its children and handler elements should be in the order they are to be executed at runtime. If the handler is dealing with a SOAP response, it should be in the reverse order for output. There are two type of handler that are available:
  • Logical Handlers - this type of handler operates on message context properties and message payloads. They are protocol-agnostic and cannot affect protocol specific parts of a message. Logical Handlers implement the javax.xml.ws.handler.LogicalHandler interface.
  • Protocol Handlers - this type of handler operates on message context properties and protocol specific messages. Protocol Handlers are specific to a particular protocol and may access and change protocol specific aspects of a message. They implement any interface derived from javax.xml.ws.handler.Handler. The exception to this is the interface for Logical Handlers (i.e. javax.xml.ws.handler.LogicalHandler).

The JAX-WS specification states that if you mix Logical and Protocol Handlers, the Logical Handlers will be executed before the protocol handlers although the relative order within the two groups will be preserved. The listing below shows the @HandlerChain Configuration file:

XML Code: @HandlerChain Configuration File
<handler-chains xmlns:jws="http://java.sun.com/xml/ns/javaee">
  <handler-chain>
    <handler>
      <handler-class>com.acme.validation.ValidationHandler</handler-class>
    </handler>
  </handler-chain>
</handler-chains>
With the LogicalHandler interface, you only have access to the payload via a javax.xml.ws.LogicalMessage. In terms of the SOAP binding, this implies access only to the SOAP Body element but not the headers. If you need access to the entire SOAP message, you will need to use a Protocol Handler that is specific to SOAP. The listing below shows the implementation of the ValidationHandler class that is referred to in the @HandlerChain configuration file above. As we are creating a Protocol Handler, this class implements javax.xml.ws.handler.soap.SOAPHandler<SOAPMessageC ontext>. This is the standard handler for the SOAP protocol binding, and the javax.xml.ws.handler.soap.SOAPContext is the standard extension of MessageContext used with the SOAP protocol binding. This handler serves to validate the SOAP message against the WSDL. The listing is shown below:

Java Code: ValidationHandler Class
public class ValidationHandler implements SOAPHandler<SOAPMessageContext> {
  
  public boolean handleMessage(SOAPMessageContext context) {

    if ( ((Boolean)context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY)).
        booleanValue() ) return true;
    try {
      SOAPMessage message = context.getMessage();
      SOAPBody body = message.getSOAPBody();
      SOAPElement requestElt =
        (SOAPElement) body.getFirstChild();
      String errMsg = validateAgainstWSDL(context, requestElt);
      if ( errMsg == null ) {
        return true;
      }
      SOAPFactory fac = SOAPFactory.newInstance();
      SOAPFault sf = fac.createFault(
          "SOAP payload is invalid with respect to WSDL.",
          new QName("http://schemas.xmlsoap.org/soap/envelope/", "Client"));
      Detail d = sf.addDetail();
      SOAPElement de = d.addChildElement(new QName(
          "http://www.acme.com/faults", "inputMessageValidationFault"));
      de.addAttribute(new QName("", "msg"), errMsg.replaceAll("\"",""));
      throw new SOAPFaultException(sf);
      
    } catch (Exception e) {
      e.printStackTrace();
      throw new WebServiceException(e);
    }
    
  }
This handler is only focused on the inbound SOAP message so we first check the direction of message flow using the MessageContext.MESSAGE_OUTBOUND_PROPERTY. Once we have confirmed it is an inbound message, we use the SAAJ API to extract the payload from the SOAP body. We are using document/literal wrapped style for the WSDL so just need to grab the first child of the SOAP body since there is only one child. Next we validate the payload and then pass it to the validateAgainstWSDL() method. After this normal processing is the same as well as the fault processing. When the validation is completed, any error will cause the handler to throw a SOAPFaultException. The exception will be converted by the JAX-WS runtime to a SOAP fault message using the mapping we described for fault processing.

Deploying Web Services in Java SE

From our discussion it is widely known the server-side behavior of JAX-WS within a Java EE 5 container. What you might not be aware of is that not only can you do container-based deployment of Web services but it is possible to deploy Web services from a Java SE application by using the javax.xml.ws.Endpoint class. There is no implementation of the Endpoint class is Java SE 5.0. You can only find an implementation in Java SE 6.

An Endpoint deployment can use the same SEI and service implementation bean that was used for a Java EE deployment. The listing below shows the SEI Implementation .

Java Code: SEI Implementation Published using javax.xml.ws.Endpoint
@WebService(name = "RequestOrder", 
    targetNamespace = "http://www.acme.com/req", 
    endpointInterface="com.acme.req.RequestOrderPort")
public class RequestOrder implements RequestOrderPort {

  public OrderType requestOrder(String custNum, String poNum, BUSOBJCCARD ccard,
      List<BUSOBJITEM> itemList) throws InputFault {
Note that the service implementation bean is annotated in this listing with the same @WebService annotation but without a wsdlLocation attribute. The Endpoint instance permits you to dynamically configure a pre-defined WSDL if you choose. The Endpoint class can generate the WSDL from either SEI or SIB annotations. Java SE 6 includes both the JAX-WS and JAXB run-time annotation processing system.

In order to create and publish a Web service, you need to create and deploy the Endpoint instance. This is a two-stage process. The listing below shows how this is done:

Java Code: Web Service Created and Published with javax.xml.ws.Endpoint
public static void main(String[] args) throws Exception {

Endpoint endpoint = Endpoint.create(new RequestOrder());
InputStream wsdlStream = 
      Client.class.getClassLoader().getResourceAsStream("RequestOrder.wsdl");
URL wsdlURL = 
      Client.class.getClassLoader().getResource("RequestOrder.wsdl");
if ( wsdlStream == null ) {
   throw new RuntimeException("Cannont find WSDL resouce file.");
}
ArrayList<Source> metadata = new ArrayList<Source>();
Source wsdlSource = new StreamSource(wsdlStream);
String wsdlId = wsdlURL.toExternalForm();
wsdlSource.setSystemId(wsdlId);
metadata.add(wsdlSource);
endpoint.setMetadata(metadata);
endpoint.publish("http://localhost:8680/oms");
The listing shows the first step is to create the Endpoint instance is:

CODE=JAVA;Endpoint Creation]Endpoint endpoint = Endpoint.create(new RequestOrder());[/CODE]

This is very simple and without any deployment descriptors or container. The next part is to set the metadata to supply your WSDL to the Endpoint. Without this, the endpoint will return the JAX-WS-generated WSDL. If you supply your own WSDL, you will need to use the Endpoint.setMetadata() method to provide your WSDL to the endpoint. The setMetadata() method takes an instance of List<Source>. You can include both XML schema and a WSDL in the list as meta-data. Whe you supply a WSDL as a Source instance, you will need to set the system ID if the WSDL contains references to imported or included schema that need to be resolved by an XML parser. The final step is to publish the endpoint with an endpoint URL as argument:

Java Code: Endpoint Publishing
endpoint.publish("http://localhost:8680/oms");
The client code used to invoke the Endpoint is shown below:

Java Code: Invocation of the Published Endpoint
URL wsdlDeployURL = new URL("http://localhost:8680/oms/requestOrder?wsdl");
   System.out.println("Endpoint Returns this WSDL");
   System.out.println("===========================================");
   printWSDL(wsdlDeployURL);
   QName serviceQName =
	new QName("http://www.acme.com/req", "RequestOrderService");
   QName portQName = 
	new QName("http://www.acme.com/req", "RequestOrderPort");
   Service service = Service.create(wsdlURL, serviceQName);
   RequestOrderPort port = 
	(RequestOrderPort) service.getPort(portQName, RequestOrderPort.class);
   BUSOBJCCARD ccard = createCreditCard();
   ArrayList<BUSOBJITEM> itemList = createItemList();
   OrderType order = port.requestOrder(
	"ENT0072123", null, ccard, itemList);
   System.out.println();
   System.out.println();
   System.out.println("Webservice Returns this Order");
   System.out.println("===========================================");
   printReturnedOrder(order);
   endpoint.stop();
}
This listing shows first how to get the WSDL and then print it out using the printWSDL() method. The printWSDL() method is used to show that the Endpoint publishes the WSDL correctly and then it can create a JAX-WS client to invoke the Endpoint. It is shown in the listing below:

Java Code: The printWSDL Method for the Published Endpoint
private static void printWSDL(URL wsdlURL) throws Exception {

    HttpURLConnection con = (HttpURLConnection) wsdlURL.openConnection();
    con.setRequestMethod("GET");
    con.connect();
    InputStream wsdlInput = con.getInputStream();
    int b = wsdlInput.read();
    while ( b > -1 ) {
      System.out.print((char) b);
      b = wsdlInput.read();
    }
    wsdlInput.close();
    con.disconnect();
  }
From listing shows that the Service is built from the WSDL URL and is then used to create a dynamic proxy from the RequestOrderPort SEI. It is the same process used for invoking any Web service. The WSDL that was supplied to the Endpoint instance via the setMetaData method is shown in the next listing:

XML Code: WSDL Supplied to Endpoint Instance
<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
  xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  xmlns:oms="http://www.acme.com/oms" xmlns:req="http://www.acme.com/req"
  xmlns:faults="http://www.acme.com/faults"
  targetNamespace="http://www.acme.com/req">
  <wsdl:types>
    <xs:schema targetNamespace="http://www.acme.com/oms">
      <xs:include schemaLocation="http://acmesoa.com/oms/orders.xsd"/>
    </xs:schema>
    <xs:schema targetNamespace="http://www.acme.com/faults">
      <xs:include schemaLocation="http://acmesoa.com/faults/faults.xsd"
      />
    </xs:schema>
    <xs:schema targetNamespace="http://www.acme.com/req"
      elementFormDefault="qualified">
      <xs:element name="requestOrder">
        <xs:complexType>
          <xs:sequence>
            <xs:element name="CUST_NO">
              <xs:simpleType>
                <xs:restriction base="xs:string">
                  <xs:maxLength value="10"/>
                </xs:restriction>
              </xs:simpleType>
            </xs:element>
            <xs:element minOccurs="0" name="PURCH_ORD_NO">
              <xs:simpleType>
                <xs:restriction base="xs:string">
                  <xs:maxLength value="35"/>
                </xs:restriction>
              </xs:simpleType>
            </xs:element>
            <xs:element type="oms:BUSOBJ_CCARD" minOccurs="0" name="ccard"/>
            <xs:element type="oms:BUSOBJ_ITEM" name="item" maxOccurs="unbounded"
            />
          </xs:sequence>
        </xs:complexType>
      </xs:element>
      <xs:element name="requestOrderResponse">
        <xs:complexType>
          <xs:sequence>
            <xs:element ref="oms:Order"/>
          </xs:sequence>
        </xs:complexType>
      </xs:element>
    </xs:schema>
  </wsdl:types>
  <wsdl:message name="request">
    <wsdl:part element="req:requestOrder" name="parameters"/>
  </wsdl:message>
  <wsdl:message name="response">
    <wsdl:part element="req:requestOrderResponse" name="parameters"/>
  </wsdl:message>
  <wsdl:message name="inputFault">
    <wsdl:part element="faults:inputMessageValidationFault" name="parameters"/>
  </wsdl:message>
  <wsdl:portType name="RequestOrderPort">
    <wsdl:operation name="requestOrder">
      <wsdl:input message="req:request"/>
      <wsdl:output message="req:response"/>
      <wsdl:fault message="req:inputFault" name="requestOrderInputFault"/>
    </wsdl:operation>
  </wsdl:portType>
  <wsdl:binding type="req:RequestOrderPort" name="RequestOrderSOAPBinding">
    <soap:binding style="document"
      transport="http://schemas.xmlsoap.org/soap/http"/>
    <wsdl:operation name="requestOrder">
      <wsdl:input>
        <soap:body use="literal"/>
      </wsdl:input>
      <wsdl:output>
        <soap:body use="literal"/>
      </wsdl:output>
      <wsdl:fault name="requestOrderInputFault">
        <soap:fault name="requestOrderInputFault"/>
      </wsdl:fault>
    </wsdl:operation>
  </wsdl:binding>
  <wsdl:service name="RequestOrderService">
    <wsdl:port binding="req:RequestOrderSOAPBinding" name="RequestOrderPort">
      <soap:address location="http://localhost:8680/oms/requestOrder"/>
    </wsdl:port>
  </wsdl:service>
</wsdl:definitions>
If you query the URL Order?wsdl, JAX-WS will return a WSDL in it’s response. There is a difference between the WSDL supplied as metadata to the Endpoint and this generated WSDL. This is that the schema locations have changed for all of the schema import definitions. The returned WSDL is shown in the listing below:

XML Code: JAX-WS Generated WSDL
<definitions xmlns:tns="http://www.acme.com/req"
  xmlns:xsd="http://www.w3.org/2001/XMLSchema"
  xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
  xmlns="http://schemas.xmlsoap.org/wsdl/"
  targetNamespace="http://www.acme.com/req" name="RequestOrderService">
  <types>
    <xsd:schema>
      <xsd:import namespace="http://www.acme.com/req"
        schemaLocation="http://localhost:8680/oms/requestOrder?xsd=1"/>
    </xsd:schema>
    <xsd:schema>
      <xsd:import namespace="http://www.acme.com/oms"
        schemaLocation="http://localhost:8680/oms/requestOrder?xsd=2"/>
    </xsd:schema>
    <xsd:schema>
      <xsd:import namespace="http://www.acme.com/faults"
        schemaLocation="http://localhost:8680/oms/requestOrder?xsd=3"/>
    </xsd:schema>
  </types>
  <message name="requestOrder">
    <part element="tns:requestOrder" name="parameters"/>
  </message>
  <message name="requestOrderResponse">
    <part element="tns:requestOrderResponse" name="parameters"/>
  </message>
  <message name="inputMessageValidationFault">
    <part xmlns:ns1="http://www.acme.com/faults"
      element="ns1:inputMessageValidationFault"
      name="inputMessageValidationFault"/>
  </message>
  <portType name="RequestOrderPort">
    <operation name="requestOrder">
      <input message="tns:requestOrder"/>
      <output message="tns:requestOrderResponse"/>
      <fault message="tns:inputMessageValidationFault"
        name="inputMessageValidationFault"/>
    </operation>
  </portType>
  <binding type="tns:RequestOrderPort" name="RequestOrderPortBinding">
    <soap:binding style="document"
      transport="http://schemas.xmlsoap.org/soap/http"/>
    <operation name="requestOrder">
      <soap:operation soapAction=""/>
      <input>
        <soap:body use="literal"/>
      </input>
      <output>
        <soap:body use="literal"/>
      </output>
      <fault name="inputMessageValidationFault">
        <soap:fault use="literal" name="inputMessageValidationFault"/>
      </fault>
    </operation>
  </binding>
  <service name="RequestOrderService">
    <port binding="tns:RequestOrderPortBinding" name="RequestOrderPort">
      <soap:address location="http://localhost:8680/oms/requestOrder"/>
    </port>
  </service>
</definitions>
Note that there are no references to the corporate schema repositories (i.e http://acmesoa/oms/orders.xsd). These have been replaced by local references (i.e. http://localhost:8680/oms/requestOrder?xsd=1). So you can see that providing a WSDL contract as meta-data to the Endpoint is no guarantee that it will be reproduced exactly.

Summary

OK. We have covered JAX-WS API for both the client and server side as well as for run-time behavior. Next we are on to REST, JSON, SOAP and the XML Processing APIs.