You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by lu...@apache.org on 2009/12/28 22:57:43 UTC

svn commit: r894255 [1/2] - in /myfaces/core/trunk: api/src/main/java/javax/faces/component/ api/src/main/java/javax/faces/webapp/ impl/src/main/java/org/apache/myfaces/application/ impl/src/main/java/org/apache/myfaces/lifecycle/ impl/src/main/java/or...

Author: lu4242
Date: Mon Dec 28 21:57:35 2009
New Revision: 894255

URL: http://svn.apache.org/viewvc?rev=894255&view=rev
Log:
MYFACES-2454 Adapt default error page generation to new spec (Thanks to Jakob Korherr for this patch)

Added:
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/ErrorPageWriter.java
    myfaces/core/trunk/impl/src/main/resources/META-INF/rsc/
    myfaces/core/trunk/impl/src/main/resources/META-INF/rsc/myfaces-dev-error-include.xhtml
Removed:
    myfaces/core/trunk/api/src/main/java/javax/faces/webapp/_ErrorPageWriter.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/util/DevTools.java
Modified:
    myfaces/core/trunk/api/src/main/java/javax/faces/component/UIInput.java
    myfaces/core/trunk/api/src/main/java/javax/faces/webapp/FacesServlet.java
    myfaces/core/trunk/api/src/main/java/javax/faces/webapp/PreJsf2ExceptionHandlerFactory.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/ResourceHandlerImpl.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/lifecycle/LifecycleImpl.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/lifecycle/RestoreViewExecutor.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/FaceletViewDeclarationLanguage.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/FaceletViewHandler.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/ui/IncludeHandler.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/ui/UIDebug.java

Modified: myfaces/core/trunk/api/src/main/java/javax/faces/component/UIInput.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/api/src/main/java/javax/faces/component/UIInput.java?rev=894255&r1=894254&r2=894255&view=diff
==============================================================================
--- myfaces/core/trunk/api/src/main/java/javax/faces/component/UIInput.java (original)
+++ myfaces/core/trunk/api/src/main/java/javax/faces/component/UIInput.java Mon Dec 28 21:57:35 2009
@@ -57,7 +57,6 @@
     public static final String CONVERSION_MESSAGE_ID = "javax.faces.component.UIInput.CONVERSION";
     public static final String REQUIRED_MESSAGE_ID = "javax.faces.component.UIInput.REQUIRED";
     public static final String UPDATE_MESSAGE_ID = "javax.faces.component.UIInput.UPDATE";
-    private static final String ERROR_HANDLING_EXCEPTION_LIST = "org.apache.myfaces.errorHandling.exceptionList";
 
     /** -=Leonardo Uribe =- According to http://wiki.java.net/bin/view/Projects/Jsf2MR1ChangeLog 
       * this constant will be made public on 2.1. For now, since this param is handled in
@@ -300,38 +299,31 @@
         }
         catch (Exception e)
         {
+            // Enqueue an error message
             context.getExternalContext().log(e.getMessage(), e);
-            _MessageUtils.addErrorMessage(context, this, UPDATE_MESSAGE_ID, new Object[] { _MessageUtils.getLabel(
-                context, this) });
+            
+            // Create a FacesMessage with the id UPDATE_MESSAGE_ID
+            FacesMessage facesMessage = _MessageUtils.getMessage(context,
+                    context.getViewRoot().getLocale(), FacesMessage.SEVERITY_ERROR, UPDATE_MESSAGE_ID,
+                    new Object[] { _MessageUtils.getLabel(context, this) });
+            
+            // create an UpdateModelException and enqueue it since 
+            // we are not allowed to throw it directly here
+            // spec javadoc: The exception must not be re-thrown. This enables tree traversal to 
+            // continue for this lifecycle phase, as in all the other lifecycle phases.
+            UpdateModelException updateModelException = new UpdateModelException(facesMessage, e);
+            ExceptionQueuedEventContext exceptionQueuedContext 
+                    = new ExceptionQueuedEventContext (context, updateModelException, this, PhaseId.UPDATE_MODEL_VALUES);
+            
+            // spec javadoc says we should call context.getExceptionHandler().processEvent(exceptionQueuedContext),
+            // which is not just syntactically wrong, but also stupid!!
+            context.getApplication().publishEvent(context, ExceptionQueuedEvent.class, exceptionQueuedContext);
+            
+            // Set the valid property of this UIInput to false
             setValid(false);
-
-            /*
-             * we are not allowed to throw exceptions here - we still need the full stack-trace later on to process it
-             * later in our error-handler
-             */
-            queueExceptionInRequest(context, expression, e);
         }
     }
 
