How to exit a flow? - jsf

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.

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
}

Set current displayed tab programmatically in p:wizard

Is it possible to set current displayed tab programmatically in <p:wizard>?
For example, I want that for two different request to the same page which contains a wizard, to have a different tab selected.
What I am currently trying to do, is to have a wizard with many tabs, in the second tab I have a redirection to another page, so when I come back I want to come to the last step which caused the redirection.
Can you please help me ? Thank you a lot !
According to primefaces documentation there's a step attribute for p:wizard tag, which specifies the step of the wizard you're currently in.
attribute: step
default value: 0
type: String
description: Id of the current step in flow
You must bind this attribute to a value of your backing bean and maintain it during redirection and coming back. If your wizard's bean is #ViewScoped you'll loose that info during redirection step, so you have to pass it using a view param or flash scope.
My answer would most probably not meet your complete requirements, but, nonetheless, it may point you towards solution to your problem.
As far as I know, the PrimeFaces Wizard UIComponent is designed for a workflow of one page. That effectively means that inputs will be handled by a backing beans that is in a view scope.
This way, making a redirection on a certain step will clear all data inputs, because your view changes and the old one is destroyed.
Anyway, a means of setting a current tab for display is step attribute of Wizard component. So,
<p:wizard step="#{wizardBean.currentStep}" >...</p:wizard>
will force the wizard to show you step which you specified in your bean. You may be able to get it by using, for example, a view parameter, like in
<f:viewParam name="step" value="#{wizardBean.currentStep}" />
But it will make sense if lifetime of your bean is more that for a view, for example, the bean could be put in session scope.
That said, maybe it is a better idea to do login beforehand. Or, if it is absolutely necessary to do it in step 2 of your wizard, provide for a built-in login functionality in a page itself, or in a popular window?
Also, programmatically the setting you speak of can be achieved via a binding of component to your backing bean and setting the step value in the backing bean, for example, in a preRenderView event.

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.

JSF page navigation failing with NullPointerException

I wrote two pages...one a form where data submitted and second just to confirm the transaction actually carried out some calculation.
I have a managed bean i.e. FormDataBean and a class Reservation.java from which i instantiate for each booking made. Now I have at the end of a form a submit button:
<h:commandButton value="Submit" action="confirmation"/>
in the bean I have setters and getters as usual. in a method i defined I create an instance of Reservation, then set the beans variables to the instance variabels, like
reservation.startDate = startDate;
reservation.endDate = endDate;
reservation.checkRange();
The last method, i.e. checkRange() will use the assigned values to instance variables to carry calculation. it should return a string successful or failure.
Now when I enter data in the form, and press submit, it just refreshes the page but nothing is submitted. because it doesn't go to next page :(
Any idea what is happening? I don't need to define a navigation rule, because in other project, I carry out simple calculation and display result in next page and it worsks! Please advice
Thanks,
Your are missing to tell us some of the more important details so the answer is a kind of guesswork.
As you don't use navigation rules I assume you are using JSF 2, aren't you?
With JSF 2 you can directly set the new navigation target, without navigation rules. A forward to "confirmation" should work if your outcome file is named confirmation.xhtml. Check that. With a navigation rule you could forward it do a different file.
This part should work regardless of the rest.
For the bean not getting any values make sure that you are using the correct scope either through annotation or entry in your faces-config.xml. As you have a quite unusal validation mechanism you probably have to use the session scope.
The correct way would be using an actionlistener that does your checks and then sets the navigation depending on your checks. The bean scope could be more restrictive then.
Did you try action="confirmation?faces-redirect=true"?

Resources