How to log specific exception if i am already using FullAjaxExceptionHandler - jsf

I am using FullAjaxExceptionHandler to handle timeout issue in ajax request. The problem that I am facing is to handle javax.faces.view.facelets.FaceletException. If i have an error in the xhtml page, i dont want to show the stack trace instead show an error page. This i have achieved by specifying error page in web.xml. The problem is that i want to log this error. I am using log4j for other exceptions, but how to write handler for FaceletException. If write another Exception handler is there an order in which i should specify the handler class because i am already using FullAjaxExceptionHandler.
faces-config.xml:
<application>
<el-resolver>
org.springframework.web.jsf.el.SpringBeanFacesELResolver
</el-resolver>
</application>
<factory>
<exception-handler-factory>org.omnifaces.exceptionhandler.FullAjaxExceptionHandlerFactory</exception-handler-factory>
</factory>
<render-kit>
<renderer>
<component-family>org.primefaces</component-family>
<renderer-type>org.primefaces.component.ScheduleRenderer</renderer-type>
<renderer-class>com.example.domain.web.custom.MyScheduleRenderrer</renderer-class>
</renderer>
</render-kit>

Add a custom Exception handler factory in faces-config.xml
<application>
<el-resolver>
org.springframework.web.jsf.el.SpringBeanFacesELResolver
</el-resolver>
</application>
<factory>
<exception-handler-factory>com.fetchinglife.domain.web.permissions.CustomExceptionHandlerFactory</exception-handler-factory>
</factory>
Create custom exception handler factory
public class CustomExceptionHandlerFactory extends ExceptionHandlerFactory{
private ExceptionHandlerFactory wrapped;
public CustomExceptionHandlerFactory(ExceptionHandlerFactory wrapped) {
this.wrapped = wrapped;
}
#Override
public ExceptionHandler getExceptionHandler() {
return new CustomExceptionHandler(wrapped.getExceptionHandler());
}
#Override
public ExceptionHandlerFactory getWrapped() {
return wrapped;
}
}
Create custom exception handler
public class CustomExceptionHandler extends FullAjaxExceptionHandler{
static Logger log = Logger
.getLogger(CustomExceptionHandler.class);
public CustomExceptionHandler(ExceptionHandler wrapped) {
super(wrapped);
}
#Override
public void handle() throws FacesException {
Iterator<ExceptionQueuedEvent> unhandledExceptionQueuedEvents = getUnhandledExceptionQueuedEvents().iterator();
if(unhandledExceptionQueuedEvents.hasNext()){
Throwable exception = unhandledExceptionQueuedEvents.next().getContext().getException();
log.error("FL Error",exception);
}
super.handle();
}
}

Unfortunately, it appears that you can't have both.
From The JSF Spec, the ExceptionHandlerFactory is expecting a single type to be configured
From the source of the FullAjaxExceptionHandler, if the exception is non-ajax, it's rethrown, to be handled by the <error-page> mechanism.
You'll either have to extend or wrap the FullAjaxExceptionHandler to provide both Ajax and Non-Ajax exception handling

Related

Why my custom javax.faces.context.ExceptionHandler doesn't handle javax.validation.ConstraintViolationException

