Hi Martin,
> Hi Thomas,
>
> what would be the sense of catching an OutOfMemoryException - while
> rendering the error page, there can - at any time - a new
> OutOfMemoryException happening? Specifically, Exceptions are thought
> for catching in Java, but catching Errors doesn't make much sense.
The sense would be not to show a stack trace, but a nice-looking error page
to the end user. Most people think it is inappropriate to show a stack
trace to the end user, and one wants to avoid this as hard as one can. Of
course, in the case of an OutOfMemoryError, it can not be guaranteed that
it works, but one has tried at least. Maybe also the OutOfMemoryError is a
bad example; another example would be a InstantiationError thrown by
erroneous reflection code.
Or more generally speaking, if a extension hook (in this case the error
handling hook) is offered by a framework, in my personal opinion the hook
should be as general as possible. One never knows what the extension point
is used for.
> As for your other suggestion of wrapping the request-parameters: yes,
> that makes sense, if there is a way to get to the original request
> somehow. If you provide a patch for 1.2, I'd certainly incorporate it.
I would be happy to provide a patch. One could access the original request
through the request wrapper by adding a getter for the wrapped request to
the wrapper. To re-gain the original request, one would have the code [1].
I'd also NOT implement this as default handling of errors, because it is
not sure that an error page exists in every webapp and if it exists, the
url is not known. I'd instead add a error handler implementation, which
must be explicitly configured.
If you agree with this, I'll submit a patch to jira.
regards,
Thomas
[1] code to regain original request:
HttpServletRequest httpServletRequest = getRequestFromSomewhere();
HttpServletRequest originalRequest;
if (httpServletRequest instanceof ChangedParametersRequestWrapper)
{
originalRequest
= ((ChangedParametersRequestWrapper) httpServletRequest)
.getOriginalRequest();
}
else
{
// request is the original request
originalRequest = httpServletRequest;
}
> On 8/9/07, Thomas Fischer <[EMAIL PROTECTED]> wrote:
> >
> > Hi all,
> >
> > I'm rather a JSF newbie and I am wondering about a good way to do error
> > handling. In my previous pre-JSF web apps (i.e. Struts 1), error
handling
> > had the following features:
> >
> > - one could define a global error handler, no need to define it on
every
> > view
> > - one could read information about the error in the error handler (from
> > informations in the servlet request)
> > - It did not rely on sending a redirect to the client
> >
> > I'm trying to get the same for Myfaces.The error page should also be a
JSF
> > page, so I can use JSF features inside the error page.
> > In the wiki [1], three approaches are described:
> > 1) use Faces error handling in Myfaces 1.2.1
> > 2) Add a error page definition to the web.xml
> > 3) Write a delegate Servlet which wraps the FacesServlet
> >
> > 1) unfortunately Myfaces 1.2.1 is not yet released. Also, in the
current
> > 1.2.1 code, only java.lang.Exception is caught, not
java.lang.Throwable. So
> > e.g. in case of an OutOfMemoryError, still a stack trace is shown to
the
> > user.
> >
> > 2) Using myfaces 1.2.0, this method partly works and party does not
work.
> > In particular, it does not work in the following situation:
> > The user accesses a page which calls a backing bean method on a submit
> > button [2]. The user presses the button, and the the backing bean
method
> > throws a NullPointerException.
> > What should happen: This Exception should be caught by the error
handler,
> > and the error JSF page should be displayed.
> > What happens: a stack trace is displayed [3]. It seems that myfaces
> > recognizes that the request is a postback, and restores the view of the
> > original page where the error occured. Then Myfaces tries to call the
> > backing bean method tied to the form submit button again, which again
> > throws a null pointer exception. Then the servlet container display the
> > stack trace with the original exception, because the error page
invocation
> > failed. This happens regardless of using f:view and f:subview in the
> > error.jsf page.
> >
> > 3) With the servlet code on the wiki page, the same happened as in 2).
I
> > also found another web page which clears the current view using jsf
methods
> > [4] and thus should fix this error, but I did not try it because I'm
not so
> > deep in JSF to understand the code.
> >
> > So I wondered whether there was a way with no jsf view management code.
The
> > root of the problem is that the http request parameters are also
available
> > to the error jsf page, which misinterprets them. So all should be fine
if
> > the http request parameters would not be forwarded to the error page.
One
> > cannot simply modify the http request parameters in a servlet request,
but
> > one can use a dispatcher with a servlet request wrapper. I choose to
use a
> > servlet filter for the code, but one could also have used a dispatcher
> > servlet. The filter wraps all calls to the facesServlet in a
> > try-catch-block. In the catch block, it creates a requestWrapper
wrapping
> > the original request but without http parameters, and then dispatches
the
> > modified request to the error page. See [5] fore some code. Until now
it
> > works very well.
> >
> > One could also have used this approach in a custom error handler in
myfaces
> > 1.2.1
> >
> > I am posting this because a) I'd like to ask whether anyone sees a
problem
> > with this and b) to share it if someone has the same problems as I with
> > solution 2). If you think it is a valid solution, I can add the
suggestion
> > to the wiki.
> >
> > Thomas
> >
> > [1] http://wiki.apache.org/myfaces/Handling_Server_Errors
> >
> > [2]
> > jsp snippet:
> > <f:view>
> > <h:form id="loginForm">
> > <h:inputText id="loginUser" value="#{loginController.username}"
> > required="true" />
> > <h:inputSecret id="loginPass" value="#{loginController.password}"
> > required="true"/>
> > <h:commandButton id="loginSubmit" value="Login" action="
> > #{loginController.send}" />
> > </h:form>
> > </f:view>
> >
> > loginController.send:
> > public String send()
> > {
> > if (true)
> > {
> > throw new NullPointerException("Some Error");
> > }
> > }
> >
> > facesConfig snippet:
> > <managed-bean>
> > <managed-bean-name>loginController</managed-bean-name>
> >
<managed-bean-class>app.controller.LoginController</managed-bean-class>
> > <managed-bean-scope>request</managed-bean-scope>
> > </managed-bean>
> >
> > [3]
> > javax.faces.FacesException: Error calling action method of component
with
> > id loginForm:loginSubmit
> >
> > org.apache.myfaces.application.ActionListenerImpl.
> processAction(ActionListenerImpl.java:69)
> >
> >
javax.faces.component.UICommand.broadcast(UICommand.java:121)
> >
> >
javax.faces.component.UIViewRoot._broadcastForPhase(UIViewRoot.java:292)
> >
javax.faces.component.UIViewRoot.process(UIViewRoot.java:209)
> >
> >
javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:117)
> >
> > org.apache.myfaces.lifecycle.InvokeApplicationExecutor.
> execute(InvokeApplicationExecutor.java:32)
> >
> >
> >
org.apache.myfaces.lifecycle.LifecycleImpl.executePhase(LifecycleImpl.java:95)
> >
> >
> >
org.apache.myfaces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:70)
> >
javax.faces.webapp.FacesServlet.service(FacesServlet.java:137)
> >
> >
> >
> > root cause
> >
> >
> > javax.faces.el.EvaluationException:
org.apache.jasper.el.JspELException:
> > /login.jsp(72,14) '#{loginController.send}'
java.lang.NullPointerException:
> > Some Error
> >
> > javax.faces.component._MethodExpressionToMethodBinding.
> invoke(_MethodExpressionToMethodBinding.java:79)
> >
> >
> > org.apache.myfaces.application.ActionListenerImpl.
> processAction(ActionListenerImpl.java:54)
> >
> >
javax.faces.component.UICommand.broadcast(UICommand.java:121)
> >
> >
javax.faces.component.UIViewRoot._broadcastForPhase(UIViewRoot.java:292)
> >
javax.faces.component.UIViewRoot.process(UIViewRoot.java:209)
> >
> >
javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:117)
> >
> > org.apache.myfaces.lifecycle.InvokeApplicationExecutor.
> execute(InvokeApplicationExecutor.java:32)
> >
> >
> >
org.apache.myfaces.lifecycle.LifecycleImpl.executePhase(LifecycleImpl.java:95)
> >
> >
> >
org.apache.myfaces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:70)
> >
javax.faces.webapp.FacesServlet.service(FacesServlet.java:137)
> >
> >
> >
> > root cause
> >
> >
> > org.apache.jasper.el.JspELException: /login.jsp(72,14)
> > '#{loginController.send}' java.lang.NullPointerException: Some Error
> >
> >
org.apache.jasper.el.JspMethodExpression.invoke(JspMethodExpression.java:77)
> >
> >
> > javax.faces.component._MethodExpressionToMethodBinding.
> invoke(_MethodExpressionToMethodBinding.java:75)
> >
> >
> > org.apache.myfaces.application.ActionListenerImpl.
> processAction(ActionListenerImpl.java:54)
> >
> >
javax.faces.component.UICommand.broadcast(UICommand.java:121)
> >
> >
javax.faces.component.UIViewRoot._broadcastForPhase(UIViewRoot.java:292)
> >
javax.faces.component.UIViewRoot.process(UIViewRoot.java:209)
> >
> >
javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:117)
> >
> > org.apache.myfaces.lifecycle.InvokeApplicationExecutor.
> execute(InvokeApplicationExecutor.java:32)
> >
> >
> >
org.apache.myfaces.lifecycle.LifecycleImpl.executePhase(LifecycleImpl.java:95)
> >
> >
> >
org.apache.myfaces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:70)
> >
javax.faces.webapp.FacesServlet.service(FacesServlet.java:137)
> >
> >
> >
> > root cause
> >
> >
> > java.lang.NullPointerException: Some Error
> >
app.controller.LoginController.send(LoginController.java:70)
> > sun.reflect.NativeMethodAccessorImpl.invoke0(Native
Method)
> > sun.reflect.NativeMethodAccessorImpl.invoke(Unknown
Source)
> > sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown
> > Source)
> > java.lang.reflect.Method.invoke(Unknown Source)
> > org.apache.el.parser.AstValue.invoke(AstValue.java:131)
> >
> >
org.apache.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:276)
> >
> >
org.apache.jasper.el.JspMethodExpression.invoke(JspMethodExpression.java:68)
> >
> >
> > javax.faces.component._MethodExpressionToMethodBinding.
> invoke(_MethodExpressionToMethodBinding.java:75)
> >
> >
> > org.apache.myfaces.application.ActionListenerImpl.
> processAction(ActionListenerImpl.java:54)
> >
> >
javax.faces.component.UICommand.broadcast(UICommand.java:121)
> >
> >
javax.faces.component.UIViewRoot._broadcastForPhase(UIViewRoot.java:292)
> >
javax.faces.component.UIViewRoot.process(UIViewRoot.java:209)
> >
> >
javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:117)
> >
> > org.apache.myfaces.lifecycle.InvokeApplicationExecutor.
> execute(InvokeApplicationExecutor.java:32)
> >
> >
> >
org.apache.myfaces.lifecycle.LifecycleImpl.executePhase(LifecycleImpl.java:95)
> >
> >
> >
org.apache.myfaces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:70)
> >
javax.faces.webapp.FacesServlet.service(FacesServlet.java:137)
> >
> > [4]comment from Rhys22 on
> >
http://www.jroller.com/ksevindik/entry/uncaught_exception_handling_in_java
> >
> > [5]
> > web xml snippet:
> > <filter>
> > <filter-name>errorFilter</filter-name>
> > <filter-class>
> > app.filter.ErrorFilter
> > </filter-class>
> > <init-param>
> > <param-name>generalErrorForward</param-name>
> > <param-value>/error.jsf</param-value>
> > </init-param>
> > </filter>
> > <filter-mapping>
> > <filter-name>errorFilter</filter-name>
> > <url-pattern>/*</url-pattern>
> > </filter-mapping>
> >
> > ErrorFilter.java snippet:
> > public class ErrorFilter implements Filter
> > {
> > private String generalErrorForward;
> >
> > private static final String GENERAL_ERROR_FORWARD_INIT_PARAM
> > = "generalErrorForward";
> >
> > public void init(FilterConfig filterConfig) throws ServletException
> > {
> > generalErrorForward
> > =
filterConfig.getInitParameter(GENERAL_ERROR_FORWARD_INIT_PARAM);
> > if (generalErrorForward == null)
> > {
> > throw new ServletException("Init Parameter "
> > + GENERAL_ERROR_FORWARD_INIT_PARAM
> > + " must be set");
> > }
> > }
> >
> > public void doFilter(
> > ServletRequest req,
> > ServletResponse res,
> > FilterChain chain)
> > throws IOException, ServletException
> > {
> > HttpServletRequest request = (HttpServletRequest) req;
> > HttpServletResponse response = (HttpServletResponse) res;
> >
> > try
> > {
> > chain.doFilter(request, response);
> > }
> > catch (Throwable t)
> > {
> > // One could save the exception in a request attribute here
> > // ...
> > ServletRequest noParametersRequest
> > = new ChangedParametersRequestWrapper(request);
> > RequestDispatcher requestDispatcher
> > = request.getRequestDispatcher(generalErrorForward);
> > requestDispatcher.forward(noParametersRequest, response);
> > return;
> > }
> > }
> >
> > public void destroy()
> > {
> > }
> > }
> >
> > ChangedParametersRequestWrapper.java snippet:
> > public class ChangedParametersRequestWrapper extends
> > HttpServletRequestWrapper
> > {
> > private Map<String,String[]> requestParameters;
> >
> > public ChangedParametersRequestWrapper(HttpServletRequest
servletRequest)
> > {
> > super(servletRequest);
> > requestParameters = new HashMap<String,String[]>();
> > }
> >
> > public ChangedParametersRequestWrapper(
> > HttpServletRequest servletRequest,
> > Map<String,String[]> requestParameters)
> > {
> > super(servletRequest);
> > this.requestParameters = new
> > HashMap<String,String[]>(requestParameters);
> > }
> >
> > public String getParameter(String key)
> > {
> > String[] values = getParameterValues(key);
> > if (values == null)
> > {
> > return null;
> > }
> > return values[0];
> > }
> >
> > public Map<String,String[]> getParameterMap()
> > {
> > return Collections.unmodifiableMap(requestParameters);
> > }
> >
> > public String[] getParameterValues(String key)
> > {
> > return requestParameters.get(key);
> > }
> >
> > public Enumeration<String> getParameterNames()
> > {
> > return Collections.enumeration(requestParameters.keySet());
> > }
> > }
> >
> >
>
>
> --
>
> http://www.irian.at
>
> Your JSF powerhouse -
> JSF Consulting, Development and
> Courses in English and German
>
> Professional Support for Apache MyFaces