All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.myfaces.shared_tomahawk.context.AjaxExceptionHandlerImpl Maven / Gradle / Ivy

Go to download

JSF components and utilities that can be used with any JSF implementation. This library is based on the JSF1.1 version of Tomahawk, but with minor source code and build changes to take advantage of JSF2.1 features. A JSF2.1 implementation is required to use this version of the Tomahawk library.

The newest version!
/*
 * 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 org.apache.myfaces.shared_tomahawk.context;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
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.context.ExceptionHandler;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.context.PartialResponseWriter;
import javax.faces.context.PartialViewContext;
import javax.faces.event.AbortProcessingException;
import javax.faces.event.ExceptionQueuedEvent;
import javax.faces.event.ExceptionQueuedEventContext;
import javax.faces.event.SystemEvent;

/**
 * 
 * Specialized Ajax Handler, according to JSF 2.0 rev A section 13.3.7.
 * 
 * @author Leonardo Uribe
 *
 */
public class AjaxExceptionHandlerImpl extends ExceptionHandler
{
    //The spec says this related to exception handling in ajax requests:
    //
    //"... JavaServer Faces Ajax frameworks must ensure exception information 
    // is written to the response in the format: 
    //
    //
    //  
    //    ...
    //    ...
    //  
    //
    //
    //Implementations must ensure that an ExceptionHandler suitable for writing 
    //exceptions to the partial response is installed if the current request 
    //required an Ajax response (PartialViewContext.isAjaxRequest() returns true)
    //
    //Implementations may choose to include a specialized ExceptionHandler for 
    //Ajax that extends from javax.faces.context.ExceptionHandlerWrapper, and 
    //have the javax.faces.context.ExceptionHandlerFactory implementation 
    //install it if the environment requires it. ..."
    
    private static final Logger log = Logger.getLogger(AjaxExceptionHandlerImpl.class.getName());
    
    private Queue handled;
    private Queue unhandled;
    private ExceptionQueuedEvent handledAndThrown;
    
    public AjaxExceptionHandlerImpl()
    {
    }
    
    /**
     * {@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}
     */
    @Override
    public void handle() throws FacesException
    {
        if (unhandled != null && !unhandled.isEmpty())
        {
            if (handled == null)
            {
                handled = new LinkedList();
            }
            
            List throwableList = new ArrayList();
            FacesContext facesContext = 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();

                    if (facesContext == null)
                    {
                        facesContext = event.getContext().getContext();
                    }
                    
                    // and call getException() on the returned result
                    Throwable exception = context.getException();
                    
                    // Upon encountering the first such Exception that is not an instance of
                    // javax.faces.event.AbortProcessingException
                    if (!shouldSkip(exception))
                    {
                        // set handledAndThrown so that getHandledExceptionQueuedEvent() returns this event
                        handledAndThrown = event;
                        
                        Throwable rootCause = getRootCause(exception);
                        
                        throwableList.add(rootCause == null ? exception : rootCause);
                        
                        //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);
                    }
                }
                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());

            if (!throwableList.isEmpty())
            {
                PartialResponseWriter partialWriter = null;
                boolean responseComplete = false;

                //Retrieve the partial writer used to render the exception
                if (facesContext == null)
                {
                    facesContext = FacesContext.getCurrentInstance();
                }
                
                facesContext = (facesContext == null) ? FacesContext.getCurrentInstance() : facesContext;
                ExternalContext externalContext = facesContext.getExternalContext();
                
                //Clean up the response if by some reason something has been written before.
                if (!facesContext.getExternalContext().isResponseCommitted())
                {
                    facesContext.getExternalContext().responseReset();
                }
                
                PartialViewContext partialViewContext = facesContext.getPartialViewContext();
                partialWriter = partialViewContext.getPartialResponseWriter();

                // ajax request --> xml error page 
                externalContext.setResponseContentType("text/xml");
                externalContext.setResponseCharacterEncoding("UTF-8");
                externalContext.addResponseHeader("Cache-control", "no-cache");
                
                try
                {
                    partialWriter.startDocument();
    
                    for (Throwable t : throwableList)
                    {
                        renderAjaxError(partialWriter, t);
                    }
                    
                    responseComplete = true;
                }
                catch (IOException e)
                {
                    if (log.isLoggable(Level.SEVERE))
                    {
                        log.log(Level.SEVERE, "Cannot render exception on ajax request", e);
                    }
                }
                finally
                {
                    if (responseComplete)
                    {
                        try
                        {
                            partialWriter.endDocument();
                            facesContext.responseComplete();
                        }
                        catch (IOException e1)
                        {
                            if (log.isLoggable(Level.SEVERE))
                            {
                                log.log(Level.SEVERE, "Cannot render exception on ajax request", e1);
                            }
                        }
                    }
                }
            }
        }
    }
    
    private void renderAjaxError(PartialResponseWriter partialWriter, Throwable ex) throws IOException
    {
        partialWriter.startError(ex.getClass().getName());
        if (ex.getCause() != null)
        {
            partialWriter.write(ex.getCause().toString());
        }
        else if (ex.getMessage() != null)
        {
            partialWriter.write(ex.getMessage());
        }
        partialWriter.endError();
    }

    /**
     * {@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 - 2024 Weber Informatics LLC | Privacy Policy