-    /**
-     * For development and production, we want to offer a single point to which error-handlers can attach. So we queue
-     * up all ocurring exceptions and later pass them to the configured error-handler.
-     */
-    @SuppressWarnings("unchecked")
-    private void queueExceptionInRequest(FacesContext context, ValueExpression expression, Exception e)
-    {
-        Map<String, Object> requestScope = context.getExternalContext().getRequestMap();
-        List<FacesException> li = (List<FacesException>) requestScope.get(ERROR_HANDLING_EXCEPTION_LIST);
-        if (null == li)
-        {
-            li = new ArrayList<FacesException>();
-            context.getExternalContext().getRequestMap().put(ERROR_HANDLING_EXCEPTION_LIST, li);
-        }
-
-        li.add(new FacesException("Exception while setting value for expression : " + expression.getExpressionString()
-                + " of component with path : " + _ComponentUtils.getPathToComponent(this), e));
-    }
-
     protected void validateValue(FacesContext context, Object convertedValue)
     {
         if (!isValid())

Modified: myfaces/core/trunk/api/src/main/java/javax/faces/webapp/FacesServlet.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/api/src/main/java/javax/faces/webapp/FacesServlet.java?rev=894255&r1=894254&r2=894255&view=diff
==============================================================================
--- myfaces/core/trunk/api/src/main/java/javax/faces/webapp/FacesServlet.java (original)
+++ myfaces/core/trunk/api/src/main/java/javax/faces/webapp/FacesServlet.java Mon Dec 28 21:57:35 2009
@@ -19,10 +19,6 @@
 package javax.faces.webapp;
 
 import java.io.IOException;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.util.List;
-import java.util.Map;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
@@ -69,28 +65,6 @@
 
     private static final String SERVLET_INFO = "FacesServlet of the MyFaces API implementation";
     
-    /**
-     * Indicate if myfaces is responsible to handle errors. 
-     * See http://wiki.apache.org/myfaces/Handling_Server_Errors for details. 
-     */
-    @JSFWebConfigParam(defaultValue="true",expectedValues="true,false", since="1.2.4")
-    private static final String ERROR_HANDLING_PARAMETER = "org.apache.myfaces.ERROR_HANDLING";
-    
-    /**
-     * If you want to choose a different class for handling the exception.
-     * <p> 
-     * The error-handler needs to include the following methods:
-     * </p>
-     * <ul>
-     * <li>handleException(FacesContext fc, Exception ex)</li>
-     * <li>handleExceptionList(FacesContext facesContext, List exceptionList)</li>
-     * <li>handleThrowable(FacesContext facesContext, Throwable ex)</li>
-     * </ul>
-     */
-    @JSFWebConfigParam(since="1.2.4")
-    private static final String ERROR_HANDLER_PARAMETER = "org.apache.myfaces.ERROR_HANDLER";
-    private static final String ERROR_HANDLING_EXCEPTION_LIST = "org.apache.myfaces.errorHandling.exceptionList";
-
     private ServletConfig _servletConfig;
     private FacesContextFactory _facesContextFactory;
     private Lifecycle _lifecycle;
@@ -211,251 +185,10 @@
             else
             {
                 // If this returns false, handle as follow
-                _handleStandardRequest(facesContext);
-            }
-        }
-        catch (Exception e)
-        {
-            handleLifecycleException(facesContext, e);
-        }
-        catch (Throwable e)
-        {
-            handleLifecycleThrowable(facesContext, e);
-        }
-        finally
-        {
-            // In a finally block, FacesContext.release() must be called. 
-            facesContext.release();
-        }
-        if (log.isLoggable(Level.FINEST))
-            log.finest("service end");
-    }
-
-    /**
-     * This method makes sure we see an exception page also if an exception has been thrown in UIInput.updateModel(); In
-     * this method, according to the spec, we may not rethrow the exception, so we add it to a list and process it here.
-     * 
-     * Attention: if you use redirects, the exceptions will get lost - exactly like in the case of FacesMessages. If you
-     * want them to be taken over to the next request, you should try the redirect-tracker of MyFaces.
-     * 
-     * @param facesContext
-     * @throws FacesException
-     */
-    @SuppressWarnings("unchecked")
-    private boolean handleQueuedExceptions(FacesContext facesContext) throws IOException, ServletException
-    {
-        Map<String, Object> requestScope = facesContext.getExternalContext().getRequestMap();
-        List<Exception> li = (List<Exception>)requestScope.get(ERROR_HANDLING_EXCEPTION_LIST);
-
-        if (li != null && li.size() >= 1)
-        {
-            // todo: for now, we only handle the first exception out of the list - we just rethrow this
-            // first exception.
-            // in the end, we should enable the error handler to show all the exceptions at once
-            boolean errorHandling =
-                    getBooleanValue(facesContext.getExternalContext().getInitParameter(ERROR_HANDLING_PARAMETER), true);
-
-            if (errorHandling)
-            {
-                String errorHandlerClass = facesContext.getExternalContext().getInitParameter(ERROR_HANDLER_PARAMETER);
-                if (errorHandlerClass != null)
-                {
-                    try
-                    {
-                        Class<?> clazz = Class.forName(errorHandlerClass);
-
-                        Object errorHandler = clazz.newInstance();
-
-                        Method m = clazz.getMethod("handleExceptionList", new Class[]{FacesContext.class,List.class});
-                        m.invoke(errorHandler, new Object[]{facesContext, li});
-                    }
-                    catch (ClassNotFoundException ex)
-                    {
-                        throw new ServletException("Error-Handler : " + errorHandlerClass
-                                + " was not found. Fix your web.xml-parameter : " + ERROR_HANDLER_PARAMETER, ex);
-                    }
-                    catch (IllegalAccessException ex)
-                    {
-                        throw new ServletException("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 ServletException("Error-Handler : " + errorHandlerClass
-                                + " could not be instantiated. Error-Handler is specified in web.xml-parameter : "
-                                + ERROR_HANDLER_PARAMETER, ex);
-                    }
-                    catch (NoSuchMethodException ex)
-                    {
-                        // Handle in the old way, since no custom method handleExceptionList found,
-                        // throwing the first FacesException on the list.
-                        throw (FacesException)li.get(0);
-                    }
-                    catch (InvocationTargetException ex)
-                    {
-                        throw new ServletException("Excecution of method handleException in Error-Handler : "
-                                + errorHandlerClass
-                                + " threw an exception. Error-Handler is specified in web.xml-parameter : "
-                                + ERROR_HANDLER_PARAMETER, ex);
-                    }
-                }
-                else
-                {
-                    _ErrorPageWriter.handleExceptionList(facesContext, li);
-                }
-            }
-            else
-            {
-                _ErrorPageWriter.throwException(li.get(0));
-            }
-            return true;
-        }
-        return false;
-    }
-
-    private void handleLifecycleException(FacesContext facesContext, Exception e) throws IOException, ServletException
-    {
-
-        boolean errorHandling =
-                getBooleanValue(facesContext.getExternalContext().getInitParameter(ERROR_HANDLING_PARAMETER), true);
-
-        if (errorHandling)
-        {
-            String errorHandlerClass = facesContext.getExternalContext().getInitParameter(ERROR_HANDLER_PARAMETER);
-            if (errorHandlerClass != null)
-            {
-                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[] { facesContext, e });
-                }
-                catch (ClassNotFoundException ex)
-                {
-                    throw new ServletException("Error-Handler : " + errorHandlerClass
-                            + " was not found. Fix your web.xml-parameter : " + ERROR_HANDLER_PARAMETER, ex);
-                }
-                catch (IllegalAccessException ex)
-                {
-                    throw new ServletException("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 ServletException("Error-Handler : " + errorHandlerClass
-                            + " could not be instantiated. Error-Handler is specified in web.xml-parameter : "
-                            + ERROR_HANDLER_PARAMETER, ex);
-                }
-                catch (NoSuchMethodException ex)
-                {
-                    log
-                       .log(Level.SEVERE,
-                           "Error-Handler : "
-                                   + errorHandlerClass
-                                   + " did 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);
-                    // Try to look if it is implemented more general method handleThrowable
-                    handleLifecycleThrowable(facesContext, e);
-                }
-                catch (InvocationTargetException ex)
-                {
-                    throw new ServletException("Excecution of method handleException in Error-Handler : "
-                            + errorHandlerClass
-                            + " caused an exception. Error-Handler is specified in web.xml-parameter : "
-                            + ERROR_HANDLER_PARAMETER, ex);
-                }
-            }
-            else
-            {
-                _ErrorPageWriter.handleException(facesContext, e);
-            }
-        }
-        else
-        {
-            _ErrorPageWriter.throwException(e);
-        }
-    }
-
-    private void handleLifecycleThrowable(FacesContext facesContext, Throwable e) throws IOException, ServletException
-    {
-
-        boolean errorHandling =
-                getBooleanValue(facesContext.getExternalContext().getInitParameter(ERROR_HANDLING_PARAMETER), true);
-
-        if (errorHandling)
-        {
-            String errorHandlerClass = facesContext.getExternalContext().getInitParameter(ERROR_HANDLER_PARAMETER);
-            if (errorHandlerClass != null)
-            {
-                try
-                {
-                    Class<?> clazz = Class.forName(errorHandlerClass);
-
-                    Object errorHandler = clazz.newInstance();
-
-                    Method m = clazz.getMethod("handleThrowable", new Class[] { FacesContext.class, Throwable.class });
-                    m.invoke(errorHandler, new Object[] { facesContext, e });
-                }
-                catch (ClassNotFoundException ex)
-                {
-                    throw new ServletException("Error-Handler : " + errorHandlerClass
-                            + " was not found. Fix your web.xml-parameter : " + ERROR_HANDLER_PARAMETER, ex);
-                }
-                catch (IllegalAccessException ex)
-                {
-                    throw new ServletException("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 ServletException("Error-Handler : " + errorHandlerClass
-                            + " could not be instantiated. Error-Handler is specified in web.xml-parameter : "
-                            + ERROR_HANDLER_PARAMETER, ex);
-                }
-                catch (NoSuchMethodException ex)
-                {
-                    throw new ServletException(
-                        "Error-Handler : "
-                                + errorHandlerClass
-                                + " did 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 ServletException("Excecution of method handleException in Error-Handler : "
-                            + errorHandlerClass
-                            + " threw an exception. Error-Handler is specified in web.xml-parameter : "
-                            + ERROR_HANDLER_PARAMETER, ex);
-                }
-            }
-            else
-            {
-                _ErrorPageWriter.handleThrowable(facesContext, e);
-            }
-        }
-        else
-        {
-            _ErrorPageWriter.throwException(e);
-        }
-    }
-    
-    private void _handleStandardRequest(FacesContext context) throws IOException, ServletException
-    {
-        try
-        {
-            // call Lifecycle.execute(javax.faces.context.FacesContext)
-            _lifecycle.execute(context);
-
-            if (!handleQueuedExceptions(context))
-            {
+                // call Lifecycle.execute(javax.faces.context.FacesContext)
+                _lifecycle.execute(facesContext);
                 // followed by Lifecycle.render(javax.faces.context.FacesContext).
-                _lifecycle.render(context);
+                _lifecycle.render(facesContext);
             }
         }
         catch (FacesException e)
@@ -488,16 +221,13 @@
                 throw new ServletException(cause.getLocalizedMessage(), cause);
             }
         }
