Exception handling in parent router - exception

I have parent router that calls other routers. The parent router has all the exception handling logic. In all child routers, on exception, I want to just add properties in the exchange object and leave the actual exception handling in the parent(main) router.
Example:
public class ParentRouter extends RouteBuilder {
#Override
public void configure() throws Exception {
onException(CustomException.class)
.process(new ExceptionProcessor())
.handled(true);
from("direct:parent-route").to("direct:child-route");
from("direct:child-route")
.onException(CustomException.class)
.process(new Processor(){
#Override
public process(Exchange exchange){
exchange.setProperty("childExceptionFlg", "true");
}
});
}
As per my requirement, when CustomExpection is thrown in the child router, it should add a property to the exchange object and the final handling code needs to be executed in the ExceptionProcessor in the parent router.

What you try to achieve can be done using routes dedicated to error handling that call each other (child error handler route calls parent error handler route) or at least a route for the main error handler that is called by the exception policy of your child routes.
Something like:
// The main logic of the main exception policy is moved to a dedicated
// route called direct:main-error-handler
onException(CustomException.class)
.to("direct:main-error-handler")
.handled(true);
from("direct:parent-route").to("direct:child-route");
from("direct:child-route")
.onException(CustomException.class)
// Set the exchange property childExceptionFlg to true
.setProperty("childExceptionFlg", constant("true"))
// Call explicitly the main logic of the the main exception policy once
// the property is set
.to("direct:main-error-handler")
// Flag the exception as handled
.handled(true)
.end()
// Throw a custom exception to simulate your use case
.throwException(new CustomException());
from("direct:main-error-handler")
.log("Property childExceptionFlg set to ${exchangeProperty.childExceptionFlg}");
Result:
INFO route3 - Property childExceptionFlg set to true

Related

How to create global exception handler

In actframework, we can use #catch to handle exception, but it's only working in current class and parent class. What can i do if i want to create a global exception handler, just like #ExceptionHandler in SpringBoot?
Just add #Global annotation to your #Catch method, e.g.
public class AppExceptionHandler {
#Global
#Catch(value = Throwable.class, priority = 1)
public void logThrowable(Throwable throwable) {
AppEntry.LOGGER.error(throwable, "Global Exception Handler: %s", throwable.getMessage());
}
}
With the given code above, it will catch exception triggered in any request handler, e.g,
You can use #ControllerAdvice to create Global Exception Handler in spring boot. Below answer has sample code snippet that explains the same.
#ControllerAdvice even by setting the highest precedense for RestControllers not working as it should

How to pause message processing for a certain period?

We use Apache Camel in Talend ESB Studio v6.4
In an ESB route, we consume JMS messages, process them then send them to an HTTP server. But that target server is down for maintainance every saturday from 6pm to 10pm.
How can we "pause" message consuming or message processing during that period ? I think quartz only works with file/ftp endpoints.
We could use a Processor component to check in Java if we are in the down period, but what to do after that ?
There are several ways to do this. One camel specific way to do it is through CamelControlBus. It takes in a routeId and performs an action (start/stop/resume etc) on it - Read more here to get an understanding Camel ControlBus
However, there is another approach that you can take. You can create a POJO bean that has 3 methods
shouldRouteStop() : to check the current time and decide if it should stop your route.
startRoute() : Starts a route if it is suspended
stopRoute() : Suspends a route if it is started
A simple implementation can be as follows:
public class ManagementBean {
public boolean shouldRouteStop() {
// Mocking the decision here
return new Random().nextBoolean();
}
public void startRoute(org.apache.camel.CamelContext ctx) throws Exception {
if (ctx.getRouteStatus("GenerateInvoices") == ServiceStatus.Suspended)
// replace the argument with your route Id
ctx.resumeRoute("GenerateInvoices");
}
public void stopRoute(org.apache.camel.CamelContext ctx) throws Exception {
if (ctx.getRouteStatus("GenerateInvoices") == ServiceStatus.Started)
// replace the argument with your route Id
ctx.suspendRoute("GenerateInvoices");
}
}
Make sure that the jms-route that you wish to control has a routeId and add this bean to your base/default CamelContext like this
main.bind("manageRouteBean", new ManagementBean());
Create another timer based route, that checks on each tick, if the route should be stopped or not and then suspends or resumes the route by routeId. This route can be implemented like below:
public class MonitoringRoute extends RouteBuilder {
#Override
public void configure() throws Exception {
onException(Exception.class).log(exceptionMessage().toString());
from("timer:time?period=10000")
.choice()
.when().simple("${bean:manageRouteBean?method=shouldRouteStop}")
.log("Route Should Stop")
.bean(ManagementBean.class, "stopRoute(*)")
.otherwise()
.log("Route Should Start")
.bean(ManagementBean.class, "startRoute(*)")
.end();
}
}
Note that startRoute and stopRoute take the argument as *. This is camel way of automatically binding parameters based on type.
Finally, you can add this route to the main camel context like : main.addRouteBuilder(new MonitoringRoute());
For a complete implementation, have a look at this github repo

Method Overriding in Exception handling

In exception handling, it is known that, if the super class method does not declare an exception, subclass overridden method cannot declare the checked exception but it can declare unchecked exception. Why so? consider the following example :
import java.io.*;
class Parent {
void msg() {
System.out.println("parent");
}
}
class TestExceptionChild extends Parent {
void msg() throws IOException {
System.out.println("TestExceptionChild");
}
public static void main(String args[]) {
Parent p = new TestExceptionChild();
p.msg();
}
}
What I have tried:
We get compilation error here. If I need to read a file in the overridden method "msg", then I have to mention "throws IOException" there. But java doesn't allow them. Can anyone explain this?
This happens because you are violating the Liskov substitution principle, i.e: you can't replace the instance of the superclass with one of the subclass because you are modifying the signature of the method msg in the father superclass.
In the more general class, the method msg doesn't throw any exception, and you want to modify the signature in the subclass, which is obviously unallowed, because it violates the contract of the override principal.
You need remember one thing that if you are using throws keyword than any exception arises will be forwarded into the calling chain and in case of overriding at compilation time compiler checks weather the overridden method is there in parent or not and JVM execute the child class method.
So,basically from parent the child method is called and hence it should be capable of handling checked exception if child method throws any exception otherwise CE..
I Hope It Helps :)

