Handle apache camel consumer errors - java

I want to stop route in case if user credentials changed, for this I want to handle javax.mail.AuthenticationFailedException.class but this does not work:
from(_getImapSentURL(emailConfiguration)).routeId(routeIdSent)
.onException(javax.mail.AuthenticationFailedException.class)
.process(new EmailErrorHandler()).end()
.process(new EmailContentSentProcessor(user, filterSent));
and error processor
public class EmailErrorHandler implements Processor {
private static final long serialVersionUID = 1L;
Logger logger = Logger.getLogger(getClass());
#Override
public void process(Exchange exchange) throws Exception {
logger.info("handled");
}
}
In console I'm getting this exception but it's not handled.
Where is the mistake?
Solution:
Add param to endpoint URL consumer.bridgeErrorHandler=true
In route builder add exception handler
onException(Exception.class)
.log("Exception occurred due: ${exception.message}")
.bean(new EmailConsumerExceptionHandler(), "handleException").handled(true)
.end();
Implement ExceptionHandler
Also if you set handle(..) to true you can access to exception only in this way
Exception cause = originalExchange.getProperty(
Exchange.EXCEPTION_CAUGHT, Exception.class);
in reffer to Apache camel documentation

Its like a chicken and egg situation. The Camel error handler reacts when you have a valid message to route and then during routing some error happens.
But as the mail consumer cannot login then there is no valid message to route.
But you can turn on an option to bridge the consumer with Camels error handler. You can find more details from here: http://camel.apache.org/why-does-my-file-consumer-not-pick-up-the-file-and-how-do-i-let-the-file-consumer-use-the-camel-error-handler.html and the links it refers to

Related

Apache camel onException adding error details to the original message

I have added this exception handling to the camel route.
.onException(BeanCreationException.class, ValidationException.class)
.handled(true)
.process(new OnExceptionProcessor())
.to("errorQueue0").id("errorQueue")
.end()
public class OnExceptionProcessor implements Processor {
#Override
public void process(Exchange exchange) throws Exception {
Exception cause = exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Exception.class);
exchange.getIn().setHeader("FailedBecause", cause.getMessage());
}
}
When I read this message back from the error queue, I cannot find this header.
any idea on how to add error details along with the original message to the error queue
This could be a context problem because you are in a processor that is called by the error handler.
As an alternative, you could return the String value to set in the header from your processor method. By the way, this also improves the testability of your Processor.
Then you can use this return value to set the header in the error handler route directly.
.setHeader("FailedBecause", method(new OnExceptionProcessor()))

Camel: how to route data from process method to another pipeline?

I have code like this:
.from("file://" + FTP_FILES + "?idempotent=true")
.process(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
list = parseDataFromExchange(ecxhange);
}
I want to send this data to another pipeline vm:myEndpoint
I believe that Camel can this but google didn't help me.
How can I achieve this ?
Just use a ProducerTemplate from inside your Processor, then you can send any message to any Camel endpoint. You can find more information on the Camel website such as: http://camel.apache.org/producertemplate.html

camel route http response xml parsing

I am new to using camel and I need to build a route in JAVA to process some xml returned by http request. I tried to parse the body of the response by setting up a route with a processor and log it to a file setting the consumer as http url but it didn't work. Then I tried to set up a jms queue to grab and process it from the queue with similar result.
I think I am getting the 200 response but the producer text file I set it to write to is not working and the log4j in DEBUG is not too informative on isolating the issue. Does anyone have any insight on this issue to point me in the right camel direction? thanks in advance!
public static void main(String[] args) throws Exception {
CamelContext camelContext = new DefaultCamelContext();
// connect to embedded ActiveMQ JMS broker
ConnectionFactory connectionFactory =
new ActiveMQConnectionFactory("vm://localhost");
camelContext.addComponent("jms",
JmsComponent.jmsComponentAutoAcknowledge(connectionFactory));
try {
camelContext.addRoutes(new RouteBuilder() {
#Override
public void configure() throws Exception {
from("direct:start")
.to("http://tomcatappurl:8080/format=xml?bridgeEndpoint=true")
.process(new OrderProcessor())
.to("log:DEBUG?showBody=true&showHeaders=true")
.log("file:C:/Desktop/camellog1.txt")
.to("log:DEBUG?showBody=true&showHeaders=true")
.log("${headers}")
.convertBodyTo(String.class)
.to("file:C:/Desktop/camellog1.txt")
.log("${in.headers}")
.to("stream:out")
.to("jms");
from("jms:incomingOrders")
.process(new Processor() {
public void process (Exchange exchange) throws Exception {
//HttpServletRequest request = exchange.getIn().getBody(HttpServletRequest.class);
System.out.println("Response received from Google, is streamCaching = " + exchange.getContext().isStreamCaching());
System.out.println("----------------------------------------------IN MESSAGE--------------------------------------------------------------");
System.out.println(exchange.getIn().getBody(String.class));
System.out.println("----------------------------------------------OUT MESSAGE--------------------------------------------------------------");
//System.out.println(exchange.getOut().getBody(String.class)); //Activating this line causes empty response on browser
}
})
.to("file:C:/Users/Desktop/camellog1.txt?fileExist=Append");
}
});
camelContext.start();
} finally {
camelContext.stop();
}
}
I think your routes are not running.
You need something (like a timer) to trigger your routes, for example:
from("timer:myTimer?period=30s")
.to("direct:start");
Camel documentation for Direct component says:
The direct: component provides direct, synchronous invocation of any consumers when a producer sends a message exchange.
So you need something else to start the invocation of the route.
Mind that your first route must finish to the correct JMS queue:
// ... cut
.to("file:C:/Desktop/camellog1.txt")
.log("${in.headers}")
.to("stream:out")
.to("jms:incomingOrders");
without the queue name it will not work.

