flash.keep & flash.setKeepMessages(true) on redirection - jsf

I am going through an example in Anghel Leonard book Mastering Java Server Faces 2.2.
The author demonstrates with an example on how preserve data for the next request on redirection when the bean is made is #RequestScoped.
This is the code for index.xhtml-
<h:body>
<f:metadata>
<f:event type="preRenderView"
listener="#{playersBean.pullValuesFromFlashAction}"/>
</f:metadata>
<h:messages />
<h:form>
Name: <h:inputText value="#{playersBean.playerName}"/>
Surname: <h:inputText value="#{playersBean.playerSurname}"/>
<h:commandButton value="Register"
action="#{playersBean.addValuesToFlashAction()}"/>
</h:form>
</h:body>
terms.xhtml-
<h:body>
<h:messages />
Hello, <h:outputText value="#{flash.keep.playerName} #{flash.keep.playerSurname}"/>
<br/><br/>Terms & Conditions ... ... ... ... ...
<h:form>
<h:commandButton value="Reject"
action="#{playersBean.termsRejectedAction()}" />
<h:commandButton value="Accept"
action="#{playersBean.termsAcceptedAction()}" />
</h:form>
</h:body>
done.xhtml-
<h:head>
<title></title>
</h:head>
<h:body>
<f:metadata>
<f:event type="preRenderView"
listener="#{playersBean.pullValuesFromFlashAction}"/>
</f:metadata>
<h:messages />
<h:outputText value="#{playersBean.playerName} #{playersBean.playerSurname}"/>
successfully registered!
</h:body>
And the backing bean-
#ManagedBean
#RequestScoped
public class PlayersBean {
private final static Logger logger = Logger.getLogger(PlayersBean.class.getName());
private String playerName;
private String playerSurname;
public PlayersBean() {
}
public String getPlayerName() {
return playerName;
}
public void setPlayerName(String playerName) {
this.playerName = playerName;
}
public String getPlayerSurname() {
return playerSurname;
}
public void setPlayerSurname(String playerSurname) {
this.playerSurname = playerSurname;
}
public String addValuesToFlashAction() {
Flash flash = FacesContext.getCurrentInstance().getExternalContext().getFlash();
flash.put("playerName", playerName);
flash.put("playerSurname", playerSurname);
return "terms?faces-redirect=true";
}
public void pullValuesFromFlashAction(ComponentSystemEvent e) {
Flash flash = FacesContext.getCurrentInstance().getExternalContext().getFlash();
playerName = (String) flash.get("playerName");
playerSurname = (String) flash.get("playerSurname");
}
public String termsAcceptedAction() {
Flash flash = FacesContext.getCurrentInstance().getExternalContext().getFlash();
flash.setKeepMessages(true);
pullValuesFromFlashAction(null);
//do something with firstName, lastName
logger.log(Level.INFO, "First name: {0}", playerName);
logger.log(Level.INFO, "Last name: {0}", playerSurname);
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Terms accepted and player registered!"));
return "done?faces-redirect=true";
}
public String termsRejectedAction() {
Flash flash = FacesContext.getCurrentInstance().getExternalContext().getFlash();
flash.setKeepMessages(true);
pullValuesFromFlashAction(null);
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Terms rejected! Player not registered!"));
return "index?faces-redirect=true";
}
}
I think there was no need for these 2 lines-
flash.setKeepMessages(true);
pullValuesFromFlashAction(null);
as flash.keep on terms.xhtml page serves the same purpose.
The author seems to be confused here.
Or am I completely wrong & they do definitely serves a purpose over here.

The code chosen by the author is a bit confusing, from my point of view, however, it does what it is intended to do.
flash.setKeepMessages(true);
This line tells JSF you want to keep the FacesMessage in the flash scope. That's a requirement when making a redirection, because more than one subsequent requests are involved and the messages would die from one request to another otherwise. The line is necessary.
pullValuesFromFlashAction(null);
The line does nothing special, just grabs the name and the surname from the flash scope. It's just right to call it from preRenderView to load bean data from the flash scope, but it's redundant to invoke it from the action methods (unless you want to do some logging to see parameters are properly set). Anyway, if you're starting with JSF I encourage you to use JSF 2.2 which has a parameterless replacement for the preRenderView methods, called viewAction.
Last but not least, I would recommend you going through an answer I made some time ago showing an example for dealing with the flash scope, you might find it interesting.
See also:
JSF Keep Messages docs
How to show faces message in the redirected page

