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

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>

Related

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

How to display Primefaces dialog (dialog framework) as part of CustomExceptionHandler

I have a CustomExceptionHandler from which I want to display a modal dialog to get some information from the user, using Primefaces dialog framework.
The CustomExceptionHandler#handle method is being called as expected when I deliberately cause a Null Pointer exception. And I can display and interact with the dialog's .xhtml page if I directly invoke it from a p:commandButton's actionListener on a xhtml page (both cases with ajax enabled and disabled).
When I invoke a p:commandButton (with ajax disabled to eliminate a possible ajax error from complicating the scenario) on a page that leads to the NPE, both before/after log messages are generated from CustomExceptionHandler#handle, but the dialog page is not displayed. The window flashes like it's being refreshed, however.
From CustomExceptoinHandler.java:
public class CustomExceptionHandler
extends ExceptionHandlerWrapper
{
private ExceptionHandler wrapped;
public CustomExceptionHandler(ExceptionHandler wrapped)
{
this.wrapped = wrapped;
}
#Override
public ExceptionHandler getWrapped()
{
return wrapped;
}
#Override
public void handle()
throws FacesException
{
Iterator<ExceptionQueuedEvent> iterator = getUnhandledExceptionQueuedEvents().iterator();
while (iterator.hasNext()) {
boolean removeError = false;
Throwable t = iterator.next().getContext().getException();
while (t.getCause() != null)
t = t.getCause();
if (t instanceof NullPointerException) {
Logging.devLogger.warn("NPE exception handler before dialog");
Map<String, Object> options = new HashMap<>();
options.put("modal", true);
String page = "/home/dialogs/exceptionDialog.xhtml";
RequestContext.getCurrentInstance().openDialog(page, options, null);
Logging.devLogger.warn("NPE exception handler after dialog");
removeError = true;
} // TBD: other cases and refactoring ....
if (removeError) iterator.remove();
}
getWrapped().handle();
}
}
The RequestContext....openDialog() invocation is the same when handling the exception and when the dialog is directly opened via a commandButton. I've determined that the backing bean for the exception dialog (view scoped) gets constructed when the dialog is opened outside the exception situation, but does not get constructed when opened while handling the exception (#PostConstruct method not called).
How would I change the way the exception is handled so the dialog behaves as expected? I'm using Mojarra 2.2.5, Primefaces 4.0, Glassfish 4.0.
I'm woring with PrimeFaces 5.2, i've solved this problem in other way.
To show the dialog, i've created the error dialog in my template named "errorDialog" and te show it by my CustomExceptionHandler i've used, this command
RequestContext.getCurrentInstance().execute("PF('errorDialog').show();");
You can't use the command below, becose there is already an exception, so you can rendered the dialog.
RequestContext.getCurrentInstance().openDialog(page, options, null);
Concerning the exception handling by #PostConstruct method, i've used :
#PostConstruct
private void init() {
try {
initController();
} catch (Exception ex) {
logger.error(ex, null);
//Show the error dialog
MyUtil.openErrorDialog();
}
}
Note : I have still a problem, when an exception (Error 500) is occurred and handled by the App Server and not my CustomHandlerClass, i can't show the dialog becose there is already a redirection by the App Server.

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>

JSF: <f:event> with custom events

I can't figure out if it is possible to use custom events using f:event. The book by Ed Burns suggests to ad the #NamedEvent annotation to the Event class and to use:
<f:event type="com.foo.bar.myEvent" listener="#{listener} />
but the event seems never to be instantiated.
From my point of view this makes sense, since the component does not know anything about the event, e.g. when to publish, so this might be useful for custom component authors only.
On the other hand, standard components should be able to publish the the event if derived from e.g. PostAddToViewEvent. Anyway, custom events seem to be never published by standard components.
Am I missing something? Is there a convenient way to use custom events with standard components?
Here is what I wanted to do:
<h:inputText id="input">
<f:event type="foo.bar.MyCustomEvent" />
</h:inputText>
public class MyCustomEvent extends javax.faces.event.PostAddToViewEvent {
}
yes you can for this you have to override some method in jsf render or component class
public class MyComponent extends HtmlInputText or public class MyRenderer extends TextRenderer
#Override
public void decode(FacesContext context, UIComponent component) {
super.decode(context, component);
String sourceName = context.getExternalContext().getRequestParameterMap().get("javax.faces.source");
if(sourceName != null && sourceName.equals(component.getClientId())){
component.queueEvent(new MyEvent(component));
}
}
but in MyEvent class you have to override some methods
#Override
public PhaseId getPhaseId() {
return PhaseId.INVOKE_APPLICATION;
}
which will define in which face this event will process (by default it is ANY_PHASE and event trigger in same phase in which it registered)
#Override
public boolean isAppropriateListener(FacesListener listener) {
return false;
}
if you have appropiate listener it must return true
if you have appropiate listener for MyEvent then JSF will call that listener's processAction(ActionEvent event) method when it will trigger event, otherwise it will call broadcast method in component class which has to be override by developer
#Override
public void broadcast(FacesEvent event) throws AbortProcessingException {
super.broadcast(event);
if(event instanceof MyEvent){
try {
processMyEvent(event);
} catch (Exception e) {
// TODO: handle exception
}
}
}
Even you can register any event by your own by using component queueEvent(FacesEvent event) method, it will regiester event and it get the phase in which it will trigger by getPhaseId() method in MyEvent class if getPhaseId() method is not overrided by devloper then it will trigger in same phase in which it registered

Resources