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 <[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