Spring integration error channel when using PollableChannel

We're using Spring integration in my application. I'd like put some objects into channel for asynchronous processing and error handling. So for this, I configured MessageGateway with error channel and PollableChannel for handling objects to be processed.
The problem
So I'm calling messageGateway.processMessage(message) to put message into channel. This works as expected - calling this method is non-blocking, messages get processed and are forwarded to next channel. But when processing method throws an exception, it is not redirected to error channel.
On the other hand when I change my processing channel from PollableChannel to SubscribableChannel, error channel works as expected, but calling the gateway is of course blocking. What am I missing? Can I have both non blocking call and error channel?
The code
Component doing the message processing:
#Component
public MessageProcessor {
#Transactional
#ServiceActivator(inputChannel = "msg.process", outputChannel = "msg.postprocess")
public void processMessage(MyMessage message) {
// Message processing that may throw exception
}
}
Channel definition:
#Configuration
public class IntegrationConfig {
#Bean(name = "msg.process")
private MessageChannel processChannel() {
return new RendezvousChannel();
}
#Bean(name = "msg.error")
private MessageChannel errorChannel() {
return new DirectChannel();
}
}
My gateway looks like this:
#MessagingGateway(errorChannel = "msg.error")
public interface MessagingGateway {
#Gateway(requestChannel = "msg.processing")
void processMessage(MyMessage message);
}
Error handler:
#Component
public ErrorHandlers {
#Transactional
#ServiceActivator(inputChannel = "msg.error")
public void processError(MessagingException me) {
// Error handling is here
}
}
But when processing method throws an exception, it is not redirected to error channel.
When a gateway method returns void, the calling thread is released immediately when it returns to the gateway.
The gateway does not add an error channel header in this case (in the next release - 5.0) we have changed that.
In the meantime, you can use a header enricher to set the errorChannel header to your error channel. You can also use the defaultHeaders property on the #MessagingGateway - see the comments on this answer.

Getting the actual class of a message body

I'm passing a List of different objects to a camel route. I would like the route to split the body into one object per message and put the class of the body in a header (using a processor).
from("direct:in")
.split(body())
.process(new JmsTypeHeaderProcessor(body().getClass().getName()))
.to("mock:out");
I'm trying it like this...
#Produce(uri = "direct:in") private ProducerTemplate template;
#EndpointInject(uri = "mock:out") private MockEndpoint endpoint;
#Test
public void testRoute() throws Exception {
List<Object> list = new ArrayList<>();
list.add("String");
list.add(Integer.valueOf(1));
list.add(Boolean.FALSE);
template.sendBody(list);
for (Exchange ex : endpoint.getExchanges()) {
System.out.println("JMSType=" + ex.getIn().getHeader("JMSType"));
}
}
When I run that I find I actually have the headers
JMSType=org.apache.camel.builder.ValueBuilder
JMSType=org.apache.camel.builder.ValueBuilder
JMSType=org.apache.camel.builder.ValueBuilder
whereas I expected, and would like
JMSType=java.lang.String
JMSType=java.lang.Integer
JMSType=java.lang.Boolean
What is needed to get the class of the actual body?
BTW. I can see that log("body.class") returns what I want but I have not been able to follow how it works or adapt it for my needs.
The Camel routes are designed in the route builder and the code is run once, to setup the routes.
So this code
.process(new JmsTypeHeaderProcessor(body().getClass().getName()))
Is invoked once, and body().getClass() returns the ValueBuilder as that is what is used at design time in the DSL to specify body etc.
If you want to access the runtime message body, then get that from the Exchange from the process method of your processor. That is the runtime message and then you can get the body.

Categories

Resources