-    }
-
-    private static boolean getBooleanValue(String initParameter, boolean defaultVal)
-    {
-
-        if (initParameter == null || initParameter.trim().length() == 0)
-            return defaultVal;
-
-        return (initParameter.equalsIgnoreCase("on") || initParameter.equals("1") || initParameter
-                                                                                                  .equalsIgnoreCase("true"));
+        finally
+        {
+            // In a finally block, FacesContext.release() must be called. 
+            facesContext.release();
+        }
+        if (log.isLoggable(Level.FINEST))
+            log.finest("service end");
     }
 
     private FacesContext prepareFacesContext(ServletRequest request, ServletResponse response)

Modified: myfaces/core/trunk/api/src/main/java/javax/faces/webapp/PreJsf2ExceptionHandlerFactory.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/api/src/main/java/javax/faces/webapp/PreJsf2ExceptionHandlerFactory.java?rev=894255&r1=894254&r2=894255&view=diff
==============================================================================
--- myfaces/core/trunk/api/src/main/java/javax/faces/webapp/PreJsf2ExceptionHandlerFactory.java (original)
+++ myfaces/core/trunk/api/src/main/java/javax/faces/webapp/PreJsf2ExceptionHandlerFactory.java Mon Dec 28 21:57:35 2009
@@ -18,6 +18,8 @@
  */
 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;
@@ -31,13 +33,17 @@
 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: slessard $)
+ * @author Jakob Korherr
  * @version $Revision: 696523 $ $Date: 2009-03-14 20:06:50 -0400 (mer., 17 sept. 2008) $
  *
  * @since 2.0
@@ -82,6 +88,19 @@
         
         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:
+         * <ul>
+         * <li>handleException(FacesContext fc, Exception ex)</li>
+         * </ul>
+         * Furthermore, the init parameter only works when using the PreJsf2ExceptionHandlerFactory.
+         */
+        @JSFWebConfigParam(since="1.2.4")
+        private static final String ERROR_HANDLER_PARAMETER = "org.apache.myfaces.ERROR_HANDLER";
+        
         private Queue<ExceptionQueuedEvent> handled;
         private Queue<ExceptionQueuedEvent> unhandled;
         private ExceptionQueuedEvent handledAndThrown;
