I'd personally implement it in another way.
Define an Exception handler factory in your faces-config.xml
as follows:
<factory>
<exception-handler-factory>
com.package.faces.FullAjaxExceptionHandlerFactory
</exception-handler-factory>
</factory>
Create the exception handler factory that extends javax.faces.context.ExceptionHandlerFactory
. It should return your own implementation of the ExceptionHandler. This could be an example:
import javax.faces.context.ExceptionHandler;
import javax.faces.context.ExceptionHandlerFactory;
public class FullAjaxExceptionHandlerFactory extends ExceptionHandlerFactory {
private ExceptionHandlerFactory wrapped;
/**
* Construct a new full ajax exception handler factory around the given wrapped factory.
* @param wrapped The wrapped factory.
*/
public FullAjaxExceptionHandlerFactory(ExceptionHandlerFactory wrapped) {
this.wrapped = wrapped;
}
/**
* Returns a new instance of {@link FullAjaxExceptionHandler} which wraps the original exception handler.
*/
@Override
public ExceptionHandler getExceptionHandler() {
return new FullAjaxExceptionHandler(wrapped.getExceptionHandler());
}
/**
* Returns the wrapped factory.
*/
@Override
public ExceptionHandlerFactory getWrapped() {
return wrapped;
}
}
In the end, extend the javax.faces.context.ExceptionHandlerWrapper
to handle all exceptions. An example is the following:
public class FullAjaxExceptionHandler extends ExceptionHandlerWrapper {
private ExceptionHandler wrapped;
public FullAjaxExceptionHandler(ExceptionHandler wrapped) {
this.wrapped = wrapped;
}
private static Throwable extractCustomException(Throwable ex) {
Throwable t = ex;
while (t != null) {
if (t instanceof YourOwnExceptionInterface) {
return t;
}
t = t.getCause();
}
return ex;
}
private static String extractMessage(Throwable t) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
t.printStackTrace(pw);
return matchJmillErrorTag(sw.toString());
}
public static boolean handleException(Throwable original) {
Throwable ex = extractCustomException(original);
if (ex instanceof ViewExpiredException) {
// redirect to login page
return false;
} else if (ex instanceof YourOwnExceptionInterface) {
((YourOwnExceptionInterface) ex).handle();
return true;
} else if (ex instanceof NonexistentConversationException) {
FacesContext.getCurrentInstance().getExternalContext().invalidateSession();
// redirect to login page
return false;
} else {
String message = extractMessage(ex);
final FacesContext fc = FacesContext.getCurrentInstance();
original.printStackTrace();
// redirect to error page
fc.responseComplete();
return true;
}
}
@Override
public void handle() throws FacesException {
final Iterator<ExceptionQueuedEvent> i = getUnhandledExceptionQueuedEvents().iterator();
FacesContext facesContext = FacesContext.getCurrentInstance();
if (Redirector.isRedirectingToLogin(facesContext)) {
return;
}
while (i.hasNext()) {
ExceptionQueuedEvent event = i.next();
ExceptionQueuedEventContext context = (ExceptionQueuedEventContext) event.getSource();
i.remove();
if (!handleException(context.getException())) {
return;
}
}
getWrapped().handle();
}
@Override
public ExceptionHandler getWrapped() {
return wrapped;
}
}
Check the public static boolean handleException(Throwable original)
in the previous class. You could use that to manage all your exceptions.
At one point I put a condition there about YourOwnExceptionInterface
which is an interface with a handle()
method that I'd implement for example by a NotAuthorizedException
kind of exception. In this case in the handle()
method of the NotAuthorizedException
I'd notify the user that he can't complete a certain operation through a p:growl component for example. I'd use this in my beans as throw new NotAuthorizedException("message");
The custom exception class should of course extend the RuntimeException
.