Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Override CXF error handling

Tags:

java

soap

cxf

I am working on some web-services based application and I have a question about Apache CXF unmarshalling. In our project we use CXF 2.4.1 version.

When some SOAP request is incorrect (e.g. some field is text instead of numeric) CXF throws standard SOAPFaultException and SOAP response is built up with standard fields like:

<soap:Fault>
    <faultcode>soap:Client</faultcode>
    <faultstring>Unmarshalling Error: some field missing</faultstring>
</soap:Fault>

Project requirements says that in case of any fault system need to respond in other format, like:

<soap:body>
    <ResponseState>
        <ErrorCode>2732</ErrorCode>
        <ErrorMessage>Unmarshalling Error: some field missing</ErrorMessage>
        <ErrorDetails> some details </ErrorDetails>
        <some other fields>
        ...
    </ResponseState>
</soap:body>

So the question is: how can I override somehow this error handling and respond in my format, not default?

Thanks in advance.

P.S. I tried to look into some ValidationEventHandler principals, but it works in some other way in CXF 2.0 and higher.

like image 366
Viktor Molokanov Avatar asked Apr 17 '12 15:04

Viktor Molokanov


2 Answers

OK, So after lot of research I've found some ways of CXF error handling.

*. ValidationEventHandler gives you possibility to throw your own exception instead of standard one. BUT you can't change responding behavior and you can't change SOAP response format.

*. Another way to alter error handling is to create your own interceptor. CXF workflow is built on chain of interceptors. There's 4 type of interceptors: inInterceptor, outInterceptor, inFaultInterceptor and outFaultInterceptor.

Using some smart hacks you can change workflow through creating your own interceptor (with adding it to chain), and remove standard interceptor from chain (if you know it's class name). So you can actually do anything you need.

BUT as far as all these interceptors marshall response manually (xmlWriter.writeStartElement() etc) it could be a great challenge to write your own interceptors for each flow phase. It could be real huge bunch of work.

Unfortunately, I haven't found good reference about CXF interceptors.

Another thing - if you need to return regular response instead of SOAPFaultException you may need additional information like: actual service that return this response, service parameters passed in request etc. I haven't found this info in accessible parameters in interceptors. And, surely, by doing so you cheat client code that will return OK instead of real exception.

*. Designing your wsdl's with all params as text may be very not very good solution:

a. Consumer of your services may be really confused if no data types and validation rules in wsdl.

b. You'll need to 'reinvent the wheel' for validation. I mean that you'll need to code your own validator that could be very difficult with some complicated rules. At the same time XSD has all of this validations implemented and good tested.

And finally about my situation: we discussed it with requirement manager and decided to allow CXF throw it's own standard exceptions if XML schema requirements violated in request. It's good solution because now we are using all the power of XSD validation and don't waste our time on complicated and useless work.

Great thanks to @ericacm for answer.

like image 129
Viktor Molokanov Avatar answered Oct 04 '22 06:10

Viktor Molokanov


You can certainly generate a better error response than the default using ValidationEventHandler and throwing a Fault that conforms to the JAX-WS Fault spec. But it will only allow you so much customization - there will be some elements that you have no control over. For example, here is the ValidationEventHandler response from one of my apps:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
   <soap:Body>
      <soap:Fault>
         <faultcode>soap:Client</faultcode>
         <faultstring>Errors in request</faultstring>
         <detail>
            <ns2:ValidationFault xmlns:ns2="http://notification.ws.foo.com/">
               <errors>
                  <error>
                     <inputElement>topicId</inputElement>
                     <errorMessage>java.lang.NumberFormatException: For input string: "" [line:6]</errorMessage>
                  </error>
               </errors>
            </ns2:ValidationFault>
         </detail>
      </soap:Fault>
   </soap:Body>
</soap:Envelope>

You can't do anything about the <soap:Fault>, <faultcode> and <faultstring> elements. But everything from <ValidationFault> to </ValidationFault> is custom.

If you need to have more detailed control over the response then you should change the field type from numeric to string and then do the validation in your code instead of letting the unmarshaller catch the error.

Yes, I agree, forcing it to be a string would suck but if the response has to be exactly what you spec'd above it will not be possible without diving deeper into CXF than the JAX-WS layer (for example using an interceptor).

like image 35
sourcedelica Avatar answered Oct 04 '22 08:10

sourcedelica