From: Simon Kitching [mailto:[EMAIL PROTECTED] > > Giampaolo Tomassoni wrote: > > Dears, > > Ciao Bella ;)
Yuhuuu :) > > I'm facing a problem with myfaces-1.4 in a framed web app under > JBoss Seam (http://labs.jboss.com/portal/jbossseam) and it seems > that the problem needs upstream support (you). > > > > The problem is the following. When a page with parameters and > an <h:form> in it is first displayed through a GET, myfaces > correctly issues the phase events RESTORE_VIEW, then > RENDER_RESPONSE. However, when a subsequent GET attempts showing > the very same page, possibly with different parameters, myfaces > invokes the following phases instead: RESTORE_VIEW, > APPLY_REQUEST_VALUES, PROCESS_VALIDATIONS, UPDATE_MODEL_VALUES, > INVOKE_APPLICATION and RENDER_RESPONSE. This basicly means that > myfaces handles the subsequent GET as a form submission, which > may not always be the case. > > > > In my case, in example, the GET parameters are used to specify > an item in a table. The <h:form> is then used to edit some of the > fields in that item. When the <h:form> is submitted through a > POST, the GET parameters which are used to identify the edited > item are not supplied in the form content: they are instead > automatically otained by a per-conversation context handled by JBoss Seam. > > > > So, handling a GET with parameters as a form submission drives > Seam to simply ignore the parameters and apply the values stored > in the conversation context. The net effect is that once a page > with parameters is displayed, it is not anymore possible to > "switch" to the same page with different parameters. > > > > GET isn't handled any differently from POST in MyFaces, and as far as I > know that's the correct behaviour. GET and POST are just two different > ways of encoding the parameters. In plain html, a form's method can be > set to "GET" or "POST". > <form method="get" action="/my/postback/url"> > <input name="data" size="10"> > </form> > So I don't believe it's a myfaces bug. I did suspect something like this. > What you are seeing in terms of JSF phases is expected; if view X is > requested by the browser and there is a component tree to restore for > that view, then the phases APPLY_REQUEST_VALUES, PROCESS_VALIDATIONS, > UPDATE_MODEL_VALUES, INVOKE_APPLICATION happen. If there is no existing > component tree for that view, then RESTORE_VIEW does not succeed so > processing skips straight to RENDER_RESPONSE. > > When using client-side state saving, the behaviour you want happens > automatically, because the POST will include a hidden field that > contains a serialized component tree (hence RESTORE_VIEW can be > performed). The GET command will not contain that hidden field, so > RESTORE_VIEW will not be possible and myfaces will move directly to > RENDER_RESPONSE. > > However when using server-side state saving, the component tree can be > found regardless of whether GET or POST is used, so RESTORE_VIEW succeeds. Well, right. But even in server-side state saving I see an <h:form> is encoded in a <form> with some <hidden> fields. So, I guess that a GET would need to supply the values of these <hidden>s in order to be identified as a postback. This may mean that there are ways to better identify a GET as a postback, but actually myfaces doesn't seem to pay too much attention to them. > As it happens, in the application I'm working on we have what seems to > be a similar problem to you (though we don't use Seam); we are using > server-side state saving and want "GET" requests to show a fresh view of > the page even when the GET refers to the same view we recently rendered. Right. Exactly my case. > > Please note that the same doesn't hold when a page with <h:form> is > > invoked by a GET without parameters: it always gets a RESTORE_VIEW > > followed by a RENDER_RESPONSE cycle. > > I'm surprised by that; are you quite sure? Either the component tree can > be found or it can't, and a few random parameters aren't going to change > that... I confirm this behaviour. Maybe this is due to some kind of optimization in myfaces: when a get doesn't supply parameters, then it possibly can't be any (usefull) form submission. As written above, this may not cause problems to empty <h:form>s: they anyway get <hidden>s in them which must probably cause some kind of parameter values to be carried by a postback GET. > > Is there any way to circumvent this problem? Is the way myfaces > > handles GET with parameters a by-design behaviour? Is so, which is the > > purpouse? Is there a way (maybe by mean of some init param) to > > instruct facelets to handle GETs always with a RESTORE_VIEW and > > RENDER_RESPONSE cycle, and not as a form submission? > > > Our solution is a custom PhaseListener that checks the method property > of the request, and discards any component tree that may have been > retrieved during RESTORE_VIEW (thus forcing a jump to RENDER_RESPONSE). > > public void afterPhase(PhaseEvent event) { > if (event.getPhaseId().equals(PhaseId.RESTORE_VIEW)) { > // Never do a postback on GET request. > // Ideally this check would be done in > // before-restore-view, but JSF provides no way for > // code to skip the restore-view processing. We > // therefore need to let the normal restore-view > // take its course, then forcibly override the results > // here :-(. > FacesContext fc = event.getFacesContext(); > ExternalContext ec = fc.getExternalContext(); > HttpServletRequest hreq = (HttpServletRequest) > ec.getRequest(); > if (hreq.getMethod().equals("GET")) { > // discard UIViewRoot created during restoreView > // and use a new one > UIViewRoot viewRoot = fc.getViewRoot(); > String viewId = viewRoot.getViewId(); > UIViewRoot newView = > fc.getApplication(). > getViewHandler().createView(fc, viewId); > newView.setViewId(viewId); > fc.setViewRoot(newView); > fc.renderResponse(); > } > } > } > > Note that this code checks PhaseId==RESTORE_VIEW because our version of > this listener actually does several things, so is active for all phases. > If your version only returns RESTORE_VIEW as its active phase then this > check is not needed. Thank you very much for sharing your code with me: I didn't even know where starting "patch" jsf to fix my problem. I guess that jsf-1.2 attempts fixing the "is it a postback?" problem, since it defines a isPostback() getter in the ResponseStateManager class. I suspect this is done exactly to allow the renderkit to more precisely discriminate "show-the-page" requests from true postback ones. Even not implementing the full jsf-1.2 specs, I guess that myfaces should apply more effort in discriminating the two cases. Please note also that method org.apache.myfaces.shared_impl.renderkit.html.HtmlFormRendererBase.encodeBegin in myfaces-1.1.4 says: <snip> writer.startElement(HTML.FORM_ELEM, htmlForm); writer.writeAttribute(HTML.ID_ATTR, clientId, null); writer.writeAttribute(HTML.NAME_ATTR, clientId, null); writer.writeAttribute(HTML.METHOD_ATTR, "post", null); writer.writeURIAttribute(HTML.ACTION_ATTR, facesContext.getExternalContext().encodeActionURL(actionURL), null); </snip> Which means that every and each <h:form> in myfaces-1.1.4 is to be handled through a POST request. This may mean that every and each GET request may be seen as not being a postback, but it seems that myfaces-1.1.4 does not enforce this. Please see the following excerpt from the org.apache.myfaces.lifecycle.LifecycleImpl.execute method: <snip> if (facesContext.getExternalContext().getRequestParameterMap().isEmpty()) { //no POST or query parameters --> set render response flag facesContext.renderResponse(); } </snip> See? A GET is a postback if and only if it carries parameters (which is compatible with my experience about refreshing pages with no parameters). Even wider, a postback is as such irregardless of the carring method (POST or GET), which is compatible with what you told me about a JSF postback being carried by a GET, but which also seems not compatible with the specific myfaces-1.1.4 impl. of an html form. So, would it be possible to assert that, in the myfaces implementation, postbacks are handled only by POST (maybe non-empty) requests? What is supposed to be the payload of a postback GET when all the forms use POST methods instead? I don't have such a deep knowledge of the JSF framework to reply to this. > Cheers, > > Simon Thanks Simon. I really appreciate your help. Cheers dear, :) Giampaolo

