/*
* Copyright 2017 OmniFaces
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package org.omnifaces.exceptionhandler;
import static javax.faces.application.FacesMessage.SEVERITY_FATAL;
import static org.omnifaces.util.Messages.addGlobal;
import java.util.Iterator;
import javax.faces.application.FacesMessage;
import javax.faces.context.ExceptionHandler;
import javax.faces.context.ExceptionHandlerWrapper;
import javax.faces.context.FacesContext;
import javax.faces.event.ExceptionQueuedEvent;
/**
* <p>
* The {@link FacesMessageExceptionHandler} will add every exception as a global FATAL faces message.
*
* <h3>Installation</h3>
* <p>
* This handler must be registered by a factory as follows in <code>faces-config.xml</code> in order to get it to run:
* <pre>
* <factory>
* <exception-handler-factory>org.omnifaces.exceptionhandler.FacesMessageExceptionHandlerFactory</exception-handler-factory>
* </factory>
* </pre>
*
* <h3>Note</h3>
* <p>
* It's your own responsibility to make sure that the faces messages are being shown. Make sure that there's a
* <code><h:messages></code> or any equivalent component (OmniFaces, PrimeFaces, etc) is present in the view and
* that it can handle global messages and that it's explicitly or automatically updated in case of ajax requests. Also
* make sure that you don't have bugs in rendering of your views. This exception handler is not capable of handling
* exceptions during render response. It will fail silently.
*
* <h3>Customizing <code>FacesMessageExceptionHandler</code></h3>
* <p>
* If more fine grained control of creating the FATAL faces message is desired, then the developer can opt to extend
* this {@link FacesMessageExceptionHandler} and override the following method:
* <ul>
* <li>{@link #createFatalMessage(Throwable)}
* </ul>
*
* @author Bauke Scholtz
* @see FacesMessageExceptionHandlerFactory
* @see DefaultExceptionHandlerFactory
* @since 1.8
*/
public class FacesMessageExceptionHandler extends ExceptionHandlerWrapper {
// Variables ------------------------------------------------------------------------------------------------------
private ExceptionHandler wrapped;
// Constructors ---------------------------------------------------------------------------------------------------
/**
* Construct a new faces message exception handler around the given wrapped exception handler.
* @param wrapped The wrapped exception handler.
*/
public FacesMessageExceptionHandler(ExceptionHandler wrapped) {
this.wrapped = wrapped;
}
// Actions --------------------------------------------------------------------------------------------------------
/**
* Set every exception as a global FATAL faces message.
*/
@Override
public void handle() {
for (Iterator<ExceptionQueuedEvent> iter = getUnhandledExceptionQueuedEvents().iterator(); iter.hasNext();) {
addGlobal(new FacesMessage(SEVERITY_FATAL, createFatalMessage(iter.next().getContext().getException()), null));
iter.remove();
}
wrapped.handle();
}
/**
* Create fatal message based on given exception which will in turn be passed to
* {@link FacesContext#addMessage(String, javax.faces.application.FacesMessage)}.
* The default implementation returns {@link Throwable#toString()}.
* @param exception The exception to create fatal message for.
* @return The fatal message created based on the given exception.
*/
protected String createFatalMessage(Throwable exception) {
return exception.toString();
}
@Override
public ExceptionHandler getWrapped() {
return wrapped;
}
}