FacesException not being handled by standard error page - jsf

there is one issue to which i don't find any specific answer. there is an ArrayOutOfBoundException thrown in a setter method called during render response phase since i have the value of that property set in my faces-config. Now, when this happens, it is not redirecting. What i could understand till now is it might be converting this exception to FacesException and so its not redirecting. Any views to handle this ? the call does not seem to be an ajax call too since it is coming when i click on a menu item.

Related

Faces messages not shown when preRenderView event jumps to another view in nested backing bean

I have two scenarios. First one, from an external URL, I access a view (V1) with a preRenderView event in it. The executed method in the backing bean navigates to another view (V2). In V2 I have some elements that are associated to a backing bean (BB1). Also, V2 includes another view with another backing bean (BB2).
Wherever an error occurs in BB2, the errors don´t display, but if an error happens in BB1, the errors display without any problem.
Second one, if I access V1 and this event doesn´t navigate to other view, V1 renders. In V1 is a form with a button that navigates to V2. This way, doesn´t matter where the errors occur, either BB1's errors and BB2's errors are displayed.
¿Any thoughts about the BB2's errors aren´t displayed in the first scenario?
Thank you in advance
I reached a solution for my problem. I think the preRenderView event that I had in my V2 was messing somehow with the preRenderView in V1 when I do the navigation by the first scenario. I changed it to a preRenderComponent in the V2 and enclosed by the f:metadata tag and the messages started to appear.

Navigation from managed bean constructor in ADF Faces JSF 1.2

Is it possible to navigate to another page/view from the constructor of the managed bean? I want this redirection if any exception occurred. I have tried many ways:
Try-1:
getFacesContext().responseComplete();
getFacesContext().getApplication().getNavigationHandler().handleNavigation(getFacesContext(), null, "gotoPartError");
getFacesContext().renderResponse();
Try-2:
getServletResponse().sendRedirect("partError.jspx")
Try-3:
getFacesContext().responseComplete();
getFacesContext().getExternalContext().redirect(getServletRequest().getContextPath() + "/pages/partError.jspx");
Try-4:
RequestDispatcher dispatcher = getServletRequest().getRequestDispatcher("partError.jspx");
dispatcher.forward(getServletRequest(), getServletResponse());
Try-5:
FacesContext context = getFacesContext();
UIViewRoot newPage = context.getApplication().getViewHandler().createView(context, "/partError.jspx");
context.setViewRoot(newPage);
context.renderResponse();
Try-6:
ControllerContext.getInstance().getCurrentViewPort().setViewId("partError");
Try-7:
Exception Handler in adfc-config.xml
Try-8:
Custom service handler defined in /.adf/META-INF/services/oracle.adf.view.rich.context.Exceptionhandler which extends oracle.adf.view.rich.context.Exceptionhandler
Try-9:
By extending JSF Life Cycle
None of them worked. For all the cases I received
java.lang.IllegalStateException: Cannot forward after response has been committed
Is not really possible in JSF 1.2? As I am using ADF 11.1.1.6.0, which uses JSF 1.2, some of the above "Try" contains ADF Faces ways.
I need anyway, that can be JSF 1.2 or ADF Faces, to navigate to error page. The only way I got success is the use of javascript, executed from backend, to open the error page in the _self window in case of error, but I don't really like it.
Any pointer in this matter would be very helpful.
It's easier to solve a problem if the cause of the problem is understood. A good exception tells basically already everything about the cause of the problem.
Look closer:
java.lang.IllegalStateException: Cannot forward after response has been committed
The response has been committed. This is a point of no return. Perhaps you failed to understand what it means that a response has been committed (which has the consequence that you also failed to understand the exception itself).
By default, the HTTP response is written to a buffer which is flushed every ~2KB, depending on server configuration. A flush of the response buffer causes the written bytes being actually sent from server to client. Once that happens for the first time, a response is considered committed. This is a point of no return. The server cannot take the already written bytes back from the client in case the server actually needs to change the response afterwards.
If you have some code which potentially needs to change the response, then you should be invoking it before the response is committed.
In your particular case, the managed bean is apparently constructed in the midst of the JSF render response phase during generating the HTML output. A part of the generated HTML output has already been sent to the client (so, the response is committed). You're apparently referencing the request scoped bean relatively late in the JSF page, or the response buffer is relatively small, or the HTML <head> is relatively large which causes a flush already before the <body> starts, etcetera.
You really need to invoke the code before the render response phase. In JSF 1.2, you can use the <f:view beforePhase> for this.
E.g.
<f:view beforePhase="#{bean.navigate}">
with
public void navigate(PhaseEvent event) {
if (event.getPhaseId() == PhaseId.RENDER_RESPONSE) {
// Do here your job which should run right before the RENDER_RESPONSE.
}
}
Then your Try-1 and Try-3 will work (you can however leave those responseComplete() and renderResponse() lines away, they are implicitly already taken care of).
Try-2 and Try-4 are poor. You should avoid having javax.servlet.* imports in your backing bean. Try-5 is clumsy. Try-6, Try-7 and Try-8 are beyond my scope. Try-9 is doable, but extremely clumsy.

