8 Replies Latest reply on Nov 5, 2009 3:24 AM by Willem Jiang

    CXF Fault for IOException in Camel

    Eoin Shanaghy Newbie

      Hello,

       

      I have a camel route with from & to CXF endpoints.  If the to: endpoint is inaccessible (IOException), I'd like to get a SOAP fault in the invoker which has a specific fault code.  The default behaviour gives me this (CXF 2.2.2.2-fuse in Fuse ESB 4.1, camel 1.6.1.2-fuse):

       

             

       

      I'm trying to set up a CXF interceptor which can check if the root cause was an IOException and if so, set the faultcode to something specific which can be understood as "web service down".  I set up an outFaultInterceptor on the from: endpoint which gets the SoapFault instance and updates the FaultCode, but the result at the invoker is the same!

       

      Does anyone know how this can be done with CXF interceptors or is it better to do it with a Camel processor somehow?

        • 1. Re: CXF Fault for IOException in Camel
          Pedro Neveu Newbie

          Take a look at error handling in camel: http://camel.apache.org/error-handling-in-camel.html

           

          Let me know if you have any questions.

           

          Pedro

          • 2. Re: CXF Fault for IOException in Camel
            Pat Fox Newbie

            Hi shanaghe,

             

            The following thread might be of use with regards understanding the camel outbound route - http://fusesource.com/forums/thread.jspa?threadID=637.

             

             

            Perhaps one option is to try is having a processor at the end of the route that manipulates the exception content if the exchange has an exception set.

             

             

            Best regards

             

            Pat

            • 3. Re: CXF Fault for IOException in Camel
              Eoin Shanaghy Newbie

              Thanks for the replies.

               

              Where should the processor be added to be able to read/manipulate the error?  I thought the only way to do this would be via an ErrorHandler (as alluded to in the Pedro's reply).

               

              If I try this:

                      <camel:route>

                          <camel:from uri="cxf:bean:sourceWs" />

                          <camel:to uri="cxf:bean:targetWs" />

                          <camel:process ref="bean:endProcessor"/>

                      </camel:route>

              the processor is never invoked in the error scenario.

               

              I looked at implementing an ErrorHandler but I couldn't clearly see how to implement a custom ErrorHandlerBuilder which just executes some processing - the API seemed a bit more complicated than required. 

               

               

                  public Processor createErrorHandler(RouteContext routeContext, Processor processor)

                  {

                      // If I create a processor here and return it, do I need to do anything with the routeContext and processor in the arguments?

                  }

              • 4. Re: CXF Fault for IOException in Camel
                Pat Fox Newbie

                Hi

                 

                Scratch my last reply - it was an oversight on my part. I don?t think that will work when an exception is thrown.

                 

                Best regards

                Pat

                • 5. Re: CXF Fault for IOException in Camel
                  Pedro Neveu Newbie

                  Let me know if you got this going.  My guess is you'd have to specify handled(false) so that your app will take over from the default dead letter channel.  See http://camel.apache.org/dead-letter-channel.html.

                   

                  Pedro

                  • 6. Re: CXF Fault for IOException in Camel
                    Willem Jiang Master

                    I think there are lots of way to implement your requirement on CXF side.

                    1. You can add your customer CXF MessageSenderInterceptor to throw the exception that you want.

                    2. You can also add interceptor which implements the handleFault method (you can replace the fault message as you want ), and add this interceptor before the MessageSenderInterceptor. Your interceptor's handleFault() method will be called, after the MessageSenderInterceptor throw the Fault.

                     

                    Since CXF client just use  ClientOutFaultObserver which only call the ClientCallback method when the exception is thrown, that can explain why your outFaultInterceptor doesn't take effect.

                     

                    If you want to do it on Camel side, you need go through the ErrorHandler of camel

                    • 7. Re: CXF Fault for IOException in Camel
                      Eoin Shanaghy Newbie

                      Thanks, these replies are giving me exactly the information I'm looking for.

                       

                      I have a solution working but I don't feel it's as neat as njiang's suggestions.

                       

                      I defined a CXF interceptor which implements handleMessage() and added it as an interceptor in my camel-context:

                       

                               

                       

                      Then in handleMessasge() I do:

                       

                      if (rootCause instanceof IOException) {

                          fault.setFaultCode(mySpecificFaultCode);

                      }

                       

                      Njiang, what's the best way to add my interceptor before the MessageSenderInterceptor.?  I tried and couldn't crack it.  Can I do this in the CXF endpoint definition or does it have to be done in Java code somewhere?

                      • 8. Re: CXF Fault for IOException in Camel
                        Willem Jiang Master

                        Here is the code snippet of the interceptor

                         public class MySenderIntercepor extends AbstractPhaseInterceptor<Message> {
                          public MySenderInterceptor() {
                                super(Phase.PREPARE_SEND);
                                addBefore(MessageSenderInterceptor.class.getName());
                            }
                        
                            public void handleMessage(Message message) {
                                // do nothing here
                            }
                        
                            public void handleFault(Message message) {
                               // add you code here
                            }
                        }
                        

                         

                        You can add this interceptor through the spring configuration or java code. Please check this out for more information.

                         

                        CXFEndpoint definition supports configure the interceptor like this

                        <cxf:cxfEndpoint id="routerRelayEndpointWithInsertion" 
                                           address="http://localhost:5000/HeaderService/"
                                           serviceClass="org.apache.camel.component.cxf.soap.headers.HeaderTester"
                                           endpointName="tns:SoapPortRelayWithInsertion"
                                           serviceName="tns:HeaderService"
                                           wsdlURL="soap_header.wsdl"
                                           xmlns:tns="http://apache.org/camel/component/cxf/soap/headers">
                                <cxf:inInterceptors>
                                      <ref bean="logInbound"></ref>
                                  </cxf:inInterceptors>     
                                  <cxf:outInterceptors>
                                      <ref bean="logOutbound"></ref>
                                  </cxf:outInterceptors>     
                          </cxf:cxfEndpoint>