Related

Composite Component inside ui:repeat: How to correctly save component state

I have a custom component that implements UIInput and that needs to save some state info for later reuse in postback requests. Used standalone it works fine, but inside an <ui:repeat> the postback finds the saved state of the latest rendered row of data. The log output of an action call is
INFORMATION: myData is "third foo"
INFORMATION: myData is "third foo"
INFORMATION: myData is "third foo"
INFORMATION: ok action
where I would expect
INFORMATION: myData is "first foo"
INFORMATION: myData is "second foo"
INFORMATION: myData is "third foo"
INFORMATION: ok action
I understand that myComponent is a single instance inside of ui:repeat. So what is the best way to save component state so it is restored correctly for each row in the dataset?
My XHTML form:
<h:form>
<ui:repeat var="s" value="#{myController.data}">
<my:myComponent data="#{s}"/>
</ui:repeat>
<h:commandButton action="#{myController.okAction}" value="ok">
<f:ajax execute="#form" render="#form"/>
</h:commandButton>
</h:form>
My Bean:
#Named
#ViewScoped
public class MyController implements Serializable {
private static final long serialVersionUID = -2916212210553809L;
private static final Logger LOG = Logger.getLogger(MyController.class.getName());
public List<String> getData() {
return Arrays.asList("first","second","third");
}
public void okAction() {
LOG.info("ok action");
}
}
Composite component XHTML code:
<ui:component xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:cc="http://xmlns.jcp.org/jsf/composite">
<cc:interface componentType="myComponent">
<cc:attribute name="data"/>
</cc:interface>
<cc:implementation>
<h:panelGrid columns="2">
<h:outputLabel value="cc.attrs.data"/>
<h:outputText value="#{cc.attrs.data}"/>
<h:outputLabel value="cc.myData"/>
<h:outputText value="#{cc.myData}"/>
</h:panelGrid>
</cc:implementation>
</ui:component>
Composite Component backing class:
#FacesComponent
public class MyComponent extends UIInput implements NamingContainer {
private static final Logger LOG=Logger.getLogger(MyComponent.class.getName());
public String calculateData() {
return String.format("%s foo", this.getAttributes().get("data") );
}
public String getMyData() {
return (String)getStateHelper().get("MYDATA");
}
public void setMyData( String data ) {
getStateHelper().put("MYDATA", data);
}
#Override
public String getFamily() {
return UINamingContainer.COMPONENT_FAMILY;
}
#Override
public void encodeBegin(FacesContext context) throws IOException {
this.setMyData( calculateData() );
super.encodeBegin(context);
}
#Override
public void processDecodes(FacesContext context) {
super.processDecodes(context);
LOG.log(Level.INFO, "myData {0}", getMyData() );
}
}
Just tried reproducing your issue and yes, now I get what you're after all. You just wanted to use the JSF component state as some sort of view scope for the calculated variables. I can understand that. The observed behavior is indeed unexpected.
In a nutshell, this is explained in this blog of Leonardo Uribe (MyFaces committer): JSF component state per row for datatables.
The reason behind this behavior is tags like h:dataTable or ui:repeat only save properties related with EditableValueHolder interface (value, submittedValue, localValueSet, valid). So, a common hack found to make it work correctly is extend your component from UIInput or use EditableValueHolder interface, and store the state you want to preserve per row inside "value" field.
[...]
Since JSF 2.1, UIData implementation has a new property called rowStatePreserved. Right now this property does not appear on facelets taglib documentation for h:dataTable, but on the javadoc for UIData there is. So the fix is very simple, just add rowStatePreserved="true" in your h:dataTable tag:
In the end, you have basically 3 options:
Use UIInput#value instead of something custom like MYDATA
As instructed by the abovementioned blog, just replace getMyData() and setMyData() by the existing getValue() and setValue() methods from UIInput. Your composite component already extends from it.
#Override
public void encodeBegin(FacesContext context) throws IOException {
this.setValue(calculateData()); // setValue instead of setMyData
super.encodeBegin(context);
}
#Override
public void processDecodes(FacesContext context) {
super.processDecodes(context);
LOG.log(Level.INFO, "myData {0}", getValue() ); // getValue instead of getMyData
}
And equivalently in the XHTML implementation (by the way, the <h:outputText> is unnecessary here):
<h:outputText value="#{cc.value}" /> <!-- cc.value instead of cc.myData -->
However, this didn't really work when I tried it on Mojarra 2.3.14. It turns out that Mojarra's implementation of the <ui:repeat> indeed restores the EditableValueHolder state during restore view (yay!), but then completely clears out it during decode (huh?), turning this a bit useless. I'm frankly not sure why it is doing that. I have also found in Mojarra's UIRepeat source code that it doesn't do that when it's nested in another UIData or UIRepeat. So the following little trick of putting it in another UIRepeat attempting to iterate over an empty string made it work:
<ui:repeat value="#{''}">
<ui:repeat value="#{myController.data}" var="s">
<my:myComponent data="#{s}" />
</ui:repeat>
</ui:repeat>
Remarkably is that nothing of this all worked in MyFaces 2.3.6. I haven't debugged it any further.
Replace <ui:repeat> by <h:dataTable rowStatePreserved="true">
As hinted in the abovementioned blog, this is indeed documented in UIData javadoc. Just replace <ui:repeat> by <h:dataTable> and explicitly set its rowStatePreserved attribute to true. You can just keep using your MYDATA attribute in the state.
<h:dataTable value="#{myController.data}" var="s" rowStatePreserved="true">
<h:column><my:myComponent data="#{s}" /></h:column>
</h:dataTable>
This worked for me in both Mojarra 2.3.14 and MyFaces 2.3.6.
This is unfortunately not supported on UIRepeat. So you'll have to live with a potentially unnecessary HTML <table> markup generated by the <h:dataTable>. It was during JSF 2.3 work however discussed once to add the functionality to UIRepeat, but unfortunately nothing was done before JSF 2.3 release.
Include getClientId() in state key
As suggested by Selaron in your question's comments, store the client ID along as key in the state.
public String getMyData() {
return (String) getStateHelper().get("MYDATA." + getClientId());
}
public void setMyData(String data) {
getStateHelper().put("MYDATA." + getClientId(), data);
}
Whilst it's a relatively trivial change, it's awkward. This does not infer portability at all. You'd have to hesitate and think twice every time you implement a new (composite) component property which should be saved in JSF state. You'd really expect JSF to automatically take care of this.