Preserving JSF messages after a redirect

I have a JSF page (using MyFaces 2.0) that does a bit of data gathering the first time it is displayed. If it can't find some information, it is supposed to provide a message to that effect and redirect back to a different page. I've tried using the solution found here Preserving FacesMessage after redirect for presentation through <h:message> in JSF (setKeepMessages(true)) but the messages aren't displaying after the redirect. The only difference I can pick out is that I'm not using a navigation rule, I'm calling the redirect() call on the external context because this isn't occurring in a normal action.
Relevant code:
public void redirectToPageWithMessage(String inPage, String message, FacesMessage.Severity severity){
getFlash().setKeepMessages(true);
addMessage(message, severity);
try {
getFacesContext().getExternalContext().redirect(inPage);
} catch (IOException e) {
e.printStackTrace();
}
}
Unfortunately this doesn't seem to be working. The redirect happens just fine, but the < messages /> tag isn't displaying the message. Is there something different about the way redirect() happens that prevents this from working?
The code that saves the messages are executed after the phase ends (see Flash.doPostPhaseActions(FacesContext) ). So, it is expected it does not work, but maybe you can call Flash.doPostPhaseActions before the redirect. Note is not a "clean" solution, but it is possible.
I had the same problem and solve it not using ExternalContext.redirect() but to play with outcome for your actions.
That is to say, my action called by my buttons return a String (the outcome) which indicates the navigation rules to go to the next page. With that system, the messages are preserved.
JSFMessages are kept only for the processing of the actual request. A second request is made when using redirect, so the JSFMessages will be lost. The EL-Flash is a way to work around this. This example should work: http://ocpsoft.com/java/persist-and-pass-facesmessages-over-page-redirects/

JSF adding query parameters

