Customize FullAjaxExceptionHandler to show only a faces message for specific exceptions - ajax

I am working on JSF application which uses omnifaces. I have a custom exception handler class for all ajax requests by extending the FullAjaxExceptionHandler and overriding the shouldHandleExceptionRootCause(). In here i add my business errors in to the context and i have to display these messages in the xhtml pages. the ajax calls are made from client using p:commandButton.
But the values that i set in the context from my custom exception handler are not being displayed on the xhtml page.
public class CustomExceptionHandler extends FullAjaxExceptionHandler {
#Override
protected boolean shouldHandleExceptionRootCause(FacesContext context, Throwable exception) {
context.addMessage(null, FacesMessage);
context.getApplication().getNavigationHandler().handleNavigation(context, null, null);
context.getPartialViewContext().setRenderAll(true);
context.renderResponse();
setRequest(request, baseRunTimeException);
return false;
}
}
But the message that i add in the context are not being displayed in the p:messages tag
Please let me know if there anything wrong with this approach ?

As per the functional requirement in your comment,
i dont want to display all the Exceptions as Messages, some of them i will redirect to another error page.
On those which you'd like to forward (not redirect) to error page, just let shouldHandleExceptionRootCause() method return true and register those error pages in web.xml the usual way.
On those which you'd like to show as faces message, just add the desired faces message and then return false.
The below example assumes that you'd like to show the message of an exemplary custom com.example.SystemException as a faces message.
#Override
protected boolean shouldHandleExceptionRootCause(FacesContext context, Throwable exception) {
if (exception instanceof SystemException) {
Messages.addGlobalError(exception.getMessage());
return false; // Don't show error page, just stay in same page.
}
return true; // Show error page as usual for other exceptions.
}

Related

Exception handling in JSF ajax requests

How do I handle the exception and access the stack trace when an exception is thrown while processing a JSF ajax request? Right now, I only get the exception class name and message in a JavaScript alert when JSF project stage is set to Development. Even worse, there's no visual feedback whatsoever when JSF project stage is set to Production, and the server log doesn't show any information about the exception.
If that's relevant, I'm using GlassFish in Netbeans.
This problem is known and fleshed out in among others the OmniFaces FullAjaxExceptionHandler showcase.
By default, when an exception occurs during a JSF ajax request, the enduser would not get any form of feedback if the action was successfully performed or not. In Mojarra, only when the project stage is set to Development, the enduser would see a bare JavaScript alert with only the exception type and message.
The technical reason is that asynchronous requests (read: Ajax requests) by default don't return a synchronous response (read: a full page). Instead, they return small instructions and parts how to update the HTML DOM tree of the already-opened page. When an exception occurs, then these instructions are basically fully absent. Instead, some error information is sent back. You can usually handle them in the onerror attribute of the Ajax component and e.g. display an alert or perhaps perform a window.location change. At least, this is what JSF expected from you.
In order to catch and log the exception and optionally change the whole response, you basically need to create a custom ExceptionHandler. Standard JSF unfortunately doesn't provide a default one out the box (at least, not a sensible one). In your custom exception handler you will be able to get hands on the Exception instance causing all the trouble.
Here's a kickoff example:
public class YourExceptionHandler extends ExceptionHandlerWrapper {
private ExceptionHandler wrapped;
public YourExceptionHandler(ExceptionHandler wrapped) {
this.wrapped = wrapped;
}
#Override
public void handle() throws FacesException {
FacesContext facesContext = FacesContext.getCurrentInstance();
for (Iterator<ExceptionQueuedEvent> iter = getUnhandledExceptionQueuedEvents().iterator(); iter.hasNext();) {
Throwable exception = iter.next().getContext().getException(); // There it is!
// Now do your thing with it. This example implementation merely prints the stack trace.
exception.printStackTrace();
// You could redirect to an error page (bad practice).
// Or you could render a full error page (as OmniFaces does).
// Or you could show a FATAL faces message.
// Or you could trigger an oncomplete script.
// etc..
}
getWrapped().handle();
}
#Override
public ExceptionHandler getWrapped() {
return wrapped;
}
}
In order to get it to run, create a custom ExceptionHandlerFactory as follows:
public class YourExceptionHandlerFactory extends ExceptionHandlerFactory {
private ExceptionHandlerFactory parent;
public YourExceptionHandlerFactory(ExceptionHandlerFactory parent) {
this.parent = parent;
}
#Override
public ExceptionHandler getExceptionHandler() {
return new YourExceptionHandler(parent.getExceptionHandler());
}
}
Which needs to be registered in faces-config.xml as follows:
<factory>
<exception-handler-factory>com.example.YourExceptionHandlerFactory</exception-handler-factory>
</factory>
Alternatively, you can go ahead using the OmniFaces one. It will fully transparently make sure that exceptions during asynchronous requests behave the same as exceptions during synchronous requests, using <error-page> configuration in web.xml.
See also:
Why FullAjaxExceptionHandler does not simply perform an ExternalContext#redirect()?
Authorization redirect on session expiration does not work on submitting a JSF form, page stays the same

