views:

1090

answers:

2

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 ;-(

+3  A: 

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.

BalusC
Thank you for your response. I have seen this approach used in our application however I am wondering that since this particular class has an 'outcome' which then goes to faces-config.xml to decide the next url the user should be taken to, following the approach above seems to override that. I am wondering what happens to the navigation rules, if I sort of hard-code the url with the query params? Is there no other elegant way to say... follow the navigation rules and just add on these params to the end?
msharma
Navigation rules will be ignored. `ExternalContext#redirect()` will call `FacesContext#responseComplete()`.
BalusC
@BalusC - by the letter of the spec, that URL should pass through `ExternalContext.encodeActionURL` prior to being used for redirect - though in most cases it will be returned unchanged.
McDowell
Hi BalusC, I am trying to implement what you suggested as we as using JSF1.2 and do not have the cool features McDowell has kindly suggested. I am hitting a problem though, any ideas, I ahve edited my original post.
msharma
The exception says that the response was already committed. Part of it is already sent to the client. This is a point of no return. You cannot change it anymore with sendredirect. Do you have something in servlet/filter chain which is altering the response? E.g. setting some headers, writing something to output and/or flushing the output, etc. Was it by the way an ajax or normal request?
BalusC
I am displaying headers from a properties file on the next page that the user is directed to, and there is a nullpointer for the facescontext there! Please see details above.
msharma
Uh, you aren't supposed to write raw Java code in a JSP file. Besides, there is no means of a FacesContext in a normal JSP/HTML request. If you need the FacesContext, you need to create a JSF page and pass request through the url-pattern of the FacesServlet and you need to write Java code in a backing bean rather than inside the JSP file.
BalusC
Maybe I'm not explaining too well, this is jsf page, and its existing architecture, so I'm trying to grasp it as I go along. The requests are being passed thru the url-pattern of FacesServlet defined in our web.xmlI have a hunch that I am close but have not fully resolved the issue. Since we have internationalization so we NEED to get translations for all content displayed, we have to use properties files for this. So I dont think its an issue with the headers....if I simply define an outcome there are no errors, since the navigation rules kick in.
msharma
After much struggle... having Jboss corruption and other environmental issues I am happy to say that this has worked! I can see the URL for the next page with the appended params in the URL :-)For some reason I used to get the FacesContext.getCurrentInstance()=null but after debugging again and again it it started working... i.e. FacesContext was not null, I did NOT make any code changes....so it is surprising, I guess its the X-factor of programming! Many thanks BalusC...you rock!
msharma
The `FacesContext` will be null when the request URL didn't match the `FacesServlet`'s `url-pattern`. E.g. you invoked `page.jsp` instead of `page.jsf` in URL while the `url-pattern` is `*.jsf`. The `FacesServlet` is the one who creates the `FacesContext`. Glad you fixed it. You're welcome.
BalusC
+1  A: 

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.

McDowell