Apache Camel: How to get the exception message inside the doCatch() block? - apache

I need to return the message from a thrown exception, or put it in the outmessage. But it does not print the correct message on the frontend.
The camel docs suggest using .transform(simple?...) .handled(true) but most of it is deprecated.
What's the correct way of doing this?
Response:
<418 I'm a teapot,simple{${exception.message}},{}>
Route
from("direct:csv")
.doTry()
.process(doSomeThingWithTheFileProcessor)
.doCatch(Exception.class)
.process(e -> {
e.getOut().setBody(new ResponseEntity<String>(exceptionMessage().toString(), HttpStatus.I_AM_A_TEAPOT));
}).stop()
.end()
.process(finalizeTheRouteProcessor);
doSomethingWithFileProcessor
public void process(Exchange exchange) throws Exception {
String filename = exchange.getIn().getHeader("CamelFileName", String.class);
MyFile mf = repo.getFile(filename); //throws exception
exchange.getOut().setBody(exchange.getIn().getBody());
exchange.getOut().setHeader("CamelFileName", exchange.getIn().getHeader("CamelFileName"));
}

There is a lot of ways how to do it. All of it is correct, choose your favourite depending on complexity of error handling. I have published examples in this gist. None of it is deprecated in Camel version 2.22.0.
With Processor
from("direct:withProcessor")
.doTry()
.process(new ThrowExceptionProcessor())
.doCatch(Exception.class)
.process(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
final Throwable ex = exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Throwable.class);
exchange.getIn().setBody(ex.getMessage());
}
})
.end();
With Simple language
from("direct:withSimple")
.doTry()
.process(new ThrowExceptionProcessor())
.doCatch(Exception.class)
.transform().simple("${exception.message}")
.end();
With setBody
from("direct:withValueBuilder")
.doTry()
.process(new ThrowExceptionProcessor())
.doCatch(Exception.class)
.setBody(exceptionMessage())
.end();