My custom exception handler is not being invoked by the container to intercept (checked or unchecked) exceptions (I verified it through the debugger). I have this Entity bean class with #Email annotation for the email field, and when the user types in an invalid email through the JSF page, an error message is being displayed, however, the error message is not the one I set through the custom exception handler class, rather it is the one I have set as the default message for the #Email annotation. The error message generated by the custom exception handler has a prefix string "Exception caught by the custom Exception handler: ". I surmise that an invalid email should throw a ConstraintViolationException, which would be an ideal case for the exception handler to catch.
The JSF page allows the user information to be updated, so when I update the user's email with an invalid one and click the "Update" CommandButton, the registered action method is not being invoked (I verified it through the debugger). Furthermore, what I don't seem to figure out, is that when the "invalid email" error message is displayed on the JSF page, the "Add User" command Button gets disabled, so I can not navigate to the "Add User" JSF page. Any idea, why the exception handler and the page navigation (Add User) are not working in case of an error?
public class CustomExceptionHandler extends ExceptionHandlerWrapper {
private ExceptionHandler wrapped;
private final static Logger logger = Logger.getLogger(CustomExceptionHandler.class.getName());
public CustomExceptionHandler(ExceptionHandler w) {
wrapped = w;
}
#Override
public ExceptionHandler getWrapped() {
return wrapped;
}
#Override
public void handle() throws FacesException {
Iterator iterator = getUnhandledExceptionQueuedEvents().iterator();
while (iterator.hasNext()) {
ExceptionQueuedEvent event = (ExceptionQueuedEvent) iterator.next();
ExceptionQueuedEventContext context = (ExceptionQueuedEventContext)event.getSource();
Throwable throwable = context.getException();
FacesContext fc = FacesContext.getCurrentInstance();
try {
Flash flash = fc.getExternalContext().getFlash();
// Put the exception in the flash scope to be displayed in the error
// page if necessary ...
String errorMessage = "Exception caught by the custom Exception handler: "+throwable.getMessage();
logger.severe(errorMessage);
flash.put("errorDetails", errorMessage);
NavigationHandler navigationHandler = fc.getApplication().getNavigationHandler();
//navigationHandler.handleNavigation(fc, null, "/loginmanagement");
navigationHandler.handleNavigation(fc, null, "error?faces-redirect=true");
fc.renderResponse();
} finally {
iterator.remove();
}
}
// Let the parent handle the rest
getWrapped().handle();
}
}
The factory class:
public class CustomExceptionHandlerFactory extends ExceptionHandlerFactory {
private ExceptionHandlerFactory parent;
public CustomExceptionHandlerFactory(ExceptionHandlerFactory parent) {
this.parent = parent;
}
#Override
public ExceptionHandler getExceptionHandler() {
ExceptionHandler result = new CustomExceptionHandler(parent.getExceptionHandler());
return result;
}
}
The faces-config.xml
<?xml version='1.0' encoding='UTF-8'?>
<faces-config version="2.3"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_3.xsd">
<application>
<resource-bundle>
<base-name>webmessages</base-name>
<var>bundle</var>
</resource-bundle>
<locale-config>
<default-locale>en</default-locale>
<!-- <supported-locale>es</supported-locale> -->
</locale-config>
</application>
<error-page>
<exception-type>java.lang.RuntimeException</exception-type>
<location>/loginmanagement.xhtml</location>
</error-page>
<factory>
<exception-handler-factory>
org.me.mavenlistservicedb.applicationexception.CustomExceptionHandlerFactory
</exception-handler-factory>
</factory>
</faces-config>
Here is the relevant excerpt of the JSF page
<h:column>
<f:facet name="header">#{bundle.loginmanagementemail}</f:facet>
<h:inputText value = "#{l.email}"
size ="30" rendered = "#{l.canUpdate}" />
<h:outputText value = "#{l.email}"
rendered = "#{not l.canUpdate}" />
</h:column>
<f:facet name="footer">
<h:panelGroup style="display: block; border-color: aquamarine;text-align: center;">
<h:commandButton id="update"
value="Save updates"
action="#{loginManagment.saveUpdate}" />
<h:commandButton id="add"
value="Add User"
action="adduser" />
</h:panelGroup>
</f:facet>
I use Netbeans on Windows 10 with Glassfish 5.1.
Thanks

Capture and log / notify unhandled exceptions in a JSF based application