@@ -145,11 +164,12 @@
         /**
          * {@inheritDoc}
          * 
-         * Differs from ExceptionHandlerImpl.handle() in two points:
+         * 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
@@ -161,6 +181,11 @@
                     handled = new LinkedList<ExceptionQueuedEvent>();
                 }
                 
+                // 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
@@ -176,48 +201,97 @@
                         
                         // and call getException() on the returned result
                         Throwable exception = context.getException();
-
-                        // UpdateModelException needs special treatment here
-                        if (exception instanceof UpdateModelException)
+                        
+                        if (errorHandlerClass != null)
                         {
-                            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)
+                            // myfaces-1.2's error handler
+                            try
                             {
-                                clientId = component.getClientId(context.getContext());
+                                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);
                             }
-                            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());
+                            // spec described behaviour of PreJsf2ExceptionHandler
                             
-                            log.log(Level.SEVERE, exception.getMessage(), exception);
+                            // 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)

Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/ResourceHandlerImpl.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/ResourceHandlerImpl.java?rev=894255&r1=894254&r2=894255&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/ResourceHandlerImpl.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/ResourceHandlerImpl.java Mon Dec 28 21:57:35 2009
@@ -36,6 +36,7 @@
 import javax.servlet.ServletResponseWrapper;
 import javax.servlet.http.HttpServletResponse;
 
+import org.apache.myfaces.renderkit.ErrorPageWriter;
 import org.apache.myfaces.resource.ResourceImpl;
 import org.apache.myfaces.resource.ResourceLoader;
 import org.apache.myfaces.resource.ResourceMeta;
@@ -238,134 +239,144 @@
     @Override
     public void handleResourceRequest(FacesContext facesContext) throws IOException
     {
-        String resourceBasePath = getResourceHandlerSupport()
-                .calculateResourceBasePath(facesContext);
-
-        if (resourceBasePath == null)
-        {
-            // No base name could be calculated, so no further
-            //advance could be done here. HttpServletResponse.SC_NOT_FOUND
-            //cannot be returned since we cannot extract the 
-            //resource base name
-            return;
-        }
-
-        //We neet to get an instance of HttpServletResponse, but sometimes
-        //the response object is wrapped by several instances of 
-        //ServletResponseWrapper (like ResponseSwitch).
-        //Since we are handling a resource, we can expect to get an 
-        //HttpServletResponse.
-        
-        Object response = facesContext.getExternalContext().getResponse();
-        
-        //It is safe to cast it to ServletResponse
-        ServletResponse servletResponse = (ServletResponse) response;
-        
-        HttpServletResponse httpServletResponse = null;
-        if (response instanceof HttpServletResponse)
-        {
-            httpServletResponse = (HttpServletResponse) response;
-        }
-        else if (response instanceof ServletResponseWrapper)
+        try
         {
-            //iterate until we find a instance that we can cast 
-            while (!(response instanceof HttpServletResponse))
+            String resourceBasePath = getResourceHandlerSupport()
+                    .calculateResourceBasePath(facesContext);
+    
+            if (resourceBasePath == null)
             {
-                //assume ServletResponseWrapper as wrapper
-                response = ((ServletResponseWrapper)response).getResponse();
+                // No base name could be calculated, so no further
+                //advance could be done here. HttpServletResponse.SC_NOT_FOUND
+                //cannot be returned since we cannot extract the 
+                //resource base name
+                return;
             }
-            //Case where it is an instance of ResponseSwitch
-            //in this case just return the inner response
-            httpServletResponse = (HttpServletResponse) response;
-        }
-
-        if (isResourceIdentifierExcluded(facesContext, resourceBasePath))
-        {
-            httpServletResponse.setStatus(HttpServletResponse.SC_NOT_FOUND);
-            return;
-        }
-
-        String resourceName = null;
-        if (resourceBasePath.startsWith(ResourceHandler.RESOURCE_IDENTIFIER))
-        {
-            resourceName = resourceBasePath
-                    .substring(ResourceHandler.RESOURCE_IDENTIFIER.length() + 1);
-        }
-        else
-        {
-            //Does not have the conditions for be a resource call
-            httpServletResponse.setStatus(HttpServletResponse.SC_NOT_FOUND);
-            return;
-        }
-
-        String libraryName = facesContext.getExternalContext()
-                .getRequestParameterMap().get("ln");
-
-        Resource resource = null;
-        if (libraryName != null)
-        {
-            //log.info("libraryName=" + libraryName);
-            resource = createResource(resourceName, libraryName);
-        }
-        else
-        {
-            resource = createResource(resourceName);
-        }
-
-        if (resource == null)
-        {
-            httpServletResponse.setStatus(HttpServletResponse.SC_NOT_FOUND);
-            return;
-        }
-
-        if (!resource.userAgentNeedsUpdate(facesContext))
-        {
-            httpServletResponse.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
-            return;
-        }
-
-        servletResponse.setContentType(resource.getContentType());
-
-        Map<String, String> headers = resource.getResponseHeaders();
-
-        for (Map.Entry<String, String> entry : headers.entrySet())
-        {
-            httpServletResponse.setHeader(entry.getKey(), entry.getValue());
-        }
-
-        //serve up the bytes (taken from trinidad ResourceServlet)
-        try
-        {
-            InputStream in = resource.getInputStream();
-            OutputStream out = servletResponse.getOutputStream();
-            byte[] buffer = new byte[_BUFFER_SIZE];
-
-            try
+    
+            //We neet to get an instance of HttpServletResponse, but sometimes
+            //the response object is wrapped by several instances of 
+            //ServletResponseWrapper (like ResponseSwitch).
+            //Since we are handling a resource, we can expect to get an 
+            //HttpServletResponse.
+            
+            Object response = facesContext.getExternalContext().getResponse();
+            
+            //It is safe to cast it to ServletResponse
+            ServletResponse servletResponse = (ServletResponse) response;
+            
+            HttpServletResponse httpServletResponse = null;
+            if (response instanceof HttpServletResponse)
+            {
+                httpServletResponse = (HttpServletResponse) response;
+            }
+            else if (response instanceof ServletResponseWrapper)
+            {
+                //iterate until we find a instance that we can cast 
+                while (!(response instanceof HttpServletResponse))
+                {
+                    //assume ServletResponseWrapper as wrapper
+                    response = ((ServletResponseWrapper)response).getResponse();
+                }
+                //Case where it is an instance of ResponseSwitch
+                //in this case just return the inner response
+                httpServletResponse = (HttpServletResponse) response;
+            }
+    
+            if (isResourceIdentifierExcluded(facesContext, resourceBasePath))
+            {
+                httpServletResponse.setStatus(HttpServletResponse.SC_NOT_FOUND);
+                return;
+            }
+    
+            String resourceName = null;
+            if (resourceBasePath.startsWith(ResourceHandler.RESOURCE_IDENTIFIER))
             {
-                int count = pipeBytes(in, out, buffer);
-                //set the content lenght
-                servletResponse.setContentLength(count);
+                resourceName = resourceBasePath
+                        .substring(ResourceHandler.RESOURCE_IDENTIFIER.length() + 1);
             }
-            finally
+            else
             {
+                //Does not have the conditions for be a resource call
+                httpServletResponse.setStatus(HttpServletResponse.SC_NOT_FOUND);
+                return;
+            }
+    
+            String libraryName = facesContext.getExternalContext()
+                    .getRequestParameterMap().get("ln");
+    
+            Resource resource = null;
+            if (libraryName != null)
+            {
+                //log.info("libraryName=" + libraryName);
+                resource = createResource(resourceName, libraryName);
+            }
+            else
+            {
+                resource = createResource(resourceName);
+            }
+    
+            if (resource == null)
+            {
+                httpServletResponse.setStatus(HttpServletResponse.SC_NOT_FOUND);
+                return;
+            }
+    
+            if (!resource.userAgentNeedsUpdate(facesContext))
+            {
+                httpServletResponse.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
+                return;
+            }
+    
+            servletResponse.setContentType(resource.getContentType());
+    
+            Map<String, String> headers = resource.getResponseHeaders();
+    
+            for (Map.Entry<String, String> entry : headers.entrySet())
+            {
+                httpServletResponse.setHeader(entry.getKey(), entry.getValue());
+            }
+    
+            //serve up the bytes (taken from trinidad ResourceServlet)
+            try
+            {
+                InputStream in = resource.getInputStream();
+                OutputStream out = servletResponse.getOutputStream();
+                byte[] buffer = new byte[_BUFFER_SIZE];
+    
                 try
                 {
-                    in.close();
+                    int count = pipeBytes(in, out, buffer);
+                    //set the content lenght
+                    servletResponse.setContentLength(count);
                 }
                 finally
                 {
-                    out.close();
-                }
-            }
-        }
-        catch (IOException e)
-        {
-            //TODO: Log using a localized message (which one?)
-            if (log.isLoggable(Level.SEVERE))
-                log.severe("Error trying to load resource " + resourceName
-                        + " with library " + libraryName + " :"
-                        + e.getMessage());
-            httpServletResponse.setStatus(HttpServletResponse.SC_NOT_FOUND);
+                    try
+                    {
+                        in.close();
+                    }
+                    finally
+                    {
+                        out.close();
+                    }
+                }
+            }
+            catch (IOException e)
+            {
+                //TODO: Log using a localized message (which one?)
+                if (log.isLoggable(Level.SEVERE))
+                    log.severe("Error trying to load resource " + resourceName
+                            + " with library " + libraryName + " :"
+                            + e.getMessage());
+                httpServletResponse.setStatus(HttpServletResponse.SC_NOT_FOUND);
+            }
+        }
+        catch (Throwable ex)
+        {
+            // handle the Throwable accordingly. Maybe generate an error page.
+            // FIXME we are creating a html error page for a non html request here
+            // shouln't we do something better? -=Jakob Korherr=-
+            ErrorPageWriter.handleThrowable(facesContext, ex);
         }
     }
 

Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/lifecycle/LifecycleImpl.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/lifecycle/LifecycleImpl.java?rev=894255&r1=894254&r2=894255&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/lifecycle/LifecycleImpl.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/lifecycle/LifecycleImpl.java Mon Dec 28 21:57:35 2009
@@ -33,6 +33,7 @@
 import javax.faces.lifecycle.Lifecycle;
 
 import org.apache.myfaces.config.FacesConfigurator;
+import org.apache.myfaces.renderkit.ErrorPageWriter;
 import org.apache.myfaces.shared_impl.util.ClassUtils;
 import org.apache.myfaces.shared_impl.webapp.webxml.WebXml;
 import org.apache.myfaces.util.DebugUtils;
@@ -70,23 +71,31 @@
     @Override
     public void execute(FacesContext facesContext) throws FacesException
     {
-        // refresh all configuration information if according web-xml parameter is set.
-        // TODO: Performance wise, shouldn't the lifecycle be configured with a local boolean attribute
-        // specifying if the system should look for file modification because this code seems like
-        // a developement facility, but at the cost of scalability. I think a context param like
-        // Trinidad is a better idea -= Simon Lessard =-
-        WebXml.update(facesContext.getExternalContext());
-
-        new FacesConfigurator(facesContext.getExternalContext()).update();
-
-        PhaseListenerManager phaseListenerMgr = new PhaseListenerManager(this, facesContext, getPhaseListeners());
-        for (PhaseExecutor executor : lifecycleExecutors)
+        try
         {
-            if (executePhase(facesContext, executor, phaseListenerMgr))
+            // refresh all configuration information if according web-xml parameter is set.
+            // TODO: Performance wise, shouldn't the lifecycle be configured with a local boolean attribute
+            // specifying if the system should look for file modification because this code seems like
+            // a developement facility, but at the cost of scalability. I think a context param like
+            // Trinidad is a better idea -= Simon Lessard =-
+            WebXml.update(facesContext.getExternalContext());
+    
+            new FacesConfigurator(facesContext.getExternalContext()).update();
+    
+            PhaseListenerManager phaseListenerMgr = new PhaseListenerManager(this, facesContext, getPhaseListeners());
+            for (PhaseExecutor executor : lifecycleExecutors)
             {
-                return;
+                if (executePhase(facesContext, executor, phaseListenerMgr))
+                {
+                    return;
+                }
             }
         }
+        catch (Throwable ex)
+        {
+            // handle the Throwable accordingly. Maybe generate an error page.
+            ErrorPageWriter.handleThrowable(facesContext, ex);
+        }
     }
 
     private boolean executePhase(FacesContext context, PhaseExecutor executor, PhaseListenerManager phaseListenerMgr)
@@ -164,55 +173,63 @@
     @Override
     public void render(FacesContext facesContext) throws FacesException
     {
-        // if the response is complete we should not be invoking the phase listeners
-        if (isResponseComplete(facesContext, renderExecutor.getPhase(), true))
-        {
-            return;
-        }
-        if (log.isLoggable(Level.FINEST))
-            log.finest("entering " + renderExecutor.getPhase() + " in " + LifecycleImpl.class.getName());
-
-        PhaseListenerManager phaseListenerMgr = new PhaseListenerManager(this, facesContext, getPhaseListeners());
-        Flash flash = facesContext.getExternalContext().getFlash();
-        
         try
         {
-            facesContext.setCurrentPhaseId(renderExecutor.getPhase());
-            
-            flash.doPrePhaseActions(facesContext);
-            boolean renderResponse = phaseListenerMgr.informPhaseListenersBefore(renderExecutor.getPhase());
-            // also possible that one of the listeners completed the response
+            // if the response is complete we should not be invoking the phase listeners
             if (isResponseComplete(facesContext, renderExecutor.getPhase(), true))
             {
                 return;
             }
-            if(renderResponse || facesContext.getExceptionHandler().getClass().equals(ClassUtils.classForName("javax.faces.webapp.PreJsf2ExceptionHandlerFactory$PreJsf2ExceptionHandlerImpl")))
-                renderExecutor.execute(facesContext);
-        }
-        
-        catch (Throwable e) {
-            // JSF 2.0: publish the executor's exception (if any).
+            if (log.isLoggable(Level.FINEST))
+                log.finest("entering " + renderExecutor.getPhase() + " in " + LifecycleImpl.class.getName());
+    
+            PhaseListenerManager phaseListenerMgr = new PhaseListenerManager(this, facesContext, getPhaseListeners());
+            Flash flash = facesContext.getExternalContext().getFlash();
             
-            publishException (e, renderExecutor.getPhase(), facesContext);
-        }
-        
-        finally
-        {
-            phaseListenerMgr.informPhaseListenersAfter(renderExecutor.getPhase());
-            flash.doPostPhaseActions(facesContext);
-        }
-        
-        facesContext.getExceptionHandler().handle();
-        
-        if (log.isLoggable(Level.FINEST))
-        {
-            // Note: DebugUtils Logger must also be in trace level
-            DebugUtils.traceView("View after rendering");
+            try
+            {
+                facesContext.setCurrentPhaseId(renderExecutor.getPhase());
+                
+                flash.doPrePhaseActions(facesContext);
+                boolean renderResponse = phaseListenerMgr.informPhaseListenersBefore(renderExecutor.getPhase());
+                // also possible that one of the listeners completed the response
+                if (isResponseComplete(facesContext, renderExecutor.getPhase(), true))
+                {
+                    return;
+                }
+                if(renderResponse || facesContext.getExceptionHandler().getClass().equals(ClassUtils.classForName("javax.faces.webapp.PreJsf2ExceptionHandlerFactory$PreJsf2ExceptionHandlerImpl")))
+                    renderExecutor.execute(facesContext);
+            }
+            
+            catch (Throwable e) {
+                // JSF 2.0: publish the executor's exception (if any).
+                
+                publishException (e, renderExecutor.getPhase(), facesContext);
+            }
+            
+            finally
+            {
+                phaseListenerMgr.informPhaseListenersAfter(renderExecutor.getPhase());
+                flash.doPostPhaseActions(facesContext);
+            }
+            
+            facesContext.getExceptionHandler().handle();
+            
+            if (log.isLoggable(Level.FINEST))
+            {
+                // Note: DebugUtils Logger must also be in trace level
+                DebugUtils.traceView("View after rendering");
+            }
+    
+            if (log.isLoggable(Level.FINEST))
+            {
+                log.finest("exiting " + renderExecutor.getPhase() + " in " + LifecycleImpl.class.getName());
+            }
         }
-
-        if (log.isLoggable(Level.FINEST))
+        catch (Throwable ex)
         {
-            log.finest("exiting " + renderExecutor.getPhase() + " in " + LifecycleImpl.class.getName());
+            // handle the Throwable accordingly. Maybe generate an error page.
+            ErrorPageWriter.handleThrowable(facesContext, ex);
         }
     }
 
@@ -296,4 +313,5 @@
         
         facesContext.getApplication().publishEvent (facesContext, ExceptionQueuedEvent.class, context);
     }
+
 }

Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/lifecycle/RestoreViewExecutor.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/lifecycle/RestoreViewExecutor.java?rev=894255&r1=894254&r2=894255&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/lifecycle/RestoreViewExecutor.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/lifecycle/RestoreViewExecutor.java Mon Dec 28 21:57:35 2009
@@ -24,6 +24,7 @@
 
 import javax.faces.FacesException;
 import javax.faces.application.Application;
+import javax.faces.application.ProjectStage;
 import javax.faces.application.ViewExpiredException;
 import javax.faces.application.ViewHandler;
 import javax.faces.component.UIViewParameter;
@@ -34,6 +35,8 @@
 import javax.faces.view.ViewDeclarationLanguage;
 import javax.faces.view.ViewMetadata;
 
+import org.apache.myfaces.renderkit.ErrorPageWriter;
+
 /**
  * Implements the Restore View Phase (JSF Spec 2.2.1)
  * 
@@ -88,8 +91,8 @@
         // servlet container to display an error page.
         // If the request is an error page request, the servlet container
         // is required to set the request parameter "javax.servlet.error.message".
-        boolean errorPageRequest = facesContext.getExternalContext().getRequestMap()
-                                           .get("javax.servlet.error.message") != null;
+        final boolean errorPageRequest = facesContext.getExternalContext().getRequestMap()
+                                                 .get("javax.servlet.error.message") != null;
         
         // Determine if this request is a postback or an initial request.
         // But if it is an error page request, do not treat it as a postback (since 2.0)
@@ -183,6 +186,15 @@
             }
         }
 
+        // add the ErrorPageBean to the view map to fully support 
+        // facelet error pages, if we are in ProjectStage Development
+        // and currently generating an error page
+        if (errorPageRequest && facesContext.isProjectStage(ProjectStage.Development))
+        {
+            facesContext.getViewRoot().getViewMap()
+                    .put(ErrorPageWriter.ERROR_PAGE_BEAN_KEY, new ErrorPageWriter.ErrorPageBean());
+        }
+        
         return false;
     }
     

Added: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/ErrorPageWriter.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/ErrorPageWriter.java?rev=894255&view=auto
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/ErrorPageWriter.java (added)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/ErrorPageWriter.java Mon Dec 28 21:57:35 2009
@@ -0,0 +1,745 @@
+/*
+ * 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.renderkit;
+
+import java.beans.BeanInfo;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintWriter;
+import java.io.Serializable;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.lang.reflect.Method;
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.text.DateFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.SortedMap;
+import java.util.TreeMap;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.el.Expression;
+import javax.el.ValueExpression;
+import javax.faces.FacesException;
+import javax.faces.component.UIComponent;
+import javax.faces.component.UIViewRoot;
+import javax.faces.context.ExternalContext;
+import javax.faces.context.FacesContext;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFWebConfigParam;
+import org.apache.myfaces.shared_impl.webapp.webxml.WebXml;
+
+/**
+ * This class provides utility methods to generate the
+ * MyFaces error and debug pages. 
+ * 
+ * @author Jacob Hookom (ICLA with ASF filed)
+ * @author Jakob Korherr (refactored and moved here from javax.faces.webapp._ErrorPageWriter)
+ */
+public final class ErrorPageWriter
+{
+    
+    /**
+     * This bean aims to generate the error page html for inclusion on a facelet error page via
+     * <ui:include src="javax.faces.error.xhtml" />. When performing this include the facelet
+     * "myfaces-dev-error-include.xhtml" will be included. This facelet references to the ErrorPageBean.
+     * This also works for custom error page templates.
+     * The bean is added to the ViewMap of the UIViewRoot, which is 
+     * displaying the error page, in RestoreViewExecutor.execute().
+     * @author Jakob Korherr
+     */
+    public static class ErrorPageBean implements Serializable
+    {
+        
+        private static final long serialVersionUID = -79513324193326616L;
+
+        public String getErrorPageHtml() throws IOException
+        {
+            FacesContext facesContext = FacesContext.getCurrentInstance();
+            Map<String, Object> requestMap = facesContext.getExternalContext().getRequestMap();
+            
+            Throwable t = (Throwable) requestMap.get(EXCEPTION_KEY);
+            if (t == null)
+            {
+                throw new IllegalStateException("No Exception to handle");
+            }
+            
+            UIViewRoot view = (UIViewRoot) requestMap.get(VIEW_KEY);
+            
+            StringWriter writer = new StringWriter();
+            ErrorPageWriter.debugHtml(writer, facesContext, t, view);
+            String html = writer.toString();
+            
+            // change the HTML in the buffer to be included in an existing html page
+            String body;
+            try
+            {
+                body = html.substring(html.indexOf("<body>") + "<body>".length(), html.indexOf("</body>"));
+            }
+            catch (Exception e)
+            {
+                // no body found - return the entire html
+                return html;
+            }
+            
+            String head;
+            try
+            {
+                head = html.substring(html.indexOf("<head>") + "<head>".length(), html.indexOf("</head>"));
+            }
+            catch (Exception e)
+            {
+                // no head found - return entire body
+                return body;
+            }
+            
+            // extract style and script information from head and add it to body
+            StringBuilder builder = new StringBuilder(body);
+            // extract <style>
+            int startIndex = 0;
+            while (true)
+            {
+                try
+                {
+                    int endIndex = head.indexOf("</style>", startIndex) + "</style>".length();
+                    builder.append(head.substring(head.indexOf("<style", startIndex), endIndex));
+                    startIndex = endIndex;
+                }
+                catch (Exception e)
+                {
+                    // no style found - break extraction
+                    break;
+                }
+            }
+            // extract <script>
+            startIndex = 0;
+            while (true)
+            {
+                try
+                {
+                    int endIndex = head.indexOf("</script>", startIndex) + "</script>".length();
+                    builder.append(head.substring(head.indexOf("<script", startIndex), endIndex));
+                    startIndex = endIndex;
+                }
+                catch (Exception e)
+                {
+                    // no script found - break extraction
+                    break;
+                }
+            }
+            
+            return builder.toString();
+        }
+        
+    }
+    
+    /**
+     * The key which is used to store the ErrorPageBean in the view map of a facelet error page.
+     */
+    public static final String ERROR_PAGE_BEAN_KEY = "__myFacesErrorPageBean";
+    
+    private static final String EXCEPTION_KEY = "javax.servlet.error.exception";
+    private static final String VIEW_KEY = "org.apache.myfaces.error.UIViewRoot";
+
+    private static final Logger log = Logger.getLogger(ErrorPageWriter.class.getName());
+
+    private final static String TS = "&lt;";
+
+    private static final String ERROR_TEMPLATE = "META-INF/rsc/myfaces-dev-error.xml";
+
+    @JSFWebConfigParam(defaultValue="META-INF/rsc/myfaces-dev-error.xml", since="1.2.4")
+    private static final String ERROR_TEMPLATE_RESOURCE = "org.apache.myfaces.ERROR_TEMPLATE_RESOURCE";
+
+    private static String[] ERROR_PARTS;
+
+    private static final String DEBUG_TEMPLATE = "META-INF/rsc/myfaces-dev-debug.xml";
+
+    @JSFWebConfigParam(defaultValue="META-INF/rsc/myfaces-dev-debug.xml", since="1.2.4")
+    private static final String DEBUG_TEMPLATE_RESOURCE = "org.apache.myfaces.DEBUG_TEMPLATE_RESOURCE";
+
+    private static String[] DEBUG_PARTS;
+    
+    private static final String REGEX_PATTERN = ".*?\\Q,Id:\\E\\s*(\\S+)\\s*\\].*?";
+    
+    private final static String[] IGNORE = new String[] { "parent", "rendererType" };
+
+    public ErrorPageWriter()
+    {
+        super();
+    }
+    
+    /**
+     * Generates the HTML error page for the given Throwable 
+     * and writes it to the given writer.
+     * @param writer
+     * @param faces
+     * @param e
+     * @throws IOException
+     */
+    public static void debugHtml(Writer writer, FacesContext faces, Throwable e) throws IOException
+    {
+        debugHtml(writer, faces, e, faces.getViewRoot());
+    }
+    
+    private static void debugHtml(Writer writer, FacesContext faces, Throwable e, UIViewRoot view) throws IOException
+    {
+        _init(faces);
+        Date now = new Date();
+        for (int i = 0; i < ERROR_PARTS.length; i++)
+        {
+            if ("message".equals(ERROR_PARTS[i]))
+            {
+                String msg = e.getMessage();
+                if (msg != null)
+                {
+                    writer.write(msg.replaceAll("<", TS));
+                }
+                else
+                {
+                    writer.write(e.getClass().getName());
+                }
+            }
+            else if ("trace".equals(ERROR_PARTS[i]))
+            {
+                _writeException(writer, e);
+            }
+            else if ("now".equals(ERROR_PARTS[i]))
+            {
+                writer.write(DateFormat.getDateTimeInstance().format(now));
+            }
+            else if ("tree".equals(ERROR_PARTS[i]))
+            {
+                if (view != null)
+                {
+                    _writeComponent(writer, view, _getErrorId(e));
+                }
+            }
+            else if ("vars".equals(ERROR_PARTS[i]))
+            {
+                _writeVariables(writer, faces, view);
+            }
+            else if ("cause".equals(ERROR_PARTS[i]))
+            {
+                _writeCause(writer, e);
+            }
+            else
+            {
+                writer.write(ERROR_PARTS[i]);
+            }
+        }
+    }
+
+    /**
+     * Generates the HTML debug page for the current view
+     * and writes it to the given writer.
+     * @param writer
+     * @param faces
+     * @throws IOException
+     */
+    public static void debugHtml(Writer writer, FacesContext faces) throws IOException
+    {
+        _init(faces);
+        Date now = new Date();
+        for (int i = 0; i < DEBUG_PARTS.length; i++)
+        {
+            if ("message".equals(DEBUG_PARTS[i]))
+            {
+                writer.write(faces.getViewRoot().getViewId());
+            }
+            else if ("now".equals(DEBUG_PARTS[i]))
+            {
+                writer.write(DateFormat.getDateTimeInstance().format(now));
+            }
+            else if ("tree".equals(DEBUG_PARTS[i]))
+            {
+                _writeComponent(writer, faces.getViewRoot(), null);
+            }
+            else if ("vars".equals(DEBUG_PARTS[i]))
+            {
+                _writeVariables(writer, faces, faces.getViewRoot());
+            }
+            else
+            {
+                writer.write(DEBUG_PARTS[i]);
+            }
+        }
+    }
+
+    /**
+     * Handles the given Throwbale in the following way:
+     * If there is no <error-page> entry in web.xml, try to reset the current HttpServletResponse,
+     * generate the error page and call responseComplete(). If this fails, rethrow the Exception.
+     * If there is an <error-page> entry in web.xml, save the current UIViewRoot in the RequestMap
+     * with the key "org.apache.myfaces.error.UIViewRoot" to access it on the error page and
+     * rethrow the Exception to let it flow up to FacesServlet.service() and thus be handled by the container.
+     * @param facesContext
+     * @param ex
+     * @throws FacesException
+     */
+    public static void handleThrowable(FacesContext facesContext, Throwable ex) throws FacesException
+    {
+        _prepareExceptionStack(ex);
+        
+        boolean errorPageWritten = false;
+        
+        // check if an error page is present in web.xml
+        WebXml webXml = WebXml.getWebXml(facesContext.getExternalContext());
+        if (!webXml.isErrorPagePresent())
+        {
+            // write the error page
+            Object response = facesContext.getExternalContext().getResponse();
+            if (response instanceof HttpServletResponse)
+            {
+                HttpServletResponse httpResp = (HttpServletResponse) response;
+                if (!httpResp.isCommitted())
+                {
+                    httpResp.reset();
+                    httpResp.setContentType("text/html; charset=UTF-8");
+                    try
+                    {
+                        Writer writer = httpResp.getWriter();
+                        debugHtml(writer, facesContext, ex);
+                        log.log(Level.SEVERE, "An exception occurred", ex);
+                        
+                        // mark the response as complete
+                        facesContext.responseComplete();
+                        
+                        errorPageWritten = true;
+                    }
+                    catch(IOException ioe)
+                    {
+                        throw new FacesException("Could not write the error page", ioe);
+                    }
+                }
+            }
+        }
+        else
+        {
+            // save current view in the request map to access it on the error page
+            facesContext.getExternalContext().getRequestMap().put(VIEW_KEY, facesContext.getViewRoot());
+        }
+        // rethrow the throwable, if we did not write the error page
+        if (!errorPageWritten)
+        {
+            if (ex instanceof FacesException)
+            {
+                throw (FacesException) ex;
+            }
+            if (ex instanceof RuntimeException)
+            {
+                throw (RuntimeException) ex;
+            }
+            throw new FacesException(ex);
+        }
+
+    }
+
+    private static String _getErrorTemplate(FacesContext context)
+    {
+        String errorTemplate = context.getExternalContext().getInitParameter(ERROR_TEMPLATE_RESOURCE);
+        if (errorTemplate != null)
+        {
+            return errorTemplate;
+        }
+        return ERROR_TEMPLATE;
+    }
+
+    private static String _getDebugTemplate(FacesContext context)
+    {
+        String debugTemplate = context.getExternalContext().getInitParameter(DEBUG_TEMPLATE_RESOURCE);
+        if (debugTemplate != null)
+        {
+            return debugTemplate;
+        }
+        return DEBUG_TEMPLATE;
+    }
+
+    private static void _init(FacesContext context) throws IOException
+    {
+        if (ERROR_PARTS == null)
+        {
+            ERROR_PARTS = _splitTemplate(_getErrorTemplate(context));
+        }
+
+        if (DEBUG_PARTS == null)
+        {
+            DEBUG_PARTS = _splitTemplate(_getDebugTemplate(context));
+        }
+    }
+
+    private static String[] _splitTemplate(String rsc) throws IOException
+    {
+        InputStream is = null;
+
+        if (System.getSecurityManager()!=null)
+        {
+            try
+            {
+                ClassLoader cl = AccessController.<ClassLoader>doPrivileged(new PrivilegedExceptionAction<ClassLoader>() {
+                    public ClassLoader run() throws PrivilegedActionException 
+                    {
+                        return Thread.currentThread().getContextClassLoader();
+                    }
+                });
+                is = cl.getResourceAsStream(rsc);
+            }
+            catch (PrivilegedActionException pae)
+            {
+                throw new FacesException(pae);
+            }
+        }
+        else
+        {
+            is = Thread.currentThread().getContextClassLoader().getResourceAsStream(rsc);
+            
+            if (is == null)
+            {
+                // try to get the resource from ExternalContext
+                is = FacesContext.getCurrentInstance().getExternalContext().getResourceAsStream(rsc);
+            }
+        }
+
+        if (is == null)
+        {
+            // throw an IllegalArgumentException instead of a FileNotFoundException,
+            // because when using <ui:debug /> this error is hard to trace,
+            // because the Exception is thrown in the Renderer and so it seems like
+            // the facelet (or jsp) does not exist.
+            throw new IllegalArgumentException("Could not find resource " + rsc);
+        }
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        byte[] buff = new byte[512];
+        int read;
+        while ((read = is.read(buff)) != -1)
+        {
+            baos.write(buff, 0, read);
+        }
+        String str = baos.toString();
+        return str.split("@@");
+    }
+
+    private static List<String> _getErrorId(Throwable e)
+    {
+        String message = e.getMessage();
+
+        if (message == null)
+            return null;
+
+        List<String> list = new ArrayList<String>();
+        Pattern pattern = Pattern.compile(REGEX_PATTERN);
+        Matcher matcher = pattern.matcher(message);
+
+        while (matcher.find())
+        {
+            list.add(matcher.group(1));
+        }
+        if (list.size() > 0)
+            return list;
+        return null;
+    }
+
+    private static void _writeException(Writer writer, Throwable e) throws IOException
+    {
+        StringWriter str = new StringWriter(256);
+        PrintWriter pstr = new PrintWriter(str);
+        e.printStackTrace(pstr);
+        pstr.close();
+        writer.write(str.toString().replaceAll("<", TS));
+    }
+    
+    private static void _writeCause(Writer writer, Throwable ex) throws IOException
+    {
+        String msg = ex.getMessage();
+        while (ex.getCause() != null)
+        {
+            ex = ex.getCause();
+            if (ex.getMessage() != null)
+                msg = ex.getMessage();
+        }
+
+        if (msg != null)
+        {
+            msg = ex.getClass().getName() + " - " + msg;
+            writer.write(msg.replaceAll("<", TS));
+        }
+        else
+        {
+            writer.write(ex.getClass().getName());
+        }
+    }
+
+    private static void _writeVariables(Writer writer, FacesContext faces, UIViewRoot view) throws IOException
+    {
+        ExternalContext ctx = faces.getExternalContext();
+        _writeVariables(writer, ctx.getRequestParameterMap(), "Request Parameters");
+        _writeVariables(writer, ctx.getRequestMap(), "Request Attributes");
+        _writeVariables(writer, view.getViewMap(), "View Attributes");
+        if (ctx.getSession(false) != null)
+        {
+            _writeVariables(writer, ctx.getSessionMap(), "Session Attributes");
+        }
+        _writeVariables(writer, ctx.getFlash(), "Flash Attributes");
+        _writeVariables(writer, ctx.getApplicationMap(), "Application Attributes");
+    }
+
+    private static void _writeVariables(Writer writer, Map<String, ? extends Object> vars, String caption) throws IOException
+    {
+        writer.write("<table><caption>");
+        writer.write(caption);
+        writer
+              .write("</caption><thead><tr><th style=\"width: 10%; \">Name</th><th style=\"width: 90%; \">Value</th></tr></thead><tbody>");
+        boolean written = false;
+        if (!vars.isEmpty())
+        {
+            SortedMap<String, Object> sortedMap = new TreeMap<String, Object>(vars);
+            for (Map.Entry<String, Object> entry : sortedMap.entrySet())
+            {
+                String key = entry.getKey().toString();
+                if (key.indexOf('.') == -1)
+                {
+                    writer.write("<tr><td>");
+                    writer.write(key.replaceAll("<", TS));
+                    writer.write("</td><td>");
+                    writer.write(entry.getValue().toString().replaceAll("<", TS));
+                    writer.write("</td></tr>");
+                    written = true;
+                }
+            }
+        }
+        if (!written)
+        {
+            writer.write("<tr><td colspan=\"2\"><em>None</em></td></tr>");
+        }
+        writer.write("</tbody></table>");
+    }
+
+    private static void _writeComponent(Writer writer, UIComponent c, List<String> highlightId) throws IOException
+    {
+        writer.write("<dl><dt");
+        if (_isText(c))
+        {
+            writer.write(" class=\"uicText\"");
+        }
+        if (highlightId != null)
+        {
+            if ((highlightId.size() > 0) && (highlightId.get(0).equals(c.getId())))
+            {
+                highlightId.remove(0);
+                if (highlightId.size() == 0)
+                {
+                    writer.write(" class=\"highlightComponent\"");
+                }
+            }
+        }
+        writer.write(">");
+
+        boolean hasChildren = c.getChildCount() > 0 || c.getFacets().size() > 0;
+
+        _writeStart(writer, c, hasChildren);
+        writer.write("</dt>");
+        if (hasChildren)
+        {
+            if (c.getFacets().size() > 0)
+            {
+                for (Map.Entry<String, UIComponent> entry : c.getFacets().entrySet())
+                {
+                    writer.write("<dd class=\"uicFacet\">");
+                    writer.write("<span>");
+                    writer.write(entry.getKey());
+                    writer.write("</span>");
+                    _writeComponent(writer, entry.getValue(), highlightId);
+                    writer.write("</dd>");
+                }
+            }
+            if (c.getChildCount() > 0)
+            {
+                for (UIComponent child : c.getChildren())
+                {
+                    writer.write("<dd>");
+                    _writeComponent(writer, child, highlightId);
+                    writer.write("</dd>");
+                }
+            }
+            writer.write("<dt>");
+            _writeEnd(writer, c);
+            writer.write("</dt>");
+        }
+        writer.write("</dl>");
+    }
+
+    private static void _writeEnd(Writer writer, UIComponent c) throws IOException
+    {
+        if (!_isText(c))
+        {
+            writer.write(TS);
+            writer.write('/');
+            writer.write(_getName(c));
+            writer.write('>');
+        }
+    }
+
+    private static void _writeAttributes(Writer writer, UIComponent c)
+    {
+        try
+        {
+            BeanInfo info = Introspector.getBeanInfo(c.getClass());
+            PropertyDescriptor[] pd = info.getPropertyDescriptors();
+            Method m = null;
+            Object v = null;
+            String str = null;
+            for (int i = 0; i < pd.length; i++)
+            {
+                if (pd[i].getWriteMethod() != null && Arrays.binarySearch(IGNORE, pd[i].getName()) < 0)
+                {
+                    m = pd[i].getReadMethod();
+                    try
+                    {
+                        v = m.invoke(c, (Object[])null);
+                        if (v != null)
+                        {
+                            if (v instanceof Collection || v instanceof Map || v instanceof Iterator)
+                            {
+                                continue;
+                            }
+                            writer.write(" ");
+                            writer.write(pd[i].getName());
+                            writer.write("=\"");
+                            if (v instanceof Expression)
+                            {
+                                str = ((Expression)v).getExpressionString();
+                            }
+                            writer.write(str.replaceAll("<", TS));
+                            writer.write("\"");
+                        }
+                    }
+                    catch (Exception e)
+                    {
+                        // do nothing
+                    }
+                }
+            }
+
+            ValueExpression binding = c.getValueExpression("binding");
+            if (binding != null)
+            {
+                writer.write(" binding=\"");
+                writer.write(binding.getExpressionString().replaceAll("<", TS));
+                writer.write("\"");
+            }
+        }
+        catch (Exception e)
+        {
+            // do nothing
+        }
+    }
+
+    private static void _writeStart(Writer writer, UIComponent c, boolean children) throws IOException
+    {
+        if (_isText(c))
+        {
+            String str = c.toString().trim();
+            writer.write(str.replaceAll("<", TS));
+        }
+        else
+        {
+            writer.write(TS);
+            writer.write(_getName(c));
+            _writeAttributes(writer, c);
+            if (children)
+            {
+                writer.write('>');
+            }
+            else
+            {
+                writer.write("/>");
+            }
+        }
+    }
+
+    private static String _getName(UIComponent c)
+    {
+        String nm = c.getClass().getName();
+        return nm.substring(nm.lastIndexOf('.') + 1);
+    }
+
+    private static boolean _isText(UIComponent c)
+    {
+        return (c.getClass().getName().startsWith("org.apache.myfaces.view.facelets.compiler"));
+    }
+
+    private static void _prepareExceptionStack(Throwable ex)
+    {
+
+        if (ex == null)
+            return;
+
+        // check for getRootCause and getCause-methods
+        if (!_initCausePerReflection(ex, "getRootCause"))
+        {
+            _initCausePerReflection(ex, "getCause");
+        }
+
+        _prepareExceptionStack(ex.getCause());
+    }
+
+    private static boolean _initCausePerReflection(Throwable ex, String methodName)
+    {
+        try
+        {
+            Method causeGetter = ex.getClass().getMethod(methodName, (Class[])null);
+            Throwable rootCause = (Throwable)causeGetter.invoke(ex, (Object[])null);
+            return _initCauseIfAvailable(ex, rootCause);
+        }
+        catch (Exception e1)
+        {
+            return false;
+        }
+    }
+
+    private static boolean _initCauseIfAvailable(Throwable th, Throwable cause)
+    {
+        if (cause == null)
+            return false;
+
+        try
+        {
+            Method m = Throwable.class.getMethod("initCause", new Class[] { Throwable.class });
+            m.invoke(th, new Object[] { cause });
+            return true;
+        }
+        catch (Exception e)
+        {
+            return false;
+        }
+    }
+}

Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/FaceletViewDeclarationLanguage.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/FaceletViewDeclarationLanguage.java?rev=894255&r1=894254&r2=894255&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/FaceletViewDeclarationLanguage.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/FaceletViewDeclarationLanguage.java Mon Dec 28 21:57:35 2009
@@ -24,7 +24,6 @@
 import java.beans.PropertyDescriptor;
 import java.io.FileNotFoundException;
 import java.io.IOException;