Can you set an Ajax response action to a PrimeFace component which's html is generated in a Bean?

Dear friendly strangers,
using PrimeFaces 7.0 on JSF 2.2 I'm generating html-Code in my Bean and inject it in my xhtml with <h:outputText value="#{myBean.myHtml}" escape="false"/>. This naturally doesn't work with <p:.../> components, as they themselves generate/render actual html. The way I alter the data from my Database to get the final html is too complicated for html functions though, so I still wanna do it in my Java-Beans instead of using lots of ui:repeat and hypercomplex custom styles - even though I know this is not how jsf/PrimeFaces is meant to be used. Now checking the actual rendered html e.g. of a p:commandLink it gives
<a id="myContainerID:myComponentID" href="#" class="ui-commandlink ui-widget" onclick="PrimeFaces.ab({s:"myContainerID:myComponentID",f:"myContainerID"});return false;">myComponentValue</a>
,which I can generate easily, but the response-action called when receiving the component's Ajax request (s:"myContainerID:myComponentID") will be missing, which seems to be saved somewhere in the moment the actual html is generated with <p:...>.
Is there a way to manually set that response-action, if so how/where?
EDIT: Since (quoting PrimeFaces.ab function)
//ajax shortcut
ab: function(cfg, ext) {
return PrimeFaces.ajax.AjaxRequest(cfg, ext);
}
The PrimeFaces.ajax.AjaxRequest can be asynchronous or synchronous. The AjaxRequest uses the AjaxUtils, which handles all
send, process, response, and update.
PrimeFaces.ajax.AjaxRequest = function(cfg, ext) {
cfg.ext = ext;
if(cfg.async) {
return PrimeFaces.ajax.AjaxUtils.send(cfg);
}
else {
return PrimeFaces.ajax.Queue.offer(cfg);
} }
I suppose the answer, if there is any, should lay somewhere in AjaxUtils, but couldn't find it yet.
Thanks helluvalot for any suggestion/help.
EDIT 2: I did eventually manage to transcribe it all to the xhtml with nested ui:repeats and lots of custom styles, I'm still curious though whether there's a way to do it with in-Bean-generated html.
ExampleCode
myBean:
#ManagedBean(name = "myBean")
#SessionScoped
public class myBean {
private String html1;
private String html2;
#PostConstruct
public void init() {
html1 = "<p:commandLink id=\"myComponentID\" value=\"myComponentValue\" "
+ "action=\"#{someBean.doSomething()}\"";
html2 = "<a id=\"myContainerID:myComponentID\" "
+ "href=\"#\" class=\"ui-commandlink ui-widget\" "
+ "onclick=\"PrimeFaces.ab({s:\"myContainerID:myComponentID\","
+ "f:\"myContainerID\"});"
+ "return false;\">1. myComponentValue</a>";
}
public String getHtml1() {
return html1;
}
public void setHtml1(String html1) {
this.html1 = html1;
}
public String getHtml2() {
return html2;
}
public void setHtml2(String html2) {
this.html2 = html2;
}
}
myIndex.xhtml:
<h:html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui"
>
<h:head>
</h:head>
<h:body>
<h:form id="myContainerID">
<h:outputText value="#{myBean.html1}" escape="false" />
<h:outputText value="#{myBean.html2}" escape="false" />
</h:form>
</h:body>
</h:html>