Use Struts2+rest plugin, get error for cycle in the hierarchy

SEVERE: Exception occurred during processing request: There is a cycle in the hierarchy!
net.sf.json.JSONException: There is a cycle in the hierarchy!
I have added the setcycleDetectionStrategy in the in the method:
public HttpHeaders show() {
System.out.println("In show.");
JsonConfig jsonConfig = new JsonConfig();
jsonConfig.setIgnoreDefaultExcludes(false);
//jsonConfig.setExcludes(new String[]{"requests"});
jsonConfig.setCycleDetectionStrategy(CycleDetectionStrategy.LENIENT);
model = service.get(Long.parseLong(id));
return new DefaultHttpHeaders("show");
}
But it still does not work.
Usually, it happens with having a instance reference cycle. Some object has an instance variable pointing to another object, which has an instance variable pointing back at the first object. Make sure to avoid the above scenario in your code.

Jersey ParamConverter exceptions not handled by ExceptionMapper

Per title, exceptions thrown from a ParamConverter are NOT handled the way I expect.
With an ExceptionMapper:
#Provider
public class MyExceptionMapper implements ExceptionMapper<MyException> {
#Override
public Response toResponse(MyException exception) {
return Response.serverError().entity( "It triggered" ).build();
}
}
and ParamConverter:
#Provider
(boilerplate junk)
#Override
public DateTime fromString(String value) {
throw new MyException("convert");
}
It does NOT return the "It triggered" text in a 500 error, but rather a 404.
Anticipated question : Are both providers registered?
Yes - If I throw "MyException" from a resource (within 'regular' code) it works as expected. I can also convert see the stacktrace with the "convert" message.
Is there any way to make exceptions from ParamConverters be handled by the ExceptionMapper?
I am using jersey 2.3.1, along with spring-jersey, launched in a jetty container 9.1.0.RC0
Seem from reading this, the JAX-RS spec says the implementor should wrap unhandled exceptions in a NotFoundException (404) for #QueryParam and #PathParam, and from what I tested a 400, (I'm guessing BadRequestException) for #FormParam.
"if the field or property is annotated with #MatrixParam, #QueryParam or #PathParam then an implementation MUST generate an instance of
NotFoundException (404 status) that wraps the thrown exception and no entity"
A couple ways I can see handling the exception, is to
Just handle it in the ParamConverter, e.g.
return new ParamConverter<T>() {
#Override
public T fromString(String string) {
try {
return (T)new MyObject().setValue(string);
} catch (MyException ex) {
Response response = Response.serverError().entity("Boo").build()
throw new WebApplicationException(response);
}
}
#Override
public String toString(T t) {
return t.toString();
}
};
Or just have your exception extend WebApplicationException, and return the Response there. e.g.
public class MyException extends WebApplicationException {
public MyException(String message) {
super(Response.serverError().entity(message).build());
}
}
I experienced the same behavior in Jersey 2.26.
Any Exception that extends RuntimeException gets mapped to a ParamException, which is itself a sublcass of WebApplicationException.
Assuming your MyException extends RuntimeException, it's not getting caught because your ExceptionMapper only handles MyException.
Regarding the Jersey docs saying to throw a NotFoundException: I would argue a 404 does not apply when a queryParam can't be converted. A BadRequestException seems more appropriate. And also, I can't see anything unique in the Jersey frame work when a NotFoundException is thrown besides setting the response code
To get exceptions thrown from a ParamConverter end up in an ExceptionMapper, you'll have to have your ExceptionMapper catching a more global exception, like Throwable.
Another answer suggests returning a WebApplicationException. This should be a fine solution but will NOT work if the Response object has an entity. See here: https://github.com/jersey/jersey/issues/3716