Dealing with Back Button and Resulting Phase_ID - jsf

I'm in the following situation:
JSF (MyFaces 2.1.7 and RichFaces 3.3.3)
A session Scoped Bean TEST_PAGE
Users who will use BACK button to no end
State Saving on Server
Scenario:
User click a link to navigate to page with Session Scoped bean (TEST_PAGE)
User clicks another link
User presses back button of brwoser which puts them back in TEST_PAGE
User Tries to Search in this page
On search the backing bean throws exceptions since there are many null values. Reason being is that when they pressed "Search", the page is in RESTORE_VIEW phase.
I tried disabling caching on the page, to force user to refresh the page on back button, but backlash caused by many users complaining "why can't I use back button, I could do it before!" and resulted in Help Desk Tickets since they think the application is crashing on "Confirm Form Resubmission" page chrome/IE/Firefox show, hence managers want me to look for alternatives.
My questions:
It is possible to detect the current Phase_ID of RESTORE_VIEW and not do any processing in this phase to avoid the exceptions, but that alone and just retuning gives user a partial page view. Is it possible to put the page in RENDER_RESPONSE in this scenario and do the processing then? This should refresh the page.
Question Part 2
Since the recommendation (or common/good) practive is to disable cache on dynamic pages i have done so and will have to re-educate the stubborn users.
However i have the following issue.
When pressing Back button on a page with disabled cache, the browser shows the "Confirm Form Resubmission" (chrome) where users either can press Refresh / F5 or Enter key.
If Refresh/ F5 is the action, everything is ok where i detect RESTORE_VIEW phase and avoid any processing in that PHASE and let the processing be done in RENDER_RESPONSE phase. However if Enter is pressed, The PhaseID is in RENDER_RESPONSE(6) but values of few drop-down controls is null which causes the page to fail. So i put in checks to detect such conditions and show a FaceMessage to tell the user to Refresh the page.
Question is, Can i force the page to Refresh instead of forcing the user to do it? The Navigation case for this page is in format:
<navigation-rule>
<navigation-case>
<from-outcome>/app/ord/r1</from-outcome>
<to-view-id>/jsp/ordersHistory.jsp</to-view-id>
</navigation-case>
</navigation-rule>
I've seen code snippets online where faces-redirect=true is used to force reload a page but i couldn't get that to work! Any suggestions?

Disabling the browser cache on dynamic pages is the way to go.
As to the new problems caused after this, this is likely caused by poor webapp design. Redesign your webapp to use GET instead of POST for plain vanilla page-to-page navigation (i.e. use just <h:link> or <h:outputLink> instead of <h:commandLink>). Implement the POST-Redirect-GET pattern for POST requests which needs to send the response to a different page, or change them to return to the same page and conditionally show the results, if possible by ajax. Check if some forms can't better be GET forms (for example, search forms like Google). Rethink if that bean really needs to be a session scoped one, you usually use the session scope for logged-in user and its preferences only, not for request or view scoped data.
See also:
When should I use h:outputLink instead of h:commandLink?
How to choose the right bean scope?
How to avoid re-execution of last form submit action when the page is refreshed?
Is JSF 2.0 View Scope back-button safe?

Related

Pure Java/JSF implementation for double submit prevention

We're using JSF 2.0 on WebSphere v8.5 with several component libraries PrimeFaces 4.0, Tomahawk 2.0, RichFaces, etc.
I am looking for generic mechanism to avoid form re-submission when the page is refreshed, or when the submit button is clicked once again. I have many applications with different scenarios.
For now I have considered disabling the button with a piece of JavaScript in onclick attribute, but this is not satisfying. I'm looking for a pure Java implementation for this purpose, something like the Struts2 <s:token>.
I am looking for generic mechanism to avoid form re-submission when the page is refreshed
For that there are at least 2 solutions which can not be combined:
Perform a redirect after synchronous post. This way the refresh would only re-execute the redirected GET request instead of the initial request. Disadvantage: you can't make use of the request scope anymore to provide any feedback to the enduser. JSF 2.0 has solved this by offering the new flash scope. See also How to show faces message in the redirected page.
Perform the POST asynchronously in the background (using ajax). This way the refresh would only re-execute the initial GET request which opened the form. You only need to make sure that those forms are initially opened by a GET request only, i.e. you should never perform page-to-page navigation by POST (which is at its own already a bad design anyway). See also When should I use h:outputLink instead of h:commandLink?
or when the submit button is clicked once again
For that there are basically also at least 2 solutions, which could if necessary be combined:
Just block the enduser from being able to press the submit button during the submit and/or after successful submit. There are various ways for this, all depending on the concrete functional and design requirements. You can use JavaScript to disable the button during submit. You can use JSF's disabled or rendered attributes to disable or hide the button after submit. See also How to do double-click prevention in JSF 2. You can also use an overlay window during processing ajax requests to block any enduser interaction. PrimeFaces has <p:blockUI> for the purpose.
Validate uniqueness of the newly added entity in the server side. This is way much more robust if you absolutely want to avoid duplication for technical reasons rather than for functional reasons. It's fairly simple: put a UNIQUE constraint on the DB column in question. If this constraint is violated, then the DB (and DB interaction framework like JPA) will throw a constraint violation exception. This is best to be done in combination with a custom JSF validator which validates the input beforehand by performing a SELECT on exactly that column and checking if no record is returned. A JSF validator allows you to display the problem in flavor of a friendly faces message. See also among others Validate email format and uniqueness against DB.
Instead of creating a token manually, you can use BalusC' solution. He proposed a Post-Redirect-GET pattern in his blog
Alternative solutions can be found in these answers:
Simple flow management in Post-Redirect-Get pattern
How can Flash scope help in implementing the PostRedirectGet (PRG) pattern in JSF2.0
<!--Tag to show message given by bean class -->
<p:growl id="messages" />
<h:form>
<h:inputText a:placeholder="Enter Parent Organization Id" id="parent_org_id" value="#{orgMaster.parentOrganization}" requiredMessage="Parent org-id is required" />
<h:commandButton style="margin-bottom:8px;margin-top:5px;" class="btn btn-success btn-block " value="Save" type="submit" action="#{orgMaster.save}" onclick="resetform()" />
</h:form>
public String save() {
FacesContext context = FacesContext.getCurrentInstance();
context.getExternalContext().getFlash().setKeepMessages(true); //This keeps the message even on reloading of page
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "Your submission is successful.", " ")); // To show the message on clicking of submit button
return "organizationMaster?faces-redirect=true"; // to reload the page with resetting of all fields of the form.. here my page name is organizationMaster...you can write the name of form whose firlds you want to reset on submission
}