Local tc Server 3.1 instance ends #ViewScoped and #SessionScoped beans

UPDATE:
Any #ViewScoped and #SessionScoped beans' lifecycles are not what would be expected. That is, they are ending sooner than they should. For instance, when an ajax postback is done where the method returns void neither #ViewScoped or #SessionScoped beans should end, but they do.
After deploying it to our development environment and others testing it, it seems like it only occurs on my machine and when locally ran. No idea why. tc Server 3.1 is what is being used.
I'm leaving the original in case someone comes upon the issue similarly.
Original:
I have a tree that is populated by a ViewScoped that reads data from an XML file and creates TreeNode objects for it. Performance isn't super quick so it being created in the view once is ideal. (Some of the code has been omitted below, the functionality does work though)
#ManagedBean
#ViewScoped
public class FundsXmlTreeBuilder implements Serializable {
private TreeNode root;
public FundsXmlTreeBuilder() throws SAXException, IOException, ParserConfigurationException {
root = new DefaultTreeNode("Root", null);
buildTree();
}
public void buildTree() throws SAXException, IOException, ParserConfigurationException {
//reads xml file and adds TreeNodes
}
}
There is another RequestScoped bean that has a method that handles the ajax event of a tree node being selected in the onNodeSelect method. It basically determines how another part of the page will be shown.
#ManagedBean
#RequestScoped
public class FundsXmlDisplay implements Serializable{
private Fund fund;
private FundFamily fundFamily;
private FocusedPortfolioModel model;
public TreeNode selectedRoot;
public FundsXmlDisplay() {
fund = null;
fundFamily = null;
model = null;
selectedRoot = null;
}
public void onNodeSelect(NodeSelectEvent event) {
Object data = event.getTreeNode().getData();
fund = null;
fundFamily = null;
model = null;
if (data instanceof Fund) {
fund = (Fund) data;
} else if (data instanceof FundFamily) {
fundFamily = (FundFamily) data;
} else if (data instanceof FocusedPortfolioModel) {
model = (FocusedPortfolioModel) data;
model.createPieModel();
}
}
}
Here are the main portions of the markup.
<h:body>
<h:form styleClass="form" id="form1">
*** For Home Office Use Only
<br />
<p:layout id="xmlArea"
style="min-width:400px;min-height:600px;width:95%;">
<p:layoutUnit id="xmlTree" position="west" resizable="false"
closable="false" scrollable="true" size="25%" minSize="40"
maxSize="400" style="padding:.25em;" header="Funds XML Elements">
<p:tree value="#{fundsXmlTreeBuilder.root}" var="node"
dynamic="false" selectionMode="single">
<p:ajax event="select" update=":form1:xmlDisplay"
listener="#{fundsXmlDisplay.onNodeSelect}" />
<p:treeNode>
<h:outputText value="#{node}" style="font-size:small" />
</p:treeNode>
</p:tree>
</p:layoutUnit>
<p:layoutUnit position="center" header="Element Detail" size="75%">
<p:scrollPanel id="xmlDisplay" mode="native"
style="height:100%;">
...
</p:scrollPanel>
</p:layoutUnit>
</p:layout>
</h:form>
</h:body>
The issue I am having is that FundsXmlTreeBuilder is recreated after the ajax event is fired, but before the listener. I would expect it to not be recreated at all since, from what I understand, the view is not changing.
There are quite a few rendered attributes in the xmlDisplay area. Not sure if that is relevant. I understand that a view lives when an action method returns null or void, but I don't think the rendered methods being used count as "action methods".
What is also interesting, if I change FundsXmlTreebuilder to be SessionScoped it gets recreated after selecting a node too, which is really what has stumped me.
Hope everything is clear and enough information is given. Thanks!
In the web.xml, the <secure> tag needed to be commented out. So it the corresponding section looks like:
<session-config>
<session-timeout>60</session-timeout>
<cookie-config>
<http-only>true</http-only>
<!-- <secure>true</secure> --> <-- Not be set locally -->
</cookie-config>
<tracking-mode>COOKIE</tracking-mode>
</session-config>
This tag tells the browser to only send the cookie on HTTPS transmission, which I do not believe to be the case when ran locally.
This is where I found the explanation. A teammate discovered the fix.