I would like to check and log all unhandled exceptions in my JSF web application using log4j. I read this post Log runtime Exceptions in Java using log4j and add a class that implements Thread.UncaughtExceptionHandler. but the method is not fired.
What is the correct way to achieve this?
add a class that implements Thread.UncaughtExceptionHandler. but the method is not fired
There's usually no means of an uncaught exception in the HTTP request thread managed by a Java EE web application as the server ultimately catches any exception coming from the web application and displays it in case of synchronous HTTP requests in a HTTP 500 error page (in case of asynchronous (ajax) requests, this is in turn framework-dependent). Moreover, if there was really an uncaught exception which escaped the server's attention, it would have killed the server's runtime thread causing the whole server to stop. This is clearly not an ideal real world scenario.
JSF offers you the ExceptionHandler API to get hand of those exceptions and if necessary control them.
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. As per the question, you want to log it using log4j.
logger.error("An exception occurred!", exception);
}
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>
See also:
Exception handling in JSF ajax requests

AbortProcessingException leaves stack trace in server log, how to disable this?

There is a commandButton on a page that asynchronously invokes some service, and when user clicks a button I want to verify service availability by checking special config from database. This config can be updated every minute. So if the service is not available, action of commandButton should not be executed.
So, as per Differences between action and actionListener, I'm checking service availability in actionListener and throw AbortProcessingException in case service is not available. So action will be skipped.
This works fine, but it leaves a stack trace in server's log. I don't want such behavior. Is it possible to handle the exception in such way that this will not leave mark in server logs, just like when ValidatorException is thrown? I'm using OmniFaces FullAjaxExceptionHandler, if that's relevant.
You can suppress the logging with a custom exception handler. As you're currently using OmniFaces FullAjaxExceptionHandler, you'd better extend it. In the handle() method, check if there's an exception and if it's an instance of AbortProcessingException. If so, then just ignore it and return directly from the exception handler.
public class YourExceptionHandler extends FullAjaxExceptionHandler {
public YourExceptionHandler(ExceptionHandler wrapped) {
super(wrapped);
}
#Override
public void handle() throws FacesException {
Iterator<ExceptionQueuedEvent> events = getUnhandledExceptionQueuedEvents().iterator();
if (events.hasNext() && events.next().getContext().getException() instanceof AbortProcessingException) {
return; // Ignore (and don't log).
}
super.handle(); // Continue to FullAjaxExceptionHandler.
}
}
Create a factory around it:
public class YourExceptionHandlerFactory extends ExceptionHandlerFactory {
private ExceptionHandlerFactory wrapped;
public YourExceptionHandlerFactory(ExceptionHandlerFactory wrapped) {
this.wrapped = wrapped;
}
#Override
public ExceptionHandler getExceptionHandler() {
return new YourExceptionHandler(getWrapped().getExceptionHandler());
}
#Override
public ExceptionHandlerFactory getWrapped() {
return wrapped;
}
}
In order to get this to run, register it as factory in faces-config.xml the usual way, replacing the FullAjaxExceptionHandlerFactory:
<factory>
<exception-handler-factory>com.example.YourExceptionHandlerFactory</exception-handler-factory>
</factory>

JSF 2 Global exception handling, navigation to error page not happening