Working with multiple #ControllerAdvice classes

I recently start to work with a #ControllerAdvice class to manage the exceptions in my Spring project. My current implementation is something like this:
#ControllerAdvice
public class GlobalDefaultExceptionHandler {
#ExceptionHandler(value = Exception.class)
public ModelAndView defaultErrorHandler(HttpServletRequest req, Exception e) throws Exception {
if (AnnotationUtils.findAnnotation(e.getClass(), ResponseStatus.class) != null) throw e;
return new ModelAndView("error/5xx", "exception", e);
}
}
My next step should be handle more exceptions, but for this I am thinking of use multiple classes with #ControllerAdvice, one for http status code. My goal is make the methods of my controller which handle the form submissions redirect the user for some of my custom status pages (I have one for each group - 1xx, 2xx, 3xx, 4xx, 5xx).
That methods have a structure similar to this:
#RequestMapping(value="cadastra")
#PreAuthorize("hasPermission(#user, 'cadastra_'+#this.this.name)")
public String cadastra(Model model) throws InstantiationException, IllegalAccessException {
model.addAttribute("command", this.entity.newInstance());
return "private/cadastrar";
}
Anyone can tell me if this is a good approach and give some hint of how implement my controller methods to accomplish what I want?
You can have multiple #ControllerAdvice classes that handle different exceptions.
However, because you are handling the Exception.class on your GlobalDefaultExceptionHandler, any exception might be swallowed by it.
The way I got around this was to add #Order( value = Ordered.LOWEST_PRECEDENCE )
on my general exception handler and #Order( value = Ordered.HIGHEST_PRECEDENCE ) on the others.
Maybe you want to define specific exception classes (thrown by your controller, for example: NoResourceFoundException or InvalidResourceStatusException and so on) so your ExceptionController can seperate the different cases and redirect them to the proper status page.

Prevent spring errors on webpage

I am using spring MVC 3.
I validate various users input and show errors as applicable.
But this often to show the spring errors like org.springframework.core.convert.ConversionFailedException etc being shown on UI. How can i prevent the output of these errors on webpage ?
Note:
I understand that for topic starter my answer may be no longer
relevant. But it can be useful for those who have visited this page to
search for solutions to similar problems.
Answer:
In order to prevent the output of errors on web page, you may handle them. There are several types of error handling, that you may use for this in Spring MVC 3.x and above:
Controller-based exception handling
Global exception handling
Other methods, that are bit more complicated
Controller-based exception handling
You can add an #ExceptionHandler annotation on methods inside a controller. Such methods will function as error handlers for exceptions thrown from methods annotated as #RequestMapping in the same controller.
#ExceptionHandler(Exception.class)
public ModelAndView handleError(HttpServletRequest req, Exception e) {
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("exception", e);
modelAndView.addObject("url", req.getRequestURL());
modelAndView.setViewName("error");
return modelAndView;
}
Global exception handling
A controller advice allows you to apply exception handling across the whole application, not just to an individual controller. In other words, handling will apply to exceptions thrown from any controller.
#ControllerAdvice
class GlobalControllerExceptionHandler {
public static final String DEFAULT_ERROR_VIEW = "error";
#ExceptionHandler(Exception.class)
public void handleError(HttpServletRequest req, Exception e) {
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("exception", e);
modelAndView.addObject("url", req.getRequestURL());
modelAndView.setViewName(DEFAULT_ERROR_VIEW);
return modelAndView;
}
}
For more info:
Exception Handling in Spring MVC