navigation rule causes JSF1064: Unable to find or serve resource

I've the following xhtml page, that is wrapped in the major part of the other pages in my project:
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui">
<h:head>
<title></title>
</h:head>
<h:form>
<p:menubar>
<p:menuitem value="Home" url="/protected/personal/HomeCalendar.xhtml" icon="ui-icon-home"/>
<p:menuitem value="#{topbarBean.username}" url="#" style="text-decoration: underline" />
<f:facet name="options">
<p:inputText style="margin-right:20px" placeholder="Search" value="#{searchBean.searched}"/>
<p:commandButton action="#{searchBean.search()}" type="submit" icon="ui-icon-search" />
</f:facet>
</p:menubar>
</h:form>
</ui:composition>
This is the navigation rule that I've wrote:
<navigation-rule>
<from-view-id>/Components/TopBar.xhtml</from-view-id>
<navigation-case>
<from-action>#{searchBean.search()}</from-action>
<from-outcome>searchingResults</from-outcome>
<to-view-id>/protected/SearchResults.xhtml</to-view-id>
</navigation-case>
</navigation-rule>
and this the referred Bean:
#RequestScoped
#ManagedBean
public class SearchBean implements Serializable {
private String searched;
private final String resultsOutcome = "searchingResults";
private List<User> users;
private List<Event> events;
#EJB
UserFacade uf;
#EJB
UserManager um;
#EJB
EventFacade ev;
#PostConstruct
public void init(){
try {
setEvents(um.getEventsVisibilityMasked(um.getLoggedUser().getId()));
}
catch (NotFoundException ex) {
Logger.getLogger(SearchBean.class.getName()).log(Level.SEVERE, null, ex);
}
}
public void setSearched(String searched) {
this.searched = searched;
}
public String getSearched() {
return searched;
}
public void search() {
FacesContext fc = FacesContext.getCurrentInstance();
fc.getApplication().getNavigationHandler().handleNavigation(fc, null, resultsOutcome);
}
public List<User> getUsers(){
return users;
}
public void setUsers(List<User> users){
for(User user:users)
this.users.add(user);
}
public List<Event> getEvents(){
return events;
}
public void setEvents(List<Event> events){
for(Event event:events)
this.events.add(event);
}
}
The error is the following one:
JSF1064: Unable to find or serve resource, /protected/personal/searchingResults.xhtml.
This path is not specified anywhere, if it could be helpful I've the following structure :
-Index,xhtml
-Web Pages { components , protected}
-components{TopBar.xhtml}
-protected {event,persona,user,SearchResults.xhtml}
-event{eventCreate,eventPage,eventEdit}
-personal{HomeCalendar,ManageSettings,ManageInvitations}
I don't understand if the problem regards the navigation-rule or the next xhtml page.
That can happen if JSF can't find the matching navigation rule. It'll then switch to implicit navigation. I.e. the outcome will be used as the actual view ID, relative to the current context.
Apparently the current view ID is sitting somewhere in /protected/personal. An outcome of searchingResults which doesn't match any navigation rule will then trigger an implicit navigation to /protected/personal/searchingResults.xhtml.
You've 2 options:
Fix the current view ID. The <from-view-id>/Components/TopBar.xhtml</from-view-id> is apparently wrong. You can find out the right one as follows:
System.out.println(FacesContext.getCurrentInstance().getViewRoot().getViewId());
It's usually the one matching the context-relative URI in browser's address bar as long as you don't use POST for page-to-page navigation. Use this value in <from-view-id>.
Get rid of navigation cases altogether and rely on implicit navigation. Remove the <navigation-case> altogether from faces-config.xml and change the outcome value and action method as below:
private final String resultsOutcome = "/protected/SearchResults.xhtml";
public String search() {
return resultsOutcome;
}
The NavigationHandler approach was also quite clumsy. Even with navigation cases, just return the outcome outright instead of fiddling with NavigationHandler.
See also:
Communication in JSF 2 - Implicit Navigation
What is the difference between redirect and navigation/forward and when to use what?
Differences between action and actionListener