I am developing a JSF 2.0 based web application. I am trying to implement a global exception handler which will redirect the user to a generic error page whenever any exception occurs (e.g. NullPointerException,ServletException,ViewExpiredException etc.)
Whenever a NPE occurs in my app, My customnavhandler breakpoint is hit and NavigationHandler code is executed, but somehow redirection to error page is not happening, the requested page remains partially rendered. Any idea what could be wrong here ? One info is that I am throwing an NPE deliberately on the requested page (which was partiallyu rendered after NPE)
My faces-config.xml entry
<factory>
<exception-handler-factory>
com.common.exceptions.CustomExceptionHandlerFactory
</exception-handler-factory>
</factory>
My CustomNavHandler
public class CustomExceptionHandler extends ExceptionHandlerWrapper {
private static final Logger logger = Logger.getLogger("com.gbdreports.common.exception.CustomExceptionHandler");
private final ExceptionHandler wrapped;
public CustomExceptionHandler(ExceptionHandler wrapped) {
this.wrapped = wrapped;
}
#Override
public ExceptionHandler getWrapped() {
return this.wrapped;
}
public void handle() throws FacesException {
final Iterator<ExceptionQueuedEvent> i = getUnhandledExceptionQueuedEvents().iterator();
while (i.hasNext()) {
ExceptionQueuedEvent event = i.next();
ExceptionQueuedEventContext context =
(ExceptionQueuedEventContext) event.getSource();
// get the exception from context
Throwable t = context.getException();
final FacesContext fc = FacesContext.getCurrentInstance();
final ExternalContext externalContext = fc.getExternalContext();
final Map<String, Object> requestMap = fc.getExternalContext().getRequestMap();
final ConfigurableNavigationHandler nav = (ConfigurableNavigationHandler) fc.getApplication().getNavigationHandler();
//here you do what ever you want with exception
try {
//log error ?
logger.error("Severe Exception Occured");
//log.log(Level.SEVERE, "Critical Exception!", t);
//redirect error page
requestMap.put("exceptionMessage", t.getMessage());
nav.performNavigation("/TestPRoject/error.xhtml");
fc.renderResponse();
// remove the comment below if you want to report the error in a jsf error message
//JsfUtil.addErrorMessage(t.getMessage());
}
finally {
//remove it from queue
i.remove(); }
}
//parent hanle
getWrapped().handle();
}
}
My customNavhandler factory
public class CustomExceptionHandlerFactory extends ExceptionHandlerFactory {
private ExceptionHandlerFactory parent;
public CustomExceptionHandlerFactory(ExceptionHandlerFactory parent) {
this.parent = parent;
}
#Override
public ExceptionHandler getExceptionHandler() {
return new CustomExceptionHandler (parent.getExceptionHandler());
}
}
It's most likely because the current request is an ajax (asynchronous) request. The exception handler which you've there is designed for regular (synchronous) requests.
The proper way to change the view in case of an ajax exception is as follows:
String viewId = "/error.xhtml";
ViewHandler viewHandler = context.getApplication().getViewHandler();
context.setViewRoot(viewHandler.createView(context, viewId));
context.getPartialViewContext().setRenderAll(true);
context.renderResponse();
This is however somewhat naive. This won't work if the ajax exception is been thrown in midst of rendering of a ajax response.
I'd suggest to not reinvent the wheel. The JSF utility library OmniFaces has a complete working solution in flavor of FullAjaxExceptionHandler. You can find the full source code here and the showcase example here. It makes use of standard servlet API <error-page> declarations in web.xml. This way the error pages are also reusable for synchronous requests, with a little help of FacesExceptionFilter, also provided by OmniFaces.
See also:
using ExternalContext.dispatch in JSF error handler causes corrupt page rendering
What is the correct way to deal with JSF 2.0 exceptions for AJAXified components?
Unified way to handle both ajax and non ajax requests exception could be done simplifying your code. Instead of
requestMap.put("exceptionMessage", t.getMessage());
nav.performNavigation("/TestPRoject/error.xhtml");
fc.renderResponse();
is enough to use:
fc.getExternalContext().redirect("/TestPRoject/error.xhtml");

JSF: How to execute some code on every time a navigation rule is executed?

Is there any way I can execute some code whenever a navigation rule is executed. Basically what I am trying to do is to have a JourneyTracker bean which will hold the current state of the journey (like the current page the user is in).
You can use a custom NavigationHandler for this. Basically, just extend that abstract class as follows:
public class MyNavigationHandler extends NavigationHandler {
private NavigationHandler wrapped;
public MyNavigationHandler(NavigationHandler wrapped) {
this.wrapped = wrapped;
}
#Override
public void handleNavigation(FacesContext context, String from, String outcome) {
// Do your job here. Just check if "from" and/or "outcome" matches the desired rule.
wrapped.handleNavigation(context, from, outcome); // Important! This will perform the actual navigation.
}
}
To get it to run, just register it as follows in faces-config.xml:
<application>
<navigation-handler>com.example.MyNavigationHandler</navigation-handler>
</application>

Resources