-import java.io.Writer;
 import java.lang.reflect.Array;
 import java.net.URL;
 import java.util.ArrayList;
@@ -105,7 +104,6 @@
 import org.apache.myfaces.view.facelets.tag.jstl.fn.JstlFnLibrary;
 import org.apache.myfaces.view.facelets.tag.ui.UIDebug;
 import org.apache.myfaces.view.facelets.tag.ui.UILibrary;
-import org.apache.myfaces.view.facelets.util.DevTools;
 import org.apache.myfaces.view.facelets.util.ReflectionUtil;
 
 /**
@@ -1263,11 +1261,9 @@
         }
     }
 
-    protected void handleRenderException(FacesContext context, Exception e) throws IOException, ELException,
-            FacesException
+    protected void handleRenderException(FacesContext context, Exception e) 
+            throws IOException, ELException, FacesException
     {
-        Object resp = context.getExternalContext().getResponse();
-        
         UIViewRoot root = context.getViewRoot();
         StringBuffer sb = new StringBuffer(64);
         sb.append("Error Rendering View");
@@ -1279,22 +1275,9 @@
         }
         
         log.log(Level.SEVERE, sb.toString(), e);
-
-        // handle dev response
-        if (_isDevelopmentMode(context) && !context.getResponseComplete() && resp instanceof HttpServletResponse)
-        {
-            HttpServletResponse httpResp = (HttpServletResponse) resp;
-            if (!httpResp.isCommitted())
-            {
-                httpResp.reset();
-                httpResp.setContentType("text/html; charset=UTF-8");
-                Writer w = httpResp.getWriter();
-                DevTools.debugHtml(w, context, e);
-                w.flush();
-                context.responseComplete();
-            }
-        }
-        else if (e instanceof RuntimeException)
+        
+        // rethrow the Exception to be handled by the ExceptionHandler
+        if (e instanceof RuntimeException)
         {
             throw (RuntimeException) e;
         }

Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/FaceletViewHandler.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/FaceletViewHandler.java?rev=894255&r1=894254&r2=894255&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/FaceletViewHandler.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/FaceletViewHandler.java Mon Dec 28 21:57:35 2009
@@ -52,7 +52,6 @@
 import org.apache.myfaces.view.facelets.tag.TagDecorator;
 import org.apache.myfaces.view.facelets.tag.TagLibrary;
 import org.apache.myfaces.view.facelets.tag.ui.UIDebug;
-import org.apache.myfaces.view.facelets.util.DevTools;
 import org.apache.myfaces.view.facelets.util.ReflectionUtil;
 
 /**
@@ -705,41 +704,23 @@
         }
     }
 
-    protected void handleRenderException(FacesContext context, Exception e) throws IOException, ELException,
-            FacesException
+    protected void handleRenderException(FacesContext context, Exception e) 
+            throws IOException, ELException, FacesException
     {
-        Object resp = context.getExternalContext().getResponse();
-
-        // always log
-        if (log.isLoggable(Level.SEVERE))
-        {
-            UIViewRoot root = context.getViewRoot();
-            StringBuffer sb = new StringBuffer(64);
-            sb.append("Error Rendering View");
-            if (root != null)
-            {
-                sb.append('[');
-                sb.append(root.getViewId());
-                sb.append(']');
-            }
-            log.log(Level.SEVERE, sb.toString(), e);
-        }
-
-        // handle dev response
-        if (this.developmentMode && !context.getResponseComplete() && resp instanceof HttpServletResponse)
-        {
-            HttpServletResponse httpResp = (HttpServletResponse) resp;
-            if (!httpResp.isCommitted())
-            {
-                httpResp.reset();
-                httpResp.setContentType("text/html; charset=UTF-8");
-                Writer w = httpResp.getWriter();
-                DevTools.debugHtml(w, context, e);
-                w.flush();
-                context.responseComplete();
-            }
-        }
-        else if (e instanceof RuntimeException)
+        UIViewRoot root = context.getViewRoot();
+        StringBuffer sb = new StringBuffer(64);
+        sb.append("Error Rendering View");
+        if (root != null)
+        {
+            sb.append('[');
+            sb.append(root.getViewId());
+            sb.append(']');
+        }
+        
+        log.log(Level.SEVERE, sb.toString(), e);
+        
+        // rethrow the Exception to be handled by the ExceptionHandler
+        if (e instanceof RuntimeException)
         {
             throw (RuntimeException) e;
         }