How to properly handle Exceptions in Apache Camel using OnException - apache-camel

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!");
}
});

Related

Get Failed Node Endpoint URI in Camel route

I am developing a sample route
FROM: SOURCE ENDPOINT URI
TO: TRANS ENDPOINT URI // Error or Exception occurred at this TRANS endpoint
TO: TARGET ENDPOINT URI
Now I want to catch the Error Occured endpoint and pass it to my processor.
Could anyone please help me with this?
<route>
<from uri="file:C:/MINTS/Source/"/>
<to uri="file:C:/MINTS/TRANS/"/> <!-- EXCPECTION OCCURED -->
<to uri="file:C:/MINTS/TARGET/"/>
<onException>
<exception>java.lang.Exception</exception>
<handled>
<constant>true</constant>
</handled>
<!-- NEED TO CATCH FAILURE ENDPOINT URI AND PASS TO MY PROCESSOR BELOW-->
<process ref="MyExceptionProcessor" />
</onException>
</route>
You can use exchange properties:
CamelFailureEndpoint
example xml-dsl: <exchangeProperty>CamelFailureEndpoint</exchangeProperty>
example java: exchange.getProperty(Exchange.FAILURE_ENDPOINT, String.class);
CamelToEndpoint
example xml-dsl: <exchangeProperty>CamelToEndpoint</exchangeProperty>
example java: exchange.getProperty(Exchange.TO_ENDPOINT, String.class)
The first one should print uri for the consumer endpoint (from) that failed and the second one should show the previously called producer (to) endpoint.
One handy way to debug contexts of an failed exchange is to use:
<to uri="log:loggerName?showAll=true" />
This will log all exchange properties, headers, body and exception which can help to understand what information is available within exchange. Be careful where you use it as it might also log secrets and passwords if they're within the exchange so better use it only locally during development.
For more information you'd probably need to access CamelMessageHistory exchange property through processor, bean or something.

Camel JMS component, how to get a callback on subscriptions?

I am developing a service where I need to subscribe to JMS Queues dynamically with Camel JMS 2.17.0.
So I create a listening route at runtime using a bean:
// Bean: createCustomListenerNow
String endpoint = "jms:queue:" + queueName +
"&testConnectionOnStartup=true&exceptionListener=#listenerBuilder";
// camelContext.addRoutes uses this RouteBuilder
#Override
public void configure() throws Exception {
from(endpoint)
.id(id)
.to("seda:processReply");
}
My actual broker is Websphere MQ and I may get an exception if my account doesn't have the right permissions. Unfortunately this happens after my route has been built.
My route goes like this:
<route>
<from uri="direct:mock" />
<to uri="bean:createCustomListenerNow" /> <!-- I want to block here until subscription is OK -->
<to uri="bean:doSomethingThatRequiresTheListenerToBeProperlyRunning" />
</route>
Is there a way to "block" until the JMS component creates a new connections and successfully subscribes? I didn't manage to find a callback or a simple way to get this information.
What I do now is registering a javax.jms.ExceptionListener and waiting for a JMSException. If the exception is not thrown before a timeout I suppose the subscription did succeed.
I don't think this approach is rock-solid, any suggestion is appreciated.
I cannot block until I receive a message on the listener because it can arrive hours later and I need to finish processing the current Exchange with a reply like "Setup of listener is ok" or "Setup of listener failed".

CXF SOAP Fault handling

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();

I'm having issues with camel http4 endpoint

Spring context:
<bean id="customRouteA" class="com.xxx.CustomRouteABean" />
<camelContext id="solr" xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="activemq:topic:agent" />
<to uri="bean:customRouteA"/>
</route>
</camelContext>
Java code:
public class CustomRouteABean {
#EndpointInject(uri = "http4://localhost/camel-route-test.php")
ProducerTemplate producer;
public void processMessage(#Body String message) {
...
}
}
Keeps getting error:
2085 [main] ERROR org.springframework.web.context.ContextLoader - Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'customRouteA' defined in ServletContext resource [/WEB-INF/application-context.xml]: Initialization of bean failed; nested exception is org.apache.camel.spring.GenericBeansException: Error post processing bean: customRouteA; nested exception is org.apache.camel.ResolveEndpointFailedException: Failed to resolve endpoint: http4://localhost/camel-route-test.php?bridgeEndpoint=true due to: null
I have another bean has the same setup works just fine, what am I missing here?
And you have camel-http4 and its dependent JARs on the classpath?

Stacktrace from Camel Context onException

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.

Resources