ViewScope beans behaves like it has application scope

I am doing work on a project using primefaces 3.5 and my problem is that...
I have a search form I enter some criteria in the form and press Search Button...Result is displayed...suppose using FireFox
Now If I open application same page in some other browser suppose IE there I will see the form with same values and same search result returned earlier...even this is a new session
More over suppose in the same browser if I logout and then login and navigate to same page I see the search form with same values and same result returned.
More or less this behavior is close to application scope Beans where as I have not any application scope Bean and have only one Bean with session scope for login purpose...rest of the beans are #ViewScoped
If I use #Scope("request")...Bean is created on each request but in this case I am unable to set parameter to the confirm dialog for deleting the record because when i click on dialog delete button previous values gets nullified due to new request.
I am in great difficulty and have done too much workaround but all in vain....

Saving a view in JSF

Im having a question regarding retrieving the view state of a JSF page.
I have an application in which the user is able to search for persons in a
list and when the user press "show" button the same JSF page will be filled
with a list of the various persons.
Now when I choose one of the persons , another JSF page will show up with more
in-depth and detailed information about that person. Now in that page there is a
"cancel/abort" button displayed. What I want to accomplish is that when I press
that specific "cancel/abort" button the page should be redirected and navigate
back to the JSF page with the list as it was shown, so in some way the "view state"
should be stored (I assume only) but I dont know how it could be done...
I just wanted to check if anyone has been able to solve this kind of issue
in some manner.. ? (The JSF search page as mentioned above is declared as a viewscoped as
an additional information)
Thanks for all help..
You could make the bean #SessionScoped. That means that only one instance will be created by browser session, so when you get back you get the last state.
Of course, session scoped means that when you get back to the view even if it is not a "back" navigation, that info will still be there.

Populating a page from Data table in modal panel

I'm trying to get some data from a datatable in rich:modal panel
The whole flow is as follows
When clicking on search button on main page, a modal panel pops up with appropriate data & check box
Till this point the application is working fine
After clicking on ok button, selected data should be populated into main page. This is where the code fails
I tried stuff like getRowData, getValues, etc. but in vain. This could be done by keeping the bean in session scope but I have to keep this bean in request scope using Apache MyFaces JSF 1.2
Two ways comes to mind:
Pass an extra request parameter (the search string and the page number?) so that the bean knows which data to preload.
Make use of MyFaces Orchestra to create a conversation scope which lies in between request and session scope and is exactly the scope you're looking for this particular functional requirement.

Avoiding creating the same object twice on refresh in JSF

Say we have an "add new object" form in AddObject.jspx, and a Confirm.jsp page (saying something like object with id NN was added to the database...)
in faces-config.xml:
<navigation-rule>
<from-view-id>/AddObject.jsp</from-view-id>
<navigation-case>
<from-outcome>add</from-outcome>
<to-view-id>/Confirm.jsp</to-view-id>
</navigation-case>
</navigation-rule>
So the user opens AddObject.jsp, fills out the form, and clicks the 'add' button that triggers an event handler in the AddObject's backing bean. The backing bean inserts the new object into the database and returns the "add" outcome. So we end up in the Confirm screen.
Now if I hit F5 (refresh the browser) a new object will be created and the Confirm screen redisplayed with the new ID of the new object. I can keep hitting F5 and get as many new objects as I'd like.
I don't want this. I want to detect such situations. Avoid adding the same object many times over (generating many rows in the database that differ only by ID).
Can I do this with JSF? Why does it ask me for from-view-id/outcome/to-view-id if it doesn't seem to make any good use of this information?
There are two parts to this problem.
First, you need to avoid having the broswer's refresh of the confirm page resubmit the request. So one approach if for the brower's history not to say
POST this request
and instead say
GET this confirmation page
We cam do that by using the
<redirect/>
statement in the JSF navigation. Now this means that a redirect response is sent to the Browser. The browser then ask JSF for the conformation page. NOTE: this is now a new request from JSF's perspective, so any data you want to display needs to be at session scope not request scope.
This "Use a redirect for actions that make changes" approach is quite a common idiom. However it doesn't address the "Quick Fire User" problem. What would happen if the user hit the "Submit" twice very rapidly? You can get to a situation where the browser has sent two requests. There are other scenarios where this can happen - network glitch on the first request, user gets impatient, sends the request again.
So we need somehow to handle such double submissions. This is not a JSF-specific problem. A typical solution is for the backend to send a token when the original request page is populated. This is held in a hidden field. When the request is submitted that token (some unique number) is sent back to the application which records that it has been used, hence a double submission is detected.
You can also use JavaScript in the browser to prevent double submission. This should give a friendlier user experience but I would not recommend relying only on Browser-side control. The server should have ultimate respsonbility.

Resources