JsfExceptionHandler.java
// license-header java merge-point
// Generated by andromda-jsf cartridge (exception\JsfExceptionHandler.java.vsl) DO NOT EDIT!
package org.andromda.samples.animalquiz;
import java.sql.SQLException;
import java.util.Collection;
import java.util.Iterator;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.faces.FacesException;
import javax.faces.application.FacesMessage;
import javax.faces.application.NavigationHandler;
import javax.faces.application.ViewExpiredException;
import javax.faces.component.UINamingContainer;
import javax.faces.context.ExceptionHandler;
import javax.faces.context.ExceptionHandlerWrapper;
import javax.faces.context.FacesContext;
import javax.faces.event.ExceptionQueuedEvent;
import javax.faces.event.ExceptionQueuedEventContext;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.exception.ExceptionUtils;
class JsfExceptionHandler
extends ExceptionHandlerWrapper
{
/**
* Parent ExceptionHandler
*/
private ExceptionHandler parent;
/**
* Constructor
*
* @param parent the parent ExceptionHandler
*/
public JsfExceptionHandler(ExceptionHandler parent)
{
this.parent = parent;
}
@Override
public ExceptionHandler getWrapped()
{
return this.parent;
}
/**
* Append a message to the set of messages associated with the specified
* client identifier, if clientId is not null. If clientId is null, this
* message is assumed to not be associated with any specific component instance
*
* @param clientId the client identifier with which this message is associated (if any)
* @param message the message to be appended
* @param severity the severity of the message
*/
private void addFacesMessage(final String clientId,
final String message,
final FacesMessage.Severity severity)
{
FacesContext.getCurrentInstance().addMessage(clientId,
new FacesMessage(severity,message,null));
}
/**
* Append a message to the current instance of FacesContext
*
* @param message the message to be appended
* @param severity the severity of the message
*/
private void addFacesMessage(final String message, final FacesMessage.Severity severity)
{
addFacesMessage(null,message,severity);
}
/**
* Append an error message to the set of messages associated with the
* specified client identifier, if clientId is not null. If clientId is
* null, this error message is assumed to not be associated with any
* specific component instance
*
* @param clientId the client identifier with which this message is associated (if any)
* @param message the message to be appended
*/
private void addErrorMessage(String clientId, String message)
{
addFacesMessage(clientId, message, FacesMessage.SEVERITY_ERROR);
}
/**
* Append an error message to current instance of faces context
*
* @param message the message to be appended
*/
private void addErrorMessage(String message)
{
addErrorMessage(null,message);
}
/**
* Show validation messages of a given severity
*
* @param validationMessages Collection of ValidationExceptionInfo
* @param severity the severity of the validation messages
* @return true if some clientId has any attached message
*/
private boolean showValidationMessages(final Collection<ValidationException.ValidationExceptionInfo> validationMessages,
final FacesMessage.Severity severity)
{
boolean existsFieldMessage=false;
for(ValidationException.ValidationExceptionInfo validationMessage: validationMessages){
String fieldName=validationMessage.getFieldName();
if(fieldName == null){
addFacesMessage(Messages.get(validationMessage.getMessage(),validationMessage.getArgs()),severity);
}
else
{
final FacesContext facesContext = FacesContext.getCurrentInstance();
final char namingSeparator=UINamingContainer.getSeparatorChar(facesContext);
if(fieldName.indexOf(namingSeparator) > -1)
{
//is clientId
addFacesMessage(fieldName,Messages.get(validationMessage.getMessage(),validationMessage.getArgs()),severity);
existsFieldMessage=true;
}
else
{
//changing from complex.field to complexField
final String[] nameParts=StringUtils.split(fieldName,'.');
for(int c=1; c<nameParts.length; c++)
{
nameParts[c]=StringUtils.capitalize(nameParts[c]);
}
fieldName=StringUtils.join(nameParts);
//creates the clientId using the last posted form
final String clientId=lastPostedForm()+namingSeparator+fieldName;
if(facesContext.getViewRoot().findComponent(clientId) == null)
{
//didn't find the component, try with fieldName as clientId
if(facesContext.getViewRoot().findComponent(fieldName) == null)
{
//didn't find the component, put it as a general message
addFacesMessage(Messages.get(validationMessage.getMessage(),validationMessage.getArgs()),severity);
}
else
{
addFacesMessage(fieldName,Messages.get(validationMessage.getMessage(),validationMessage.getArgs()),severity);
existsFieldMessage=true;
}
}
else
{
addFacesMessage(clientId,Messages.get(validationMessage.getMessage(),validationMessage.getArgs()),severity);
existsFieldMessage=true;
}
}
}
}
return existsFieldMessage;
}
private static final Pattern compiledPattern = Pattern.compile("(.*)(\\{\\s*([\\w|\\.+]*)\\s*\\})(.*)");
/**
* The property on the exception which could possibly contain any
* arguments on the matched exception.
*/
private static final String MESSAGE_ARGUMENTS = "messageArguments";
/**
* Attempts to retrieve any arguments from the exception from a property
* named "messageArguments" on the exception.
*
* @param throwable the Exception containing the message to retrieve
* @return the retrieved message arguments (if any) from the exception.
*/
private Object[] getMessageArguments(final Throwable cause)
{
Object[] arguments = null;
if (cause != null && cause.getMessage() != null)
{
if (PropertyUtils.isReadable(cause, MESSAGE_ARGUMENTS))
{
try {
arguments = (Object[])PropertyUtils.getProperty(cause, MESSAGE_ARGUMENTS);
} catch (Exception e) {
//just ignore
}
}
}
return arguments;
}
/**
* Handles Exceptions by retrieving the message and attempting to extract
* the specified pattern defined within this class. If a string can not be
* found matching the pattern, the exception is re-thrown
*
* @param throwable the Exception containing the message to retrieve
* @return the retrieved string matching the pattern.
*/
private boolean handleException(final Throwable cause)
{
String matched = null;
if (cause != null && cause.getMessage() != null)
{
final Matcher matcher = compiledPattern.matcher(cause.getMessage().replaceAll("[\\s]+", " "));
try
{
if (matcher.matches())
{
matched = matcher.group(3);
}
}
catch (IllegalStateException ex)
{
return false;
}
if (matched == null)
{
return false;
}
else
{
FacesContext.getCurrentInstance().addMessage(null,
new FacesMessage(javax.faces.application.FacesMessage.SEVERITY_ERROR,
Messages.get(matched, getMessageArguments(cause)),null));
return true;
}
}
else
{
return false;
}
}
/**
* Attempts to retrieve the last posted form
*
* @return the last posted form
*/
private String lastPostedForm()
{
final Object value=FacesContext.getCurrentInstance().getExternalContext().getRequestMap().get(ControllerBase.LAST_POSTED_FORM_CLIENT_ID);
return value==null?StringUtils.EMPTY:value.toString();
}
@Override
public void handle() throws FacesException
{
boolean existsMessage=false;
boolean existsFieldMessage=false;
for (Iterator<ExceptionQueuedEvent> i = getUnhandledExceptionQueuedEvents().iterator(); i.hasNext();)
{
final ExceptionQueuedEvent event = i.next();
final ExceptionQueuedEventContext context = (ExceptionQueuedEventContext) event.getSource();
final Throwable t = context.getException();
if (t instanceof ViewExpiredException)
{
final FacesContext fc = FacesContext.getCurrentInstance();
final NavigationHandler nav = fc.getApplication().getNavigationHandler();
try {
nav.handleNavigation(fc, null, "/login.jsf?faces-redirect=true");
fc.renderResponse();
} finally {
i.remove();
}
}
else
{
final Throwable cause = ExceptionUtils.getRootCause(t);
if(cause instanceof ValidationException)
{
final ValidationException vd = (ValidationException)cause;
existsFieldMessage=
showValidationMessages(vd.getErrors(),FacesMessage.SEVERITY_ERROR) ||
showValidationMessages(vd.getWarnings(),FacesMessage.SEVERITY_WARN);
i.remove();
existsMessage=true;
}
else if(handleException(cause))
{
i.remove();
existsMessage=true;
}
else
{
Throwable exception = t;
while(exception != null && !(exception instanceof SQLException))//DB exception ?
{
exception = exception.getCause();
}
String message;
if(exception instanceof SQLException)
{
message = Messages.get("attention", new String[]{exception.getMessage()});
}
else
{
final String excMessage = t.getMessage()==null?t.toString():t.getMessage();
message = Messages.get("unexpected.error", new String[]{excMessage});
Logger.getAnonymousLogger().severe(excMessage);
}
JsfUtils.addErrorMessage(message);
i.remove();
existsMessage=true;
}
}
}
if(existsMessage)
{
FacesContext.getCurrentInstance().getExternalContext().getRequestMap().put("jsfMessagesTitle", Messages.get("errors.header"));
if(existsFieldMessage)
{
addErrorMessage(Messages.get("there.are.field.validation.errors"));
}
}
// At this point, the queue will not contain known exception.
// Therefore, let the parent handle them.
getWrapped().handle();
}
}