Following my previous question in Creating FacesMessage in action method outside JSF conversion/validation mechanism? , i'm trying to handle the exceptions thrown from the business layer outside my managed beans.
The strategy is to search and convert business exceptions to faces messages in the a PhaseListener,.
It is working as i expected, but im just wondering if im just reinventing the wheel, or doing it right with the wrong way ?
Here's my code sample snippet :
public class BusinessExceptionHandler implements PhaseListener {
@Override
public void afterPhase(PhaseEvent phaseEvent) {
ExceptionHandler exceptionHandler = phaseEvent.getFacesContext().getExceptionHandler();
// just debugging the handled exception, nothing here
/*
for (ExceptionQueuedEvent event : exceptionHandler.getHandledExceptionQueuedEvents()) {
ExceptionQueuedEventContext context = (ExceptionQueuedEventContext) event.getSource();
System.out.println("handled exception : " + context.getException());
}*/
for (Iterator<ExceptionQueuedEvent> it = exceptionHandler.getUnhandledExceptionQueuedEvents().iterator();
it.hasNext();) {
ExceptionQueuedEvent event = it.next();
ExceptionQueuedEventContext eventContext = (ExceptionQueuedEventContext) event.getSource();
Throwable e = eventContext.getException();
System.out.println("unhandled exception : " + e);
// get the root cause exception
while (e.getCause() != null) {
e = e.getCause();
}
System.out.println("cause exception : " + e +
", cause exception is BE : " + (e instanceof BusinessException));
// handle BE
if (e instanceof BusinessException) {
BusinessException be = (BusinessException) e;
System.out.println("processing BE " + be);
FacesMessage message = Messages.getMessage(
"com.corejsf.errors",
be.getMessage(),
be.getParamValues()
);
FacesContext context = FacesContext.getCurrentInstance();
context.addMessage(null, message);
it.remove(); // remove the exception
// works fine without this block, if BE is thrown, always return to the original page
/*
NavigationHandler navigationHandler = context.getApplication().getNavigationHandler();
System.out.println("navigating to " + context.getViewRoot().getViewId());
navigationHandler.handleNavigation(context, context.getViewRoot().getViewId(), null);
*/
}
}
}
@Override
public void beforePhase(PhaseEvent phaseEvent) {
}
@Override
public PhaseId getPhaseId() {
return PhaseId.INVOKE_APPLICATION;
}
}
Thank you !
Regards, Albert Kam
Not sure why you're going this route, creating and registering your own exception handler is really easy. Though easier will be Seam Catch ( http://seamframework.org/Seam3/CatchModule and http://docs.jboss.org/seam/3/catch/3.0.0.Alpha1/reference/en-US/html_single/ ). I don't have a JSF bridge just yet, but it will be very easy to do. Then all you have to do is write one method that will handle a specific exception, and you'll be done!
Your approach is an intermix of JSF 1.x and JSF 2.x exception handling approaches. Since you're using JSF 2.x, I'd suggest a pure JSF 2.x approach without a PhaseListener
and with help of the new ExceptionHandler
API.
You can find an example which treats the ViewExpiredException
in page 282 of the book "JSF 2.0: The Complete Reference" which is online available here (click the 1st result link).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With