Pure Java/JSF implementation for double submit prevention - jsf

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
}

Related

jsf get disabled field values in requestscoped bean

Could you please give me some directions on how to pass values from disabled or readonly input fields in xhtml page to requestscoped bean?
I thought that I can bypass jsf checking the field state by disabling
fields in javascipt code on form open and then submit form, but that
did not help too.
I cannot use view scope, because I would have to set then almost
every page in my application in view scope.
It is very inconvenient to use hidden fields for this purpose,
because it would double the number of fields on the page.
Maybe I have missed some clean solution?
Thank you in advance for any help.
Disabling fields using JavaScript didn't work probably because you didn't enable them just before sending a form. Values of disabled fields are not sent (see input documentation).
For example the following code works perfectly well:
<h:form>
<h:inputText id="disabledinput" styleClass="disabled"
value="#{someBean.property}"></h:inputText>
<h:outputScript>
$('.disabled').attr('disabled', 'disabled');
</h:outputScript>
<h:commandButton action="#{someBean.action}"
onclick="$('.disabled').removeAttr('disabled'); return true;"
value="Submit" />
</h:form>
onclick attribute executes JavaScript code that enables input just before sending the form.
If you use AJAX request you have to restore disabled state using oncomplete or similar.
The problem with this solution is that user can manipulate the value. E.g. she/he can use javascript console in a browser to change the input to enabled or use some tool (e.g. curl) to prepare or tamper request. So if the value is sensitive or should never be changed by the user consider storing the value in the session.
IMHO if the value was provided by the user in one of the previous steps then it doesn't matter that much. However, if value is calculated (like total value or something) you should not depend on its value as users could change it. Personally I would prefer to store the value on server side (in session or in flash).

best practice for communicating between two beans that back the same page

We are making the transition to bootstrap pages. As part of this, we are making most of our dialogs into simple include files that get rendered on demand. The include files have their own backing bean to minimize code duplication.
The typical use case is when a user enters a page a datatable shows a list of things. The user selects one or more rows in the table and then clicks a button to perform an action. The page is re-rendered using ajax. The datatable is not displayed but the former dialog is. The user then does whatever bulk operation the former dialog does and clicks execute (or cancel). The page is then re-rendered with the datatable showing and the former dialog box not.
The problem here is simple; how do you set the render flags on the datatable and former dialog box? Each of the beans needs to set the render flag of the other bean. I blithely tried injecting each bean into the other and promptly got a circular injection error at runtime. I've gone to having a callback interface that the datatable beans implement. When the former dialog bean gets injected, the datatable bean sets itself up to be called back. This works but I am not sure it's the best way to do it. Being an old swing programmer, I considered using property change listeners, which are much more robust than the simple interface, but I'm not sure what the implications of using them in a managed bean environment are. I did check out the messaging API but it clearly doesn't apply to this case.
So, what's the best way for two view beans that are backing the same page to talk to each other?

How to exit a flow?

Once I've entered a Faces Flow, I want to exit it by going to any page that is not part of the flow.
The problem is that the flow is not destroyed if I go outside, for example via an h:link.
Indeed, if I click again on a h:commandButton whose action is the flowId, I go back to the previous flow instead of creating a new flow.
How to exit a flow without having the user to click explicitly on a h:commandButton whose action corresponds to the return node of the flow ?
Is it even possible ?
Edit:
Let's take this flow for example (from the JEE 7 samples)
#Produces #FlowDefinition
public Flow defineFlow(#FlowBuilderParameter FlowBuilder flowBuilder) {
String flowId = "flow1";
flowBuilder.id("", flowId);
flowBuilder.viewNode(flowId, "/" + flowId + "/" + flowId + ".xhtml").markAsStartNode();
flowBuilder.returnNode("taskFlowReturn1").
fromOutcome("#{flow1Bean.returnValue}");
flowBuilder.returnNode("goHome").
fromOutcome("#{flow1Bean.homeValue}");
flowBuilder.inboundParameter("param1FromFlow2", "#{flowScope.param1Value}");
flowBuilder.inboundParameter("param2FromFlow2", "#{flowScope.param2Value}");
flowBuilder.flowCallNode("call2").flowReference("", "flow2").
outboundParameter("param1FromFlow1", "param1 flow1 value").
outboundParameter("param2FromFlow1", "param2 flow1 value");
return flowBuilder.getFlow();
}
The flow will be terminated if the user clicks on
<h:commandButton id="index" value="home" action="goHome" />
or
<h:commandButton id="return" value="return" action="taskFlowReturn1" />
But what if the user clicks on
<h:link outcome="someOutcomeUnrelatedToTheFlow"/>
Or if the user changes the url in the browser, without removing the jfwid? It seems the flow isn't terminated but the user is actually browsing outside of the flow.
That seems a bit odd to me: I can't find any way to exit the flow (and release the backing beans) without a specific action from the user on a commandButton/commandLink.
Btw: I'm testing this on WildFly 8 CR1.
You are right. In the current version, the spec requires to navigate using UICommand components to determine if the flow is exited or not. However, this is not sufficient for any decent usage scenario where navigation happens using GET.
Notwithstanding the specs conceptual gap, a solution may be implemented and I expect to see one in upcoming versions of JSF libraries (actually, OmniFaces is a good bet, as BalusC and Arjan focus on fixing stuff that was left out in the spec ;-) ).
Technically speaking, a solution may look like this: The jfwid param is already added when h:linkor h:button is used. So a PhaseListener could be used to end the current flow if a view outside of the flows definition is requested. However, this is just a basic idea and there may be stumbling blocks which I did not consider yet.
So, to provide an answer to your question: Currently the only correct way to exit a flow is to either navigate to an exit node or to use h:commandLinkor h:commandButton for page navigation as this will also end a flow when a view outside of the flows definition is requested.

