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 = "<";
+
+ 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;
}