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 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. 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 in web.xml
.
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>
This exception handler will parse the web.xml
and web-fragment.xml
files to find the error
page locations of the HTTP error code 500
and all declared specific exception types. Those locations
need to point to Facelets files (JSP is not supported) and the URL must match the FacesServlet
mapping (just
mapping it on *.xhtml
should eliminate confusion about virtual URLs). E.g.
<error-page> <exception-type>javax.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 type java.lang.Throwable
is
required in order to get the FullAjaxExceptionHandler
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 the
java.lang.Throwable
one will always get precedence over all others. When you have error pages for
specific exception types, then you'd better use the 500
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['javax.servlet.error.request_uri']}</li> <li>Ajax request: #{facesContext.partialViewContext.ajaxRequest ? 'Yes' : 'No'}</li> <li>Status code: #{requestScope['javax.servlet.error.status_code']}</li> <li>Exception type: #{requestScope['javax.servlet.error.exception_type']}</li> <li>Exception message: #{requestScope['javax.servlet.error.message']}</li> <li>Stack trace: <pre>#{of:printStackTrace(requestScope['javax.servlet.error.exception'])}</pre> </li> </ul>
Exceptions during render response can only be handled when the javax.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.
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.
Note that the FullAjaxExceptionHandler
does not deal with normal (non-ajax) requests at all. To properly
handle JSF and EL exceptions on normal requests as well, you need an additional FacesExceptionFilter
. This
will extract the root cause from a wrapped FacesException
and ELException
before delegating the
ServletException
further to the container (the container will namely use the first root cause of
ServletException
to match an error page by exception in web.xml).
By default only FacesException
and ELException
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>javax.ejb.EJBException,javax.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>javax.faces.application.ViewExpiredException</param-value> </context-param>
This context parameter will not suppress standard JSF and/or container builtin logging. This will
only suppress org.omnifaces.exceptionhandler.FullAjaxExceptionHandler
logging. So chances are that
standard JSF and/or container will still log it. This may need to be configured separately.
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
in faces-config.xml
. This does not necessarily need to extend from
FullAjaxExceptionHandlerFactory
.
FullAjaxExceptionHandlerFactory
,
DefaultExceptionHandlerFactory
,
OmniPartialViewContext
,
OmniPartialViewContextFactory
,
WebXml
,
FacesExceptionFilter
Modifier and Type | Class and Description |
---|---|
protected static class |
FullAjaxExceptionHandler.LogReason
This is used in
logException(FacesContext, Throwable, String, LogReason) . |
Modifier and Type | Field and Description |
---|---|
static String |
PARAM_NAME_EXCEPTION_TYPES_TO_IGNORE_IN_LOGGING
The context parameter name to specify exception types to ignore in logging by
FullAjaxExceptionHandler . |
static String |
PARAM_NAME_EXCEPTION_TYPES_TO_UNWRAP
The context parameter name to specify additional exception types to unwrap by both
FullAjaxExceptionHandler
and FacesExceptionFilter . |
Constructor and Description |
---|
FullAjaxExceptionHandler(ExceptionHandler wrapped)
Construct a new ajax exception handler around the given wrapped exception handler.
|
Modifier and Type | Method and 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>[] |
getExceptionTypesToUnwrap(ServletContext context)
Get the exception types to unwrap.
|
ExceptionHandler |
getWrapped() |
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) . |
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 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 boolean |
shouldHandleExceptionRootCause(FacesContext context,
Throwable exception)
Returns
true if the FullAjaxExceptionHandler should handle this exception root cause. |
getHandledExceptionQueuedEvent, getHandledExceptionQueuedEvents, getRootCause, getUnhandledExceptionQueuedEvents, isListenerForSource, processEvent
public static final String PARAM_NAME_EXCEPTION_TYPES_TO_UNWRAP
FullAjaxExceptionHandler
and FacesExceptionFilter
. Those will be added to exception types FacesException
and ELException
.public static final String PARAM_NAME_EXCEPTION_TYPES_TO_IGNORE_IN_LOGGING
FullAjaxExceptionHandler
.public FullAjaxExceptionHandler(ExceptionHandler wrapped)
wrapped
- The wrapped exception handler.public static Class<? extends Throwable>[] getExceptionTypesToUnwrap(ServletContext context)
FacesException
and
ELException
. Additional types can be specified via context parameter
"org.omnifaces.EXCEPTION_TYPES_TO_UNWRAP", if any.context
- The involved servlet context.public void handle()
findExceptionRootCause(FacesContext, Throwable)
.
findErrorPageLocation(FacesContext, Throwable)
.
handle
in class ExceptionHandlerWrapper
protected Throwable findExceptionRootCause(FacesContext context, Throwable exception)
Exceptions.unwrap(Throwable, Class...)
with FacesException
,
ELException
and the types specified in context parameter
"org.omnifaces.EXCEPTION_TYPES_TO_UNWRAP", if any.context
- The involved faces context.exception
- The caught exception to determine the root cause for.protected boolean shouldHandleExceptionRootCause(FacesContext context, Throwable exception)
true
if the FullAjaxExceptionHandler
should handle this exception root cause. If
this returns false
, then the FullAjaxExceptionHandler
will skip handling this exception and
delegate it further to the wrapped exception handler. The default implementation just returns true
.context
- The involved faces context.exception
- The caught exception to determine the root cause for.true
if the given exception should be handled by the FullAjaxExceptionHandler
.protected String findErrorPageLocation(FacesContext context, Throwable exception)
WebXml.findErrorPageLocation(Throwable)
.context
- The involved faces context.exception
- The exception to determine the error page for./
and be relative to the context path.protected void logException(FacesContext context, Throwable exception, String location, FullAjaxExceptionHandler.LogReason reason)
logException(FacesContext, Throwable, String, String, Object...)
with the default message associated with the log reason.context
- The involved faces context.exception
- The exception to log.location
- The error page location.reason
- The log reason.protected void logException(FacesContext context, Throwable exception, String location, String message, Object... parameters)
java.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".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.public ExceptionHandler getWrapped()
getWrapped
in interface FacesWrapper<ExceptionHandler>
getWrapped
in class ExceptionHandlerWrapper
Copyright © 2012–2017 OmniFaces. All rights reserved.