Class FullAjaxExceptionHandler
- java.lang.Object
-
- jakarta.faces.context.ExceptionHandler
-
- jakarta.faces.context.ExceptionHandlerWrapper
-
- org.omnifaces.exceptionhandler.FullAjaxExceptionHandler
-
- All Implemented Interfaces:
FacesListener
,SystemEventListener
,FacesWrapper<ExceptionHandler>
,EventListener
public class FullAjaxExceptionHandler extends ExceptionHandlerWrapper
The
FullAjaxExceptionHandler
will transparently handle exceptions during ajax requests exactly the same way as exceptions during synchronous (non-ajax) requests.By default, when an exception occurs during a Faces 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. It would make sense if exceptions during ajax requests are handled the same way as exceptions during synchronous requests, which is utilizing the standard Servlet API<error-page>
mechanisms inweb.xml
.Installation
This handler must be registered by a factory as follows in
faces-config.xml
in order to get it to run:<factory> <exception-handler-factory>org.omnifaces.exceptionhandler.FullAjaxExceptionHandlerFactory</exception-handler-factory> </factory>
Error pages
This exception handler will parse the
web.xml
andweb-fragment.xml
files to find the error page locations of the HTTP error code500
and all declared specific exception types. Those locations need to point to Facelets files (JSP is not supported) and the URL must match theFacesServlet
mapping (just mapping it on*.xhtml
should eliminate confusion about virtual URLs). E.g.<error-page> <exception-type>jakarta.faces.application.ViewExpiredException</exception-type> <location>/WEB-INF/errorpages/expired.xhtml</location> </error-page>
The location of the HTTP error code
500
or the exception typejava.lang.Throwable
is required in order to get theFullAjaxExceptionHandler
to work, because there's then at least a fall back error page when there's no match with any of the declared specific exceptions types. You can have both, but thejava.lang.Throwable
one will always get precedence over all others. When you have error pages for specific exception types, then you'd better use the500
one as fallback error page.<error-page> <error-code>500</error-code> <location>/WEB-INF/errorpages/500.xhtml</location> </error-page>
The exception detail is available in the request scope by the standard Servlet error request attributes like as in a normal synchronous error page response. You could for example show them in the error page as follows:
<ul> <li>Date/time: #{of:formatDate(now, 'yyyy-MM-dd HH:mm:ss')}</li> <li>User agent: #{header['user-agent']}</li> <li>User IP: #{request.remoteAddr}</li> <li>Request URI: #{requestScope['jakarta.servlet.error.request_uri']}</li> <li>Ajax request: #{facesContext.partialViewContext.ajaxRequest ? 'Yes' : 'No'}</li> <li>Status code: #{requestScope['jakarta.servlet.error.status_code']}</li> <li>Exception type: #{requestScope['jakarta.servlet.error.exception_type']}</li> <li>Exception message: #{requestScope['jakarta.servlet.error.message']}</li> <li>Exception UUID: #{requestScope['org.omnifaces.exception_uuid']}</li> <li>Stack trace: <pre>#{of:printStackTrace(requestScope['jakarta.servlet.error.exception'])}</pre> </li> </ul>
Exceptions during render response can only be handled when the
jakarta.faces.FACELETS_BUFFER_SIZE
is large enough so that the so far rendered response until the occurrence of the exception fits in there and can therefore safely be resetted.Error in error page itself
When the rendering of the error page failed due to a bug in the error page itself, and the response can still be resetted, then the
FullAjaxExceptionHandler
will display a hardcoded error message in "plain text" informing the developer about the double mistake.Normal requests
Note that the
FullAjaxExceptionHandler
does not deal with normal (non-ajax) requests at all. To properly handle Faces and EL exceptions on normal requests as well, you need an additionalFacesExceptionFilter
. This will extract the root cause from a wrappedFacesException
andELException
before delegating theServletException
further to the container (the container will namely use the first root cause ofServletException
to match an error page by exception in web.xml).Configuration
By default only
FacesException
andELException
are unwrapped. You can supply a context parameter "org.omnifaces.EXCEPTION_TYPES_TO_UNWRAP" to specify additional exception types to unwrap. The context parameter value must be a commaseparated string of fully qualified names of additional exception types. Note that this also covers subclasses of specified exception types.<context-param> <param-name>org.omnifaces.EXCEPTION_TYPES_TO_UNWRAP</param-name> <param-value>jakarta.ejb.EJBException,jakarta.persistence.RollbackException</param-value> </context-param>
This context parameter will also be read and used by
FacesExceptionFilter
.By default all exceptions are logged. You can supply a context parameter "org.omnifaces.EXCEPTION_TYPES_TO_IGNORE_IN_LOGGING" to specify exception types to ignore from logging. The context parameter value must be a commaseparated string of fully qualified names of exception types. Note that this also covers subclasses of specified exception types.
<context-param> <param-name>org.omnifaces.EXCEPTION_TYPES_TO_IGNORE_IN_LOGGING</param-name> <param-value>jakarta.faces.application.ViewExpiredException</param-value> </context-param>
This context parameter will also be read and used by
FacesExceptionFilter
.This context parameter will not suppress standard Faces and/or container builtin logging. This will only suppress
org.omnifaces.exceptionhandler.FullAjaxExceptionHandler
logging. So chances are that standard Faces and/or container will still log it. This may need to be configured separately.Customizing
FullAjaxExceptionHandler
If more fine grained control is desired for determining the root cause of the caught exception, or whether it should be handled, or determining the error page, or logging the exception, then the developer can opt to extend this
FullAjaxExceptionHandler
and override one or more of the following protected methods:findExceptionRootCause(FacesContext, Throwable)
shouldHandleExceptionRootCause(FacesContext, Throwable)
findErrorPageLocation(FacesContext, Throwable)
logException(FacesContext, Throwable, String, LogReason)
logException(FacesContext, Throwable, String, String, Object...)
Don't forget to create a custom
ExceptionHandlerFactory
for it as well, so that it could be registered infaces-config.xml
. This does not necessarily need to extend fromFullAjaxExceptionHandlerFactory
.- Author:
- Bauke Scholtz
- See Also:
FullAjaxExceptionHandlerFactory
,OmniPartialViewContext
,OmniPartialViewContextFactory
,WebXml
,FacesExceptionFilter
-
-
Nested Class Summary
Nested Classes Modifier and Type Class Description protected static class
FullAjaxExceptionHandler.LogReason
This is used inlogException(FacesContext, Throwable, String, LogReason)
.
-
Field Summary
Fields Modifier and Type Field Description static String
EXCEPTION_UUID
The request attribute name of the UUID of the thrown exception which is logged by bothFullAjaxExceptionHandler
andFacesExceptionFilter
.static String
PARAM_NAME_EXCEPTION_TYPES_TO_IGNORE_IN_LOGGING
The context parameter name to specify exception types to ignore in logging by bothFullAjaxExceptionHandler
andFacesExceptionFilter
.static String
PARAM_NAME_EXCEPTION_TYPES_TO_UNWRAP
The context parameter name to specify additional exception types to unwrap by bothFullAjaxExceptionHandler
andFacesExceptionFilter
.
-
Constructor Summary
Constructors Constructor Description FullAjaxExceptionHandler(ExceptionHandler wrapped)
Construct a new ajax exception handler around the given wrapped exception handler.
-
Method Summary
All Methods Static Methods Instance Methods Concrete Methods Modifier and Type Method Description protected String
findErrorPageLocation(FacesContext context, Throwable exception)
Determine the error page location based on the given exception.protected Throwable
findExceptionRootCause(FacesContext context, Throwable exception)
Determine the root cause based on the caught exception, which will then be used to find the error page location.static Class<? extends Throwable>[]
getExceptionTypesToIgnoreInLogging(ServletContext context)
Get the exception types to ignore in logging.static Class<? extends Throwable>[]
getExceptionTypesToUnwrap(ServletContext context)
Get the exception types to unwrap.void
handle()
Handle the ajax exception as follows, only and only if the current request is an ajax request with an uncommitted response and there is at least one unhandled exception: Find the root cause of the exception byfindExceptionRootCause(FacesContext, Throwable)
.protected void
logException(FacesContext context, Throwable exception, String location, String message, Object... parameters)
Log the thrown exception and determined error page location with the given message, optionally parameterized with the given parameters.protected void
logException(FacesContext context, Throwable exception, String location, FullAjaxExceptionHandler.LogReason reason)
Log the thrown exception and determined error page location for the given log reason.protected boolean
shouldHandleExceptionRootCause(FacesContext context, Throwable exception)
Returnstrue
if theFullAjaxExceptionHandler
should handle this exception root cause.-
Methods inherited from class jakarta.faces.context.ExceptionHandlerWrapper
getHandledExceptionQueuedEvent, getHandledExceptionQueuedEvents, getRootCause, getUnhandledExceptionQueuedEvents, getWrapped, isListenerForSource, processEvent
-
-
-
-
Field Detail
-
PARAM_NAME_EXCEPTION_TYPES_TO_UNWRAP
public static final String PARAM_NAME_EXCEPTION_TYPES_TO_UNWRAP
The context parameter name to specify additional exception types to unwrap by bothFullAjaxExceptionHandler
andFacesExceptionFilter
. Those will be added to exception typesFacesException
andELException
.- Since:
- 2.3
- See Also:
- Constant Field Values
-
PARAM_NAME_EXCEPTION_TYPES_TO_IGNORE_IN_LOGGING
public static final String PARAM_NAME_EXCEPTION_TYPES_TO_IGNORE_IN_LOGGING
The context parameter name to specify exception types to ignore in logging by bothFullAjaxExceptionHandler
andFacesExceptionFilter
.- Since:
- 2.5
- See Also:
- Constant Field Values
-
EXCEPTION_UUID
public static final String EXCEPTION_UUID
The request attribute name of the UUID of the thrown exception which is logged by bothFullAjaxExceptionHandler
andFacesExceptionFilter
.- Since:
- 3.2
- See Also:
- Constant Field Values
-
-
Constructor Detail
-
FullAjaxExceptionHandler
public FullAjaxExceptionHandler(ExceptionHandler wrapped)
Construct a new ajax exception handler around the given wrapped exception handler.- Parameters:
wrapped
- The wrapped exception handler.
-
-
Method Detail
-
getExceptionTypesToUnwrap
public static Class<? extends Throwable>[] getExceptionTypesToUnwrap(ServletContext context)
Get the exception types to unwrap. This contains at least the standard types to unwrapFacesException
andELException
. Additional types can be specified via context parameter "org.omnifaces.EXCEPTION_TYPES_TO_UNWRAP", if any.- Parameters:
context
- The involved servlet context.- Returns:
- Exception types to unwrap.
- Since:
- 2.3
-
getExceptionTypesToIgnoreInLogging
public static Class<? extends Throwable>[] getExceptionTypesToIgnoreInLogging(ServletContext context)
Get the exception types to ignore in logging. This can be specified via context parameter "org.omnifaces.EXCEPTION_TYPES_TO_IGNORE_IN_LOGGING".- Parameters:
context
- The involved servlet context.- Returns:
- Exception types to ignore in logging.
- Since:
- 2.5
-
handle
public void handle()
Handle the ajax exception as follows, only and only if the current request is an ajax request with an uncommitted response and there is at least one unhandled exception:- Find the root cause of the exception by
findExceptionRootCause(FacesContext, Throwable)
. - Find the error page location based on root cause by
findErrorPageLocation(FacesContext, Throwable)
. - Set the standard servlet error request attributes.
- Force Faces to render the full error page in its entirety.
- Overrides:
handle
in classExceptionHandlerWrapper
- Find the root cause of the exception by
-
findExceptionRootCause
protected Throwable findExceptionRootCause(FacesContext context, Throwable exception)
Determine the root cause based on the caught exception, which will then be used to find the error page location. The default implementation delegates toExceptions.unwrap(Throwable, Class...)
withFacesException
,ELException
and the types specified in context parameter "org.omnifaces.EXCEPTION_TYPES_TO_UNWRAP", if any.- Parameters:
context
- The involved faces context.exception
- The caught exception to determine the root cause for.- Returns:
- The root cause of the caught exception.
- Since:
- 1.5
-
shouldHandleExceptionRootCause
protected boolean shouldHandleExceptionRootCause(FacesContext context, Throwable exception)
Returnstrue
if theFullAjaxExceptionHandler
should handle this exception root cause. If this returnsfalse
, then theFullAjaxExceptionHandler
will skip handling this exception and delegate it further to the wrapped exception handler. The default implementation just returnstrue
.- Parameters:
context
- The involved faces context.exception
- The caught exception to determine the root cause for.- Returns:
true
if the given exception should be handled by theFullAjaxExceptionHandler
.- Since:
- 1.8
-
findErrorPageLocation
protected String findErrorPageLocation(FacesContext context, Throwable exception)
Determine the error page location based on the given exception. The default implementation delegates toWebXml.findErrorPageLocation(Throwable)
.- Parameters:
context
- The involved faces context.exception
- The exception to determine the error page for.- Returns:
- The location of the error page. It must start with
/
and be relative to the context path. - Since:
- 1.5
-
logException
protected void logException(FacesContext context, Throwable exception, String location, FullAjaxExceptionHandler.LogReason reason)
Log the thrown exception and determined error page location for the given log reason. The default implementation delegates tologException(FacesContext, Throwable, String, String, Object...)
with the default message associated with the log reason.- Parameters:
context
- The involved faces context.exception
- The exception to log.location
- The error page location.reason
- The log reason.- Since:
- 2.4
-
logException
protected void logException(FacesContext context, Throwable exception, String location, String message, Object... parameters)
Log the thrown exception and determined error page location with the given message, optionally parameterized with the given parameters. The default implementation logs throughjava.util.logging
as SEVERE when the thrown exception is not an instance of any type specified in context parameter "org.omnifaces.EXCEPTION_TYPES_TO_IGNORE_IN_LOGGING". Since version 3.2, the log message will be prepended with the UUID and IP address. The UUID is available in EL by#{requestScope['org.omnifaces.exception_uuid']}
.- Parameters:
context
- The involved faces context.exception
- The exception to log.location
- The error page location.message
- The log message.parameters
- The log message parameters, if any. They are formatted usingFormatter
.- Since:
- 1.6
-
-