In the doCatch() Camel moves the exception into a property on the exchange with the key Exchange.EXCEPTION_CAUGHT (http://camel.apache.org/why-is-the-exception-null-when-i-use-onexception.html).
So you can use
e.getOut().setBody(new ResponseEntity<String>(e.getProperty(Exchange.EXCEPTION_CAUGHT, Exception.class).getMessage(), HttpStatus.OK));

Related

Handling checked exception in Mono flow

Not sure how to handle checked exception in the Mono flow.
return Mono.when(monoPubs)
.zipWhen((monos) -> repository.findById(...))
.map((tuple) -> tuple.getT2())
.zipWhen((org) -> createMap(org))
.map((tuple) -> tuple.getT2())
.zipWhen((map) -> emailService.sendEmail(...))
.flatMap(response -> {
return Mono.just(userId);
});
Here, the sendEmail method is declared with throws Exception.
public Mono<Boolean> sendEmail(...)
throws MessagingException, IOException
So, How to handle this checked exception in the zipWhen flow.
Also, How to handle
.zipWhen((map) -> emailService.sendEmail(...))
if the method returns void.
You need to review implementation of the sendEmail. You cannot throw checked exceptions from the publisher and need to wrap any checked exception into an unchecked exception.
The Exceptions class provides a propagate method that could be used to wrap any checked exception into an unchecked exception.
try {
...
}
catch (SomeCheckedException e) {
throw Exceptions.propagate(e);
}
As an alternative, you could use lombok #SneakyThrows to wrap non-reactive method.
Exceptions are thrown from Mono method, you can use onError* methods to handle the exception the way you like
var result = Mono.just("test")
.zipWhen((map) -> sendEmail())
.onErrorMap(SendEmailException.class, e -> new RuntimeException(e.getMessage()))
.flatMap(Mono::just);
Also it is not very clear from your post that if sendEmail takes param or not, sendEmail is not taking any input, I would just use doOnNext as it is a void method.

Catching errors on actor construction in Akka TestKit

I am trying to learn unit testing with Akka.
I have a situation where one of my tests was throwing an exception on construction and was wondering what the best way to capture this and log or otherwise throw it would be. As it stands now I had to attach a debugger and see where it threw.
I thought that I could perhaps create another actor which does logging and, on error, have a message sent to it. Breakpoints I put in the ErrorActor were never hit though. It seems as though the RootActor failed and timed out before the message was sent / received.
Is there something I'm doing wrong here or am I fundamentally off base with this? What is the the recommended way to catch errors in unit tests?
Thanks very much
[Fact]
public void CreateRootActor()
{
// Arrange
var props = Props.Create(() => new RootActor());
Sys.ActorOf(Props.Create( () =>new TestErrorActor(TestLogger)), ActorPaths.ErrorActor.Name); // register my test actor
// Act
var actor = new TestActorRef<RootActor>(this.Sys, props);
// Assert
Assert.IsType<RootActor>(actor.UnderlyingActor);
}
public class RootActor : ReceiveActor
{
private ITenantRepository tenantRepository;
public RootActor(ILifetimeScope lifetimeScope)
{
try
{
this.tenantRepository = lifetimeScope.Resolve<ITenantRepository>(); // this throws
}
catch (Exception e)
{
Context.ActorSelection(ErrorActor.Name).Tell(new TestErrorActor.RaiseError(e));
throw;
}
....
I got around this by using Akka.Logger.Serilog and a try / catch in the RootActor. I deleted the ErrorActor.

Camel Dead Letter Channel for all exceptions

Im creating a dead letter channel errorhandler like below
errorHandler(deadLetterChannel("direct:myDLC").useOriginalMessage().maximumRedeliveries(1));
from("direct:myDLC")
.bean(MyErrorProcessor.class);
The Bean MyErrorProcessor should be able to handle all types of checked and unchecked exceptions like below..
public void process(Exchange exchange) throws Exception {
Exception e=(Exception)exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Exception.class);
e.printStackTrace();
if(e instanceof MyUncheckedException){
logger.error("MyUncheckedException: "+((MyException) e).getErrorCode()+" : "+((MyException) e).getErrorDesc());
}else if(e instanceof MyException){
logger.error("MyException: "+((MyException) e).getErrorCode()+" : "+((MyException) e).getErrorDesc());
}
}
But after exception is handled the original message should be redirected to route's endpoint.. how to continue route once exception handled like this??
Using continued() will work, it will ignore the error and continue to process, so then you would probably want to handle the specific Exception
see http://camel.apache.org/exception-clause.html
onException(MyException.class)
.continued(true)
;
If you would use .useOriginalMessage() on this exception handling, the original message would be the message that is continued.

Retrieving parameter values using Microsoft Enterprise Library Exception Handler

We are using Enterprise Library for all our logging and exception handling needs in our app. We have added an email listener to send all the caught exceptions in email to the administrator. One requirement is that when an exception occurs in a method we need to retrieve the parameter values of the method if any and attach it to the exception details in the email sent. Is it possible without writing a custom logger?
Just create a custom exception, setting the message to the parameters:
try {
...
} catch(Exception ex) {
var customException = new CustomException(ex, string.format("Param1 {0}, Param2 {1}", param1, param2));
bool rethrow = ExceptionPolicy.HandleException(customException, PolicyName);
}
verified that in fact the ExceptionFormatter class will indeed traverse all inner exceptions, so your CustomException could be as simple as
public class CustomException : Exception
{
public CustomException(string message, Exception innerException) : base(message, innerException)
{
}
}

Force antlr3 to immediately exit when a rule fails

I've got a rule like this:
declaration returns [RuntimeObject obj]:
DECLARE label value { $obj = new RuntimeObject($label.text, $value.text); };
Unfortunately, it throws an exception in the RuntimeObject constructor because $label.text is null. Examining the debug output and some other things reveals that the match against "label" actually failed, but the Antlr runtime "helpfully" continues with the match for the purpose of giving a more helpful error message (http://www.antlr.org/blog/antlr3/error.handling.tml).
Okay, I can see how this would be useful for some situations, but how can I tell Antlr to stop doing that? The defaultErrorHandler=false option from v2 seems to be gone.
I don't know much about Antlr, so this may be way off base, but the section entitled "Error Handling" on this migration page looks helpful.
It suggests you can either use #rulecatch { } to disable error handling entirely, or override the mismatch() method of the BaseRecogniser with your own implementation that doesn't attempt to recover. From your problem description, the example on that page seems like it does exactly what you want.
You could also override the reportError(RecognitionException) method, to make it rethrow the exception instead of print it, like so:
#parser::members {
#Override
public void reportError(RecognitionException e) {
throw new RuntimeException(e);
}
}
However, I'm not sure you want this (or the solution by ire_and_curses), because you will only get one error per parse attempt, which you can then fix, just to find the next error. If you try to recover (ANTLR does it okay) you can get multiple errors in one try, and fix all of them.
You need to override the mismatch and recoverFromMismatchedSet methods to ensure an exception is thrown immediately (examples are for Java):
#members {
protected void mismatch(IntStream input, int ttype, BitSet follow) throws RecognitionException {
throw new MismatchedTokenException(ttype, input);
}
public Object recoverFromMismatchedSet(IntStream input, RecognitionException e, BitSet follow) throws RecognitionException {
throw e;
}
}
then you need to change how the parser deals with those exceptions so they're not swallowed:
#rulecatch {
catch (RecognitionException e) {
throw e;
}
}
(The bodies of all the rule-matching methods in your parser will be enclosed in try blocks, with this as the catch block.)
For comparison, the default implementation of recoverFromMismatchedSet inherited from BaseRecognizer:
public Object recoverFromMismatchedSet(IntStream input, RecognitionException e, BitSet follow) throws RecognitionException {
if (mismatchIsMissingToken(input, follow)) {
reportError(e);
return getMissingSymbol(input, e, Token.INVALID_TOKEN_TYPE, follow);
}
throw e;
}
and the default rulecatch:
catch (RecognitionException re) {
reportError(re);
recover(input,re);
}