I am new to Camel and CXF. I am trying to post process the fault messages that are thrown from my Web Service. But CXF throws them as Fault exception only and hence the camel routing is aborted and the error handler is invoked.
How can I tweak Camel or CXF to get the fault message just as received by the CXF itself?
Is there any configuration by which I can attain this?
Or Do I need to provide an Interceptor to achieve this?
Or Do I need to handle in Error handler?
You can try this:
from("endpoint")
.doTry()
.to("endpoint")
.doCatch()
.process(new Processor(
#Override
public void process(Exchange exchange) throws Exception {
//Get the exception
SoapFault fault = exchange.getProperty(Exchange.EXCEPTION_CAUGHT, SoapFault.class);
//Then you can change the body
}
))
.endDoTry()
.end();
This is the sample route in spring DSL. You can try this. This will perfectly work if there is SOAP Fault from the provider.
<route id="test-route-id">
<from uri="direct:from-route"/>
<doTry>
<log message="Request Payload : ${body}" loggingLevel="INFO" logName="test-route-id"/>
<to uri="direct:cxf-endpoint"/>
<log message="Response Payload : ${body}" loggingLevel="INFO" logName="test-route-id"/>
<doCatch>
<exception>org.apache.cxf.binding.soap.SoapFault</exception>
<to uri="direct:fault-handling-route"/>
</doCatch>
</doTry>
</route>
If you only want to react on faults you can do:
onException(Fault.class).handled(true).process(new MyFaltProcessor()).stop();
Related
I'm calling out to a WS using cxf:cxfEndpoint and its working fine. I want to catch any exceptions using onException or something similar. For some reason its not working. I have set the dataFormat to PAYLOAD, handleFault attribute on the route and/or the camel context to true. The web service is not running so I'm expecting the exception to be caught but its not working. Same issue with unmarshalling of the XML.
When I throw an exception using it gets caught successfully using java.lang.Exception and written to my dummy exception queue... but when the webservice is down or I pass in some invalid XML and the marshalling fails then an exception gets thrown but not caught.
Is there anything else to be aware of?
EDIT: Included the code for unmarshaling. Switched to using Try/Catch and when i pass in invalid XML the exception does get caught during the junit testing but does not get caught at runtime
<route>
<from uri="jmsamq:In"/>
<doTry>
<unmarshal>
<jaxb contextPath="outbound.message"/>
</unmarshal>
<doCatch>
<exception>java.lang.Exception</exception>
<handled>
<constant>true</constant>
</handled>
<transform>
<simple>Mapping Failed</simple>
</transform>
<to uri="jmsamq:errorqueue1"/>
</doCatch>
</doTry>
<log message="${body}"/>
<multicast stopOnException="true">
<to uri="direct:webservice"/>
<to uri="direct:myqueue"/>
</multicast>
</route>
the incorrect camel-context XML file was being used at runtime.. ignore question!
I read the corresponding documentation but I couldn't figure out why my Exception is not catched.
This is my route configuration:
<route id="foo">
<from uri="vm://.../>
<doTry>
<to uri="jetty:http://127.0.0.1:123/foo?restletMethod=PUT"/>
<to uri="ejb:java:global/..?method=method1(${body}, ${headers})"/>
<to uri="ejb:java:global/..?method=method2(${body}, ${headers})"/>
<doCatch>
<exception>java.lang.Exception</exception>
<transform>
<simple> ${exception.message} </simple>
</transform>
<to uri="smtp://... />
</doCatch>
</doTry>
</route>
Now when the JettyClient is not reachable a org.apache.camel.CamelExchangeException is thrown,
the route terminates and I receive an email. This is the desired behaviour.
But when method1 throws an exception it is not catched, hence the route continues and
I don't receive an email.
How can I make camel recognize and handle the exception in the second case too?
Solution: Make sure the exception isn't thrown inside a try-catch block -.-
This is stated in the documentation:
http://camel.apache.org/try-catch-finally.html
Camel error handling is disabled
When using doTry .. doCatch .. doFinally then the regular Camel Error
Handler does not apply. That means any onException or the likes does
not trigger. The reason is that doTry .. doCatch .. doFinally is in
fact its own error handler and that it aims to mimic and work like how
try/catch/finally works in Java.
You are probably better off to write it like this:
.doCatch(Exception.class)
// and catch all other exceptions
// they are handled by default (ie handled = true)
.to("direct:error")
In direct:error you can specify what to do in case something goes wrong.
I am new to Apache Camel. I am able to send JMS message from one queue to another queue. I would like to know how to handle the exception. I learned onException, But it is not working for me.
I changed my jms queue to jms1. However, when I execute the code i get an exception.
My expectation is whenever I get exception my bean class should be invoked, but it is not.
Exception:
org.apache.camel.RuntimeCamelException:
org.apache.camel.FailedToCreateRouteException: Failed to create route
route1 at: >>> To[jms1:queue:FinalQSource] <<< in route:
Route[[From[jms:queue:testQSource]] -> [OnException[[class j...
because of Failed to resolve endpoint: jms1://queue:FinalQSource due
to: No component found with scheme: jms1
Code
<camelContext id="jmsContext" xmlns="http://camel.apache.org/schema/spring">
<onException>
<exception>org.apache.camel.RuntimeCamelException</exception>
<exception>org.apache.camel.ResolveEndpointFailedException</exception>
<!-- <handled><constant>true</constant></handled> -->
<bean ref="exceptionListener" method="orderFailed" />
</onException>
<route>
<from uri="jms:queue:testQSource" />
<to uri="jms1:queue:FinalQSource" /><!--
</route>
</camelContext>
This will not work as the exception is being thrown by camel when it tries to parse your route. The onException block will only catch exceptions that are thrown during execution of your route.
To test exception handling use the proper camel testing guide - http://camel.apache.org/testing.html
I would recommend mocking one of your endpoints to return an exception, example here - https://github.com/christian-posta/camel-sandbox/blob/master/one-off/src/test/java/posta/TestMockExceptions.java
MockEndpoint mockException = MockEndpoint.resolve(context, "mock:exception");
mockException.whenAnyExchangeReceived(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
System.out.println("i got here...");
throw new RuntimeException("fail!");
}
});
I have a Camel route exposed as a CXF web service. This is a bottom up web service and has an operation like so:
List<Book> getBooks();
The CXF endpoint is defined as:
<cxf:cxfEndpoint id="bookService"
address="http://localhost:9045/bookservice"
serviceClass="org.test.cxfws.service.BookDBService">
</cxf:cxfEndpoint>
The operation queries a list of books and returns it to the caller. The Camel route looks like this:
<camel:camelContext xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="cxf:bean:bookService"/>
<choice>
<when>
<simple>${header.operationName} == 'getBooks'</simple>
<to uri="bean:wsImplBean?method=getBooks"/>
</when>
<to uri="log:outboundSoapResponse"/>
<choice>
</route>
</camel:camelContext>
After running the route, I am getting the following exception:
org.apache.cxf.interceptor.Fault: org.test.cxfws.service.Book cannot be cast to java.util.List
at org.apache.cxf.jaxws.interceptors.WrapperClassOutInterceptor.handleMessage(WrapperClassOutInterceptor.java:117)
at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:272)
at org.apache.cxf.interceptor.OutgoingChainInterceptor.handleMessage(OutgoingChainInterceptor.java:77)
at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:272)
...
Caused by: java.lang.ClassCastException: org.test.cxfws.service.Book cannot be cast to java.util.List
at org.test.cxfws.service.GetBooksResponse_WrapperTypeHelper1.createWrapperObject(Unknown Source)
at org.apache.cxf.jaxws.interceptors.WrapperClassOutInterceptor.handleMessage(WrapperClassOutInterceptor.java:101)
I can see that the getBooks method from the bean wsImpBean is executed and the result being returned at the end of the choice block inside the route:
[ qtp1653072092-14] outboundSoapResponse INFO Exchange[ExchangePattern: InOut, BodyType: java.util.ArrayList, Body: [org.test.cxfws.service.Book#63f1858b, org.test.cxfws.service.Book#5769bf0, org.test.cxfws.service.Book#2df7ac5d, org.test.cxfws.service.Book#5f55253e, org.test.cxfws.service.Book#4f003a57]]
Can someone help me to understand why the ClassCastException.
Thanks.
As camel-cxf use list to hold the response for handling the InOut parameters. When you set the response result into the message body, you need to wrap the result into a List just like this
List<Book> books ...
List<Object> resultList = new ArrayList<Object>();
resultList.add(books);
exchange.getOut().setBody(resultList);
I'm trying to retrieve the stacktrace from the onException handler in Apache Camel:
<onException>
<exception>java.lang.Exception</exception>
<handled>
<constant>true</constant>
</handled>
<setHeader headerName="exception">
<simple>${exception}</simple>
</setHeader>
</onException>
However, the above only shows the exception rather than the entire stacktrace.
I understand that Camel stores the caught exception as a property on the Exchange with the key: Exchange.EXCEPTION_CAUGHT, but how can this be retrieved from the camel context routes file ?
Use exception.stacktrace to get the stacktrace. See the variables listed in the table at this page: http://camel.apache.org/simple
<simple>${exception.stacktrace}</simple>
There is also a ${exception.message} to refer to the exception message itself.