myfaces-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Martin Marinschek" <martin.marinsc...@gmail.com>
Subject Re: global error handling (especially exception in backing bean)
Date Sun, 12 Aug 2007 12:19:18 GMT
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.

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.

regards,

Martin

On 8/9/07, Thomas Fischer <fischer@seitenbau.net> 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

Mime
View raw message