Dealing with Back Button and Resulting Phase_ID

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?

How to handle multiple submits before response is rendered?

It has been reported from testing that it is occasionally possible to press a button more than once if the response is not rendered fast enough, causing several invocations of the back-end code, which we do not want.
Application is Java EE 6 Web Profile using JSF 2.0 inside Glassfish 3.1.1.
I was wondering how this should be properly dealt with, and have thought of a few scenarios:
Submitting should disable all buttons using javascript while response is being rendered.
A flag in the Session scope saying it is already active, so the sensitive code is skipped and just moves on to the re-rendering of the response for the previous submit.
A synchronized block delaying the processing until the previous request have finished. Then it should be detected that it has been already processed and skipped.
Using one of the "new" scopes like conversion to handle the detection?
My immediate gut feeling is that the best approach is to have sensitive code blocks atomic, but then the problem is with rendering the correct response.
How should I approach this?
Submitting should disable all buttons using javascript while response is being rendered.
This is the easiest to implement in a generic manner. If you happen to use <f:ajax> exclusively, you could use the jsf.ajax.addOnEvent() to perform the job in a generic manner. An alternative JavaScript approach is to create kind of an "Loading" overlay which blocks the UI so that the enduser won't be able to interact with the underlying page anymore. This is basically an absolutely positioned hidden <div> which spans the entire viewport with some opacity (transparency). You could show it on submit and hide it on render. The keyword for this technique is "modal dialog". UI-oriented JSF component libraries have at least such a component already in their assortiment. E.g. PrimeFaces with a <p:dialog modal="true"> inside a <p:ajaxStatus>, or the <p:blockUI>
The only disadvantage is that it won't work if the client has JS disabled or don't use it and it thus won't prevent HTTP clients from double submits.
A flag in the Session scope saying it is already active, so the sensitive code is skipped and just moves on to the re-rendering of the response for the previous submit.
This is more known as "synchronizer token pattern" and has ever been requested for JSF by spec issue 559 which is currently on the ticket targeted for 2.2, but there doesn't seem to be any activity on it. The detection and blocking part is technically easy to implement, but the synchronous response handling part is not easy to implement if you want that the enduser ultimately retrieves the response as generated by the initial request. The asynchronous response handling is easy: just don't specify any components to update, i.e. empty the collection as returned by PartialViewContext#getRenderIds(). After all, this is more robust than using JS to disable the buttons or block the UI.
As far as I know, Seam 2 was the only who offered a reuseable JSF component for this, the <s:token>. I must however admit that this is an interesting idea for a new OmniFaces component. Maybe I will personally take a look at it.
A synchronized block delaying the processing until the previous request have finished. Then it should be detected that it has been already processed and skipped.
This is not easy to implement generically, this would require a change in all action methods to check if the job is already done. It also won't work if the webapp runs on multiple servers. A synchronizer token is easier as it would be performed before the action methods are invoked. A synchronizer token is also less expensive as you don't end up with multiple requests in the queue which would only cost threads/resources.
Using one of the "new" scopes like conversion to handle the detection?
This problem cannot be solved by playing around with managed bean scopes. Managed bean scopes serve a different purpose: the lifetime of the bean instance.
As Adrian mentioned, I would also use BlockUI. There is a BlockUI component from Primefaces. When you submit your forms through ajax, you could also use an overlay during the request. See Primefaces`s Ajax Status for an example.

Resources