I am using JSF and I have a backing bean method which does some processing and sets a
variable 'outcome' which then decides the next page to navigate to depending on the
faces-config.xml navigation rules.
What I want to do is add parameters to the URL (in the backing bean?) when the next page is navigated to.
However in the Handler where the backing bean method is, there is no reference to the
HttpRequest object. This is an existing handler which has been around for a long time, so I
am wondering how I can do
request.setAttribute("name", value);
Is there a different approach available for JSF? Any help much appreciated.
HI BalusC,
I am trying to implement what you explained below, however I am running into a problem.
This is what I have:
StringBuffer url = ( (HttpServletRequest)FacesContext.getCurrentInstance().getExternalContext().getRequest()).getRequestURL();
url.append( "?serialNumber=");
url.append(regBean.getSerialNumber());
try{ FacesContext.getCurrentInstance().getExternalContext().redirect(url.toString());
}catch (Exception ex){
ex.printStackTrace();
}
There is no exception generated however I get a 500 Http error "the server has encountered an unknown error." The log shows a little more detail but not enough to be helpful:
ERROR [lifecycle] JSF1054: (Phase ID: INVOKE_APPLICATION 5, View ID: /registration/productValidation.jsp) Exception thrown during phase execution: javax.faces.event.PhaseEvent[source=com.sun.faces.lifecycle.LifecycleImpl#591dae]
11:19:12,186 ERROR [[Faces Servlet]] Servlet.service() for servlet Faces Servlet threw exception
java.lang.IllegalStateException
at org.apache.catalina.connector.ResponseFacade.sendRedirect(ResponseFacade.java:435)
at com.sun.faces.context.ExternalContextImpl.redirect(ExternalContextImpl.java:421)
at com.sun.faces.application.NavigationHandlerImpl.handleNavigation(NavigationHandlerImpl.java:181)
at com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:130)
at javax.faces.component.UICommand.broadcast(UICommand.java:387)
at org.ajax4jsf.component.AjaxViewRoot.processEvents(AjaxViewRoot.java:321)
at org.ajax4jsf.component.AjaxViewRoot.broadcastEvents(AjaxViewRoot.java:296)
at org.ajax4jsf.component.AjaxViewRoot.processPhase(AjaxViewRoot.java:253)
at org.ajax4jsf.component.AjaxViewRoot.processApplication(AjaxViewRoot.java:466)
at com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:82)
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:100)
Any ideas at all will be very much appreciated. Thanks!
Ok, thanks for your comments, I changed some stuff around and now I have:
FacesContext.getCurrentInstance().getExternalContext().redirect("mypage.jsp?serialNumber=555555");
Upon debugging I can see that the redirect is working since on mypage.htm I am displaying some headers from a resourcebundle (properties file) so when it tried to get the header to display it is encountering a NullPointer on the line below:
FacesContext context = FacesContext.getCurrentInstance();
context is null, so the log shows NullPointer error but the url of the page is correct I can see the address bar showing http://..../mypage.jsp?serialNum=5555 just as expected!
It appears its having trouble just displaying the contents of the page. So close yet so far ;-(
You need to fire ExternalContext#redirect() in the bean action method yourself.
public void submit() {
String url = "page.jsp?name1=value1&name2=value2";
FacesContext.getCurrentInstance().getExternalContext().redirect(url);
}
If your IDE validator is jerking about the void action method, then you can just ignore it or declare it back to String and put return null; at end of method block.
If you want to set the particular parameters back in some bean in the subsequent request, then you can set them as managed properties in faces-config.xml by #{param.name1} and #{param.name2}.
That said, request attributes should not be confused with request parameters. The request attributes are attached to the current request in the server side only. They are in no way passed to the next request. There you use request parameters for which you can either attach to the redirect URL or include as hidden parameters in a POST form in the response page.
Further, it might be useful to know that you can get a handle of the HttpServletRequest in JSF by ExternalContext#getRequest(). You should however try to avoid to go that far with hauling the "raw" Servlet API from under the JSF hoods. Make use of JSF-provided facilities as many as possible.
JSF 2 added parameters to the navigation handler via the view-param element. From the spec:
If a matching <navigation-case> element was located, and the <redirect/> element was specified in this <navigation-case>, call getRedirectURL() on the ViewHandler, passing the current FacesContext, the <to-view-id>, any name=value parameter pairs specified within <view-param> elements within the element, and the value of the include-view-params attribute of the <redirect /> element if present, false, if not. The return from this method is the value to be sent to the client to which the redirect will occurr. Call getFlash().setRedirect(true) on the current FacesContext. Cause the current response to perform an HTTP redirect to this path, and call responseComplete() on the FacesContext instance for the current request. If the content of <to-view-id> is a value expression, first evaluate it to obtain the value of the view id.

JSF getValue() v.s. getSubmittedValue()

I've been developing a few JSF applications lately and am disturbed with the inconsistency in the web component APIs.
I've noticed that there is extremely unpredictable behavior when calling .getValue() or .getSubmittedValue() on a JSF component object in server side code. Sometimes when I call .getValue() on a drop down list box, I've noticed that I get the value as it was BEFORE I selected my value (so the value from the last page refresh), of which .getSubmittedValue() gets me the correct value, as such:
UIInput name = new UIInput(); // This is the control I have in a bean.
public void submit(ActionEvent ae)
{
someMethod(name.getValue().toString()); // Retrieves the "old" value
someMethod(name.getSubmittedValue().toString()); // Retrieves the correct value
}
Also, I've noticed that calling .getSubmittedValue() on a form field sometimes results in a null pointer exception because that value has not been instantiated in the component object, in which case when I call .getValue() in that circumstance I get the correct value, for example:
HtmlInputText name = new HtmlInputText(); // This is the control I have in a bean.
public void submit(ActionEvent ae)
{
someMethod(name.getValue().toString()); // Retrieves the correct value
someMethod(name.getSubmittedValue().toString()); // Throws NullPointerException
}
Is this just a "quirk" of the JSF framework, or am I just using the API COMPLETELY incorrectly?? Any insight into these two methods would be greatly appreciated. Cheers.
Since this is the #1 result in Google for searching on getValue vs. getSubmittedValue I'd just like to add that the difference between these is critical in validation (i.e. when writing a custom validator)
To quote the API documentation for getSubmittedValue():
This is non-null only between decode
and validate phases, or when
validation for the component has not
succeeded. Once conversion and
validation has succeeded, the
(converted) value is stored in the
local "value" property of this
component, and the submitted value is
reset to null.
Source: http://myfaces.apache.org/core11/myfaces-api/apidocs/javax/faces/component/UIInput.html#getSubmittedValue()
This means that if the validation/conversion has taken place for the binding you are trying to access, you should call getValue() otherwise you'll have to call getSubmittedValue() and deal with parsing it yourself. The order in which these occur seems to be dictated by the order they appear in the UI, but I don't think that's guaranteed. Even if it is, you shouldn't count on that as changing field in your UI shouldn't break your code.
You can detect if the validation/conversion has been done by just looking at what isLocalValueSet() returns. If it returns true, then the valdation/conversion has been done, so you should call getValue(). Otherwise you'll need to call getSubmittedValue() and that'll give you the raw input the user entered and you'll likely want to parse it into something more meaningful.
For example, a calendar object would return a Date object when getValue() was called, but a String object when getSubmittedValue() was called. It's up to your converter to parse the string into a Date so it can be validated.
It'd be great if the JSF spec had a method which would do this for us, but AFAIK it doesn't. If certain dates need to be before other dates, and some are only required in certain circumstances, one will need to write several validators to handle this. So it can easily become an issue. This is similar to the fact that you can't do any kind of validation on a blank field, which means you can't make that field conditionally required. If validation was run on all fields, even blank ones, a custom validator could be written to throw an exception if it should be required and is not. There are some things with JSF which are just a pain; unless/until they're fixed, we just have to deal with them.
To speak to the specifics of the issue in the original post: the difference here is where you're at in the life cycle. The submit method seems like an action listener for a button, which puts it at the end of the life cycle; actions and action listeners are triggered in the "Invoke Application" phase which comes prior to the render response, but after validation. If you're going to program in JSF, you should learn and understand the life cycle. It's worth the time.
To quote the documentation on EditableValueHolder.getSubmittedValue:
Return the submittedValue value of
this component. This method should
only be used by the encodeBegin()
and/or encodeEnd() methods of this
component, or its corresponding
Renderer.
Generally, you would not even be calling getValue. Instead, the component's value attribute should be bound to your model (a bean, maybe). Your business logic would interact with the model, not the component.
If the submitted value is not being set as the value, then I'd guess that some validation is failing. The only problem with that is that your event is being fired. Two guesses for the problem here:
You have a stale reference to the component object.
You've set the immediate attribute on a UICommand which means that the event is fired in a phase where the component will be in an inappropriate state.
It isn't possible to be certain with the information provided.
I work on xpages which are based on JSF so.. it could be the same...
Anyway, getSubmittedValue(); always returns what you see in firebug/chrome develepers network tab. That is value within sent packet. I have it shown (chrome) in headers tab, in form data section, named $$xspsubmitvalue.
On the other hand, getValue() is component specific. <-- not 100% sure here.
TL;DR answer:
UIViewRoot viewRoot = context.getViewRoot();
UIInput input = (UIInput)viewRoot.findComponent(":form:inputID");
String inputValueString;
if (input.isLocalValueSet()) {
inputValueString = (String)input.getValue(); //validated and converted already
} else {
inputValueString = (String)input.getSubmittedValue(); //raw input
}
or at least that's what the other answers are saying to do...
Just use .getSubmittedValue() and deal with the consequences of having to convert raw input (if necessary, if that raw input needs conversion). .getValue() is broken in this regard, even with the code above. It delays the submitted value if you use it and that's unacceptable.

Resources