Handling PrincipalPermission exceptions in MVC3

On my MVC application I decorated some of the methods of my controller with this:
[PrincipalPermission(SecurityAction.Demand, Role = "Administrator")]
public ActionResult Create(FormCollection collection)
{
try {
...
}
catch {
return View();
}
}
And indeed if I am not logged in or not with the correct role an exception is thrown by the MVC application. The problem is I am not getting the application redirected to an error page.
I tried creating a base controller like this:
[HandleError]
public class BaseController : Controller
{
protected override void OnException(ExceptionContext filterContext)
{
// Make use of the exception later
this.Session["ErrorException"] = filterContext.Exception;
// Mark exception as handled
filterContext.ExceptionHandled = true;
// ... logging, etc
// Redirect
filterContext.Result = this.RedirectToAction("Error", "Home");
base.OnException(filterContext);
}
}
And then adding the Error view in the Home controller as well as the actual View. The problem is that when I try this in Visual Studio I first get an exception upon entering the protected action method:
SecurityException was unhandled by the application
and then I have to do Debug|Continue and only then I am redirected to the the Error view but that is unacceptable in a production application because it should go straight to the Error view.
Just wondering why you are not just using standard AuthorizeAttribute. Pretty sure it would do that same thing and just work?
E.g.
[Authorize(Roles="Administrator")]
public ActionResult Create(FormCollection collection)
Article on general MVC security here.
http://www.codeproject.com/Articles/288631/Secure-ASP-NET-MVC3-applications

Linking Server Side Message/Exception with AJAX request

I am making an ajax submit using Primefaces but I am having trouble linking my server side message with my ajax request.
Supposed I have this button that calls an action.
In my managed bean, do I need to raise an exception? How do I pass this message into my ajax request
public void checkout(ActionEvent event){
if(expression){
throw new CustomException("Account balance is not enough!");
}
}
public class CustomException extends RuntimeException {
public CustomException(String message) {
super(message);
}
}
How do I handle this case? Will my onerror javascript method be able to handle this?
Also, in one case supposed DB is down then how do I handle the exception? Do I have accessed to the error message
in my javascript function?
public void checkout(ActionEvent event){
try{
//DB is down
if(expression){
throw new CustomException("Account balance is not enough!");
}
}catch(Exception e){
}
}
As to your concrete question, you need to implement a custom ExceptionHandler for this which does basically the following when an exception occurs in an ajax request:
String errorPageLocation = "/WEB-INF/errorpages/500.xhtml";
context.setViewRoot(context.getApplication().getViewHandler().createView(context, errorPageLocation));
context.getPartialViewContext().setRenderAll(true);
context.renderResponse();
This is not exactly trivial if you want to take web.xml error pages into account. You'd need to parse the entire web.xml for this to find the error page locations. The OmniFaces utility library has exactly such an exception handler, the FullAjaxExceptionHandler. You can find the full source code here and the showcase example here.
As to your concrete functional requirement, I wouldn't throw an exception when there's just an user error. This is fully recoverable. You need to create and add a FacesMessage and have ajax to update the <h:messages>, <p:messages> or <p:growl>. The PrimeFaces ones support an autoUpdate="true" which would auto-update itself on ajax requests. E.g.
context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "Insufficient balance", null));
with
<p:messages autoUpdate="true" />
Throwing an exception makes only sense in unrecoverable situations like as when the DB is down. Note that you usually don't throw such an exception yourself. In case of JPA it would already be thrown as PersistenceException which you in turn shouldn't catch in JSF managed bean, but just let it go.

Resources