javax.faces.webapp.PreJsf2ExceptionHandlerFactory Maven / Gradle / Ivy
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 javax.faces.webapp;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.LinkedList;
import java.util.Queue;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.el.ELException;
import javax.faces.FacesException;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.component.UpdateModelException;
import javax.faces.context.ExceptionHandler;
import javax.faces.context.ExceptionHandlerFactory;
import javax.faces.context.FacesContext;
import javax.faces.event.AbortProcessingException;
import javax.faces.event.ExceptionQueuedEvent;
import javax.faces.event.ExceptionQueuedEventContext;
import javax.faces.event.SystemEvent;
import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFWebConfigParam;
/**
* @author Simon Lessard (latest modification by $Author: bommel $)
* @author Jakob Korherr
* @version $Revision: 1187700 $ $Date: 2011-10-22 07:19:37 -0500 (Sat, 22 Oct 2011) $
*
* @since 2.0
*/
public class PreJsf2ExceptionHandlerFactory extends ExceptionHandlerFactory
{
//private static final Log log = LogFactory.getLog (PreJsf2ExceptionHandlerFactory.class);
private static final Logger log = Logger.getLogger(PreJsf2ExceptionHandlerFactory.class.getName());
/**
*
*/
public PreJsf2ExceptionHandlerFactory()
{
}
/**
* {@inheritDoc}
*/
@Override
public ExceptionHandler getExceptionHandler()
{
return new PreJsf2ExceptionHandlerImpl();
}
private static class PreJsf2ExceptionHandlerImpl extends ExceptionHandler
{
/*
* PLEASE NOTE!!!
* This is a copy of the ExceptionHandler implementation of myfaces-impl
* (org.apache.myfaces.context.ExceptionHandlerImpl), only handle() differs a bit.
* Any changes made here should also be applied to ExceptionHandlerImpl in the right way.
*
* This is really ugly, but I think we have to do this due to the fact that PreJsf2ExceptionHandlerFactory
* can be declared directly as an exception handler factory, so it's not as if we can make the methods
* in the factory abstract and have a concrete impl in the impl project (and therefore be able to
* extend ExceptionHandlerImpl). If this is not the case, please change accordingly.
*/
private static final Logger log = Logger.getLogger(PreJsf2ExceptionHandlerImpl.class.getName());
/**
* Since JSF 2.0 there is a standard way to deal with unexpected Exceptions: the ExceptionHandler.
* Due to backwards compatibility MyFaces 2.0 also supports the init parameter
* org.apache.myfaces.ERROR_HANDLER, introduced in MyFaces 1.2.4. However, the given error handler
* now only needs to include the following method:
*
* - handleException(FacesContext fc, Exception ex)
*
* Furthermore, the init parameter only works when using the PreJsf2ExceptionHandlerFactory.
*/
@JSFWebConfigParam(since="1.2.4",desc="Deprecated: use JSF 2.0 ExceptionHandler", deprecated=true)
private static final String ERROR_HANDLER_PARAMETER = "org.apache.myfaces.ERROR_HANDLER";
private Queue handled;
private Queue unhandled;
private ExceptionQueuedEvent handledAndThrown;
public PreJsf2ExceptionHandlerImpl()
{
}
/**
* {@inheritDoc}
*/
@Override
public ExceptionQueuedEvent getHandledExceptionQueuedEvent()
{
return handledAndThrown;
}
/**
* {@inheritDoc}
*/
@Override
public Iterable getHandledExceptionQueuedEvents()
{
return handled == null ? Collections.emptyList() : handled;
}
/**
* {@inheritDoc}
*/
@Override
public Throwable getRootCause(Throwable t)
{
if (t == null)
{
throw new NullPointerException("t");
}
while (t != null)
{
Class> clazz = t.getClass();
if (!clazz.equals(FacesException.class) && !clazz.equals(ELException.class))
{
return t;
}
t = t.getCause();
}
return null;
}
/**
* {@inheritDoc}
*/
@Override
public Iterable getUnhandledExceptionQueuedEvents()
{
return unhandled == null ? Collections.emptyList() : unhandled;
}
/**
* {@inheritDoc}
*
* Differs from ExceptionHandlerImpl.handle() in three points:
* - Any exceptions thrown before or after phase execution will be logged and swallowed.
* - If the Exception is an instance of UpdateModelException, extract the FacesMessage from the UpdateModelException.
* Log a SEVERE message to the log and queue the FacesMessage on the FacesContext, using the clientId of the source
* component in a call to FacesContext.addMessage(java.lang.String, javax.faces.application.FacesMessage).
* - Checks org.apache.myfaces.ERROR_HANDLER for backwards compatibility to myfaces-1.2's error handling
*/
@Override
public void handle() throws FacesException
{
if (unhandled != null && !unhandled.isEmpty())
{
if (handled == null)
{
handled = new LinkedList();
}
// check the org.apache.myfaces.ERROR_HANDLER init param
// for backwards compatibility to myfaces-1.2's error handling
String errorHandlerClass = FacesContext.getCurrentInstance()
.getExternalContext().getInitParameter(ERROR_HANDLER_PARAMETER);
FacesException toThrow = null;
do
{
// For each ExceptionEvent in the list
// get the event to handle
ExceptionQueuedEvent event = unhandled.peek();
try
{
// call its getContext() method
ExceptionQueuedEventContext context = event.getContext();
// and call getException() on the returned result
Throwable exception = context.getException();
if (errorHandlerClass != null)
{
// myfaces-1.2's error handler
try
{
Class> clazz = Class.forName(errorHandlerClass);
Object errorHandler = clazz.newInstance();
Method m = clazz.getMethod("handleException", new Class[] { FacesContext.class, Exception.class });
m.invoke(errorHandler, new Object[] { context.getContext(), exception });
}
catch (ClassNotFoundException ex)
{
throw new FacesException("Error-Handler : " + errorHandlerClass
+ " was not found. Fix your web.xml-parameter : " + ERROR_HANDLER_PARAMETER, ex);
}
catch (IllegalAccessException ex)
{
throw new FacesException("Constructor of error-Handler : " + errorHandlerClass
+ " is not accessible. Error-Handler is specified in web.xml-parameter : "
+ ERROR_HANDLER_PARAMETER, ex);
}
catch (InstantiationException ex)
{
throw new FacesException("Error-Handler : " + errorHandlerClass
+ " could not be instantiated. Error-Handler is specified in web.xml-parameter : "
+ ERROR_HANDLER_PARAMETER, ex);
}
catch (NoSuchMethodException ex)
{
throw new FacesException("Error-Handler : " + errorHandlerClass
+ " does not have a method with name : handleException and parameters : "
+ "javax.faces.context.FacesContext, java.lang.Exception. Error-Handler is"
+ "specified in web.xml-parameter : " + ERROR_HANDLER_PARAMETER, ex);
}
catch (InvocationTargetException ex)
{
throw new FacesException("Excecution of method handleException in Error-Handler : "
+ errorHandlerClass
+ " caused an exception. Error-Handler is specified in web.xml-parameter : "
+ ERROR_HANDLER_PARAMETER, ex);
}
}
else
{
// spec described behaviour of PreJsf2ExceptionHandler
// UpdateModelException needs special treatment here
if (exception instanceof UpdateModelException)
{
FacesMessage message = ((UpdateModelException) exception).getFacesMessage();
// Log a SEVERE message to the log
log.log(Level.SEVERE, message.getSummary(), exception.getCause());
// queue the FacesMessage on the FacesContext
UIComponent component = context.getComponent();
String clientId = null;
if (component != null)
{
clientId = component.getClientId(context.getContext());
}
context.getContext().addMessage(clientId, message);
}
else if (!shouldSkip(exception) && !context.inBeforePhase() && !context.inAfterPhase())
{
// set handledAndThrown so that getHandledExceptionQueuedEvent() returns this event
handledAndThrown = event;
// Re-wrap toThrow in a ServletException or (PortletException, if in a portlet environment)
// and throw it
// FIXME: The spec says to NOT use a FacesException to propagate the exception, but I see
// no other way as ServletException is not a RuntimeException
toThrow = wrap(getRethrownException(exception));
break;
}
else
{
// Testing mojarra it logs a message and the exception
// however, this behaviour is not mentioned in the spec
log.log(Level.SEVERE, exception.getClass().getName() + " occured while processing " +
(context.inBeforePhase() ? "beforePhase() of " :
(context.inAfterPhase() ? "afterPhase() of " : "")) +
"phase " + context.getPhaseId() + ": " +
"UIComponent-ClientId=" +
(context.getComponent() != null ?
context.getComponent().getClientId(context.getContext()) : "") + ", " +
"Message=" + exception.getMessage());
log.log(Level.SEVERE, exception.getMessage(), exception);
}
}
}
catch (Throwable t)
{
// A FacesException must be thrown if a problem occurs while performing
// the algorithm to handle the exception
throw new FacesException("Could not perform the algorithm to handle the Exception", t);
}
finally
{
// if we will throw the Exception or if we just logged it,
// we handled it in either way --> add to handled
handled.add(event);
unhandled.remove(event);
}
} while (!unhandled.isEmpty());
// do we have to throw an Exception?
if (toThrow != null)
{
throw toThrow;
}
}
}
/**
* {@inheritDoc}
*/
@Override
public boolean isListenerForSource(Object source)
{
return source instanceof ExceptionQueuedEventContext;
}
/**
* {@inheritDoc}
*/
@Override
public void processEvent(SystemEvent exceptionQueuedEvent) throws AbortProcessingException
{
if (unhandled == null)
{
unhandled = new LinkedList();
}
unhandled.add((ExceptionQueuedEvent)exceptionQueuedEvent);
}
protected Throwable getRethrownException(Throwable exception)
{
// Let toRethrow be either the result of calling getRootCause() on the Exception,
// or the Exception itself, whichever is non-null
Throwable toRethrow = getRootCause(exception);
if (toRethrow == null)
{
toRethrow = exception;
}
return toRethrow;
}
protected FacesException wrap(Throwable exception)
{
if (exception instanceof FacesException)
{
return (FacesException) exception;
}
return new FacesException(exception);
}
protected boolean shouldSkip(Throwable exception)
{
return exception instanceof AbortProcessingException;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy