Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How best to validate JAX-WS inputs?

Tags:

java

jaxb

jax-ws

I'm currently writing a new set of web services using JAX-WS but I'm having difficulties deciding on the best way to validate the inputs. I can do some validation in my implementation classes but some input errors fail silently. For example character data in a numeric element will result in a null Integer in the JAXB object.

These are the designs I've come across.

  1. @SchemaValidation
    I could add this annotation to the endpoint class and JAX-WS will take care of the validation. This worked locally in tomcat but there are concerns that it won't work on some servers. My main gripe is that I have to surrender control of how the errors are output in the response.

  2. All inputs as strings
    I hate this approach but I've seen other web services where all inputs are defined as strings. This would catch the case of character data in a numeric element as I could check it where I call our API although you'd still miss any incorrectly named xml elements.

I really want the errors to come back in the same manner as the API errors rather than as a soap fault. Any ideas? I've seen a few sites talking about intercepting the request with a kind of filter. Not sure how this would work with different responses for different operations though.

E.G.

<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
   <S:Body>
      <myOperationResponse>
         <return>
            <success>false</success>
            <errors>
               <error>
                  <code>UNIQUECODE</code>
                  <message>Message text</message>
               </error>
            </errors>
         </return>
      </myOperationResponse>
   </S:Body>
</S:Envelope>

Maybe I'm asking too much but thought I'd see if I'd missed anything. TIA.

like image 749
Ben Thurley Avatar asked Jul 04 '13 11:07

Ben Thurley


3 Answers

Found this article which explains one possible way.
http://one-size-doesnt-fit-all.blogspot.co.uk/2009/04/jax-ws-schemavalidation-custom-handler.html

I have it returning the parse error message in my standard response layout. i just need to test it will work on the customers machine. (Some people say they've had issues with @SchemaValidation)

like image 115
Ben Thurley Avatar answered Nov 03 '22 15:11

Ben Thurley


If you insist on control (something like you usually need to relinquish when doing Jax-WS...), you could implement a Provider and Validator validating against an XSD Schema.

The XSD Schema will take care of validating the input (type and potentially enumerations, pattern matching, etc...)

To implement the javax.xml.ws.Provider as your SOAP Endpoint, create a class looking like

@javax.xml.ws.ServiceMode(value = javax.xml.ws.Service.Mode.MESSAGE)
@javax.xml.ws.WebServiceProvider(
    wsdlLocation = "WEB-INF/wsdl/MyService.wsdl", 
    targetNamespace = "urn-com-acme-webservice", 
    serviceName = "ProcessPurchaseOrderService", 
    portName = "ProcessPurchaseOrderPort"
)
public class ProcessPurchaseOrder implements Provider<SOAPMessage> {


            @override
    public SOAPMessage invoke(final SOAPMessage request) {

                //see below     
    }
}

A SOAPMessage will be passed to the invoke method which expects in return a valid response or SOAPFault wrapped in a SOAPMessage;

To validate agains an XSD, use a javax.xml.validator:

    URL url = this.getClass().getResource(xsdSchemaLocation);

    String language = XMLConstants.W3C_XML_SCHEMA_NS_URI;
    SchemaFactory factory = SchemaFactory.newInstance(language);
    Schema schema = factory.newSchema(url);

    validator = schema.newValidator();

Extract the SOAPBody xml and validate it against the Validator using the validate() method.

Catch Exceptions around the validation and build your own SOAP Fault:

 //Build the SOAP Fault Response
 MessageFactory factory = MessageFactory.newInstance(SOAPConstants.SOAP_1_1_PROTOCOL);
 SOAPMessage response = factory.createMessage();

 SOAPFault fault = response.getSOAPBody().addFault();
 fault.setFaultString(myCustomErrorString);

 fault.addDetail().addChildElement("exception").addTextNode(myCustomErrorId);

then return the SOAPMessage containing the fault.

(no, I do not like SOAP Web Services)

like image 37
Bruno Grieder Avatar answered Nov 03 '22 17:11

Bruno Grieder


In the scenario you are trying to achieve, there wont be any SOAP fault. The validation logic (which will be part of the code which handles the request eventually ), has to make sure that all the validation scenarios are handled.

We had faced this scenarios where in the third party integrating our web services could not decipher much from the SOAP faults and we went by creating an error-response just like the way you have conceived. I would suggest the following approach.

  • Write your own validation logic
  • Create an appropriate object structure. You already have one in XML format. Just need to objectify it.
  • Call this validation logic and pass the input objects to it. The validation logic will validate all the inputs and populate appropriate response object (myOperationResponse).
  • On return of the validation method, check for the status or error objects. If there are errors then return the response object OR proceed with processing the request further and then return the success response.
like image 2
Santosh Avatar answered Nov 03 '22 17:11

Santosh