why i get null parameter value?

I have problem with parameter at my web application. At some page (index.xhtml) i have:
...
<f:metadata>
<f:viewParam name="backurl"/>
</f:metadata>
<h:form>
<h:outputLabel value="backurl: #{backurl}"/>
<h:commandButton image="/resources/graphics/poland.gif" action="#{userController.setLanguage('pl', param['backurl'])}"/>
</h:form>
setLanguage() method in userController managed bean:
public void setLanguage(String language, String backurl) {
setLang(new Locale(language));
...
}
when i run application and go to index.xhtml page i see backurl: /pages/login.xhtml
but at setLanguage method second parametr (backurl) is null when i click and debug application
Where is problem ?
why dont you use this?
<h:commandButton action="#{userController.setLanguage}">
<f:param name="param1" value="value1" />
<f:param name="backurl" value="#{backurl}" />
</h:commandButton>
and then in your method
public String setLanguage() {
Map<String,String> params =
FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap();
String param1= params.get("param1");
String backurl= params.get("backurl");
}
#{userController.setLanguage('pl', backurl)}
this should work. (didn't test it)
there are many ways to pass parameters to a backing bean. Here is a useful article
You can store the view-param value in the managed-bean (provide accessors for the introduced backurl member, also).
<f:metadata>
<f:viewParam name="backurl" value="#{userController.backurl}" />
</f:metadata>
And then you can get rid of the second method parameter and get the backurl value from the variable in the managed-bean.
action="#{userController.setLanguage('pl')}"/>
The managed bean should look like this:
public class UserController {
private String backurl;
public String getBackurl() { return backurl; }
public void setBackurl(String backurl) { this.backurl = backurl; }
public void setLanguage(String language) {
setLocale(new Locale(language));
System.out.println(backurl); //this refers the variable in the managed-bean
}
}

Resources