Refreshing a JSF/PrimeFaces interface from the backing Bean - jsf

My goal is to display a text on a web page, with JSF and/or PrimeFaces. The text is updated in real time by a process on the server side.
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui">
<h:body>
<f:view id="view">
<f:event type="preRenderView" listener="#{MyBean.init}"/>
<h:form>
<p:outputLabel id="output" value="#{MyBean.text}"/>
</h:form>
</f:view>
</h:body>
</html>
My backing bean maps the text to p:outputLabel. I also added to the bean a method foo() that modifies the text. This method is called by another process running in the background (it holds a pointer to the bean).
#ManagedBean(name="MyBean")
#SessionScoped
public class MyBean {
private String text = "text";
public void init() {
MyOtherClass.getPointer(this);
}
public String getText() {
return text;
}
public String foo(String s) {
text = text + s;
// ...and refresh ?
}
}
What I cannot do so far, is to update/refresh the view automatically each time the text is updated. The best I could do is to let the user manually refresh the web page, or to use p:poll to refresh at regular intervals.
I have researched this, and I have found very similar threads; the answer is usually to use FacesContext.getCurrentInstance() (JSF) or RequestContext.getCurrentInstance() (PrimeFaces) to access the component and refresh it. I tried, but the context is not available in foo().
I guess it's a lifecycle issue. I have a very limited knowledge of JSF. Any help is appreciated.

You can't access a faces context from a bean when it is updated from a non jsf backend call. Use PrimeFaces push for this.

Related

How many state information is saved when client mode

How to define the max number of component trees in client mode? How to prevent calling #PostConstruct method?
I'm developing an application by JavaEE7 with glassfish 4.1.
If I remember correctly, when javax.faces.STATE_SAVING_METHOD is client, there is no limit of component tree.
But when I opened more than 25 tabs in Chrome and operate the first tab, that tab's managed bean will construct and call #PostConstruct method.
I think this behavior seems losing component tree to me.
The following is source code of my application.
test.xhtml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition
template="/template/template.xhtml"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
>
<h:panelGrid columns="5" cellpadding="5" >
<p:commandButton id="returnButton" value="return"
action="#{testEditBean.return()}"
immediate="true"
/>
</h:panelGrid>
</ui:composition>
testBean.java
import java.io.Serializable;
import javax.annotation.PostConstruct;
import javax.faces.view.ViewScoped;
import javax.inject.Named;
#Named(value = "testBean")
#ViewScoped
public class TestBean implements Serializable {
#PostConstruct
public void index() {
}
public String doReturn() {
String ret = "/content/tmp/testSearch.xhtml";
return ret;
}
}
[postscript 2016/01/28]
I understand that a HTTP session stored view scoped beans (max 25) and view state only stored component tree.
This is my new question.
Unless we change mojjara 2.x to another JSF implementation, we couldn't open more than 25tabs?
"more than 25 tabs" contains this case that "an user open 2 tabs, and 23 transition occur in 2nd tab."

commandButton actionListener is not working in PrimeFaces page with viewParam

I found a weird behavior in JSF/PrimeFaces and ask your help to understand and get around it. The actionListener method in a commandButton is executed just once.
Contextualization:
I put a link in start page of my project to a second page, renderized as follows:
http://localhost:8080/MeusTestes-war/faces/somepage.xhtml?id=1
Notice there is a parameter sent by query string.
The somepage.xhtml:
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:p="http://primefaces.org/ui">
<h:head>
<title>Facelet Title</title>
</h:head>
<f:metadata>
<f:viewParam name="id" value="#{someBean.id}" required="true" />
<f:viewAction action="#{someBean.init}" />
</f:metadata>
<h:body>
<h:form id="form1">
<p:commandButton id="teste1"
value="Teste"
actionListener="#{someBean.doTeste}" />
</h:form>
</h:body>
</html>
As you can see, its extremely simple. Notice there is a metadata section doing the parameter reception and the execution of init() method. In page body there is a p:commandButton and a actionListener pointing to doTeste().
There is my Bean:
#Named(value = "someBean")
#ViewScoped
public class SomeBean implements Serializable {
private int id;
public SomeBean() {
}
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public void init() {
System.out.println("init " + id);
}
public void doTeste(ActionEvent actionEvent) {
System.out.println("doTeste " + id);
}
}
Well, now the mysterious behavior:
1) When page is loaded, as expected, the init() method shows a message with the correct property value got by viewParam.
2) Firing the button, as expected too, the doTeste() method shows a message with the correct property value.
However,
3) Firing the button again, nothing happens!
Other facts:
If I remove the metadata section the doTeste() method is executed as many times as the button is clicked, which is supposed to happen. But the property, obviously, is not initialized.
If I switch the button definition from p:commandButton to h:commandButton, the doTeste() method is executed as expected AND the property is initialized. But I lose the PrimeFaces pattern.
My question:
How to do the commandButton actionListener from PrimeFaces behave the way is expected? (executing the method each time it is fired)
Thanks!
If you for testing purposes add a <p:growl id="msgs"/> and add update="msgs" to the button you'll see that validation fails on subsequent requests (because of required="true" on the viewParam).
So you can either
remove required="true". Probably a bad idea since you need it.
add the parameter to the commandButton with <f:param name="id" value="#{someBean.id}"/>
use OmniFaces <o:viewParam>.
There is a more technical explanation here.

JSF 2.2: viewAction triggers earlier than actionListener and action

I have been using preRenderView (+ the re-direct and skip postback hacks) in my app and I'm trying to replace it with viewAction that comes with JSF2.2 (MyFaces 2.2.4). However I found it triggers earlier than command actionListener and action that it's rather useless for my purpose. For example:
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
#ManagedBean
#ViewScoped
public class TestBean2 implements Serializable {
int count = 0;
public void actionFunc() {
System.out.println(count);
}
public String addCount() {
count++;
return null;
}
public int getCount() {
return count;
}
public void initView() {
System.out.println("initView");
}
public void setCount(int count) {
this.count = count;
}
}
and then a very simple .xhtml:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core" xmlns:pt="http://xmlns.jcp.org/jsf/passthrough" xmlns:jsf="http://xmlns.jcp.org/jsf"
xmlns:t="http://myfaces.apache.org/tomahawk" xmlns:p="http://primefaces.org/ui">
<f:metadata>
<f:event type="preRenderView" listener="#{testBean2.initView}" />
<f:viewAction action="#{testBean2.actionFunc}" onPostback="true" />
</f:metadata>
<ui:composition template="/WEB-INF/template.xhtml">
<ui:define name="title">Test</ui:define>
<ui:define name="content">
#{testBean2.count}
<h:form>
<h:commandButton styleClass="btn btn-primary" action="#{testBean2.addCount}" value="addCount">
</h:commandButton>
</h:form>
</ui:define>
</ui:composition>
</html>
So the addCount() System.out output is always 1 behind what's on the rendered view, because actionFunc() always triggers before addCount().
If I want to do something like, if (count == 3) do a return "newpage" for a redirect, it ends up way too early for such decision. I can do the check in initView() and do ConfigurableNavigationHandler.performNavigation("newpage"), but that's the kind of hack I'm trying to eliminate with JSF 2.2.
Therefore, it seems like viewAction is rather useless if I want it to work with any value that I'm going to change with action or actionListener. Is it supposed to work like this?
Thanks!
preRenderView event is executed at the beginning of the RENDER_RESPONSE phase. However, the viewAction tag does not allow that phase. I suppose that in your case you should handle the redirection in your action method (TestBean2#addCount) and forget about using events, cause it makes no sense at all to perform a check over a value that has been just initialized (that's what you do with the preRenderView method, when you load the view at first time). Checking it into the action method, after having performed your logic, seems the natural way for it.
I believe events can be used to check conditions as well, but they have more to do with session and application states and not with your current view values. I mean, you could do this to handle a redirection when no items available in your shop, before your view gets rendered:
public String checkItemsAvailable() {
if (!dao.itemsAvailable()){
return "noItemsAvailable";
}
return null;
}
But for a redirection based in a condition that's being evaluated in your current view, performing it in the action method is the best way to go:
public void addCount() {
count++;
if (count>3){
FacesContext.getCurrentInstance()
.getExternalContext().redirect("index.xhtml");
}
}
See also:
f:viewAction documentation

JSF index.xhtml and redirect to faces action

I think its a good practice to have an index page (in my case index.xhtml).
I want to pass some action on index page (for example in struts:<c:redirect url="list.do" /> and I go to struts action class without any links and buttons) I know if I want to use navigation I should use commandLink-s or buttons). I can write <h:commandButton> with onclick javascript function, but I don't feel this is the best option.
I'm totally new to JSF (using JSF 2.0) and I need your advice. What are the best practices for redirecting from index page to an action in controller?
///new version
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
<f:view>
<ui:insert name="metadata"/>
<f:viewParam name="action" value="listItems.xtml"/>
<f:event type="preRenderView" listener="#{yourBean.methodInManagedBean}" />
<h:body></h:body>
</f:view>
</html>
public class ForwardBean {
private String action;
// getter, setter
public void navigate(PhaseEvent event) {
FacesContext facesContext = FacesContext.getCurrentInstance();
String outcome = action;
facesContext.getApplication().getNavigationHandler().handleNavigation(facesContext, null, outcome);
}
}
You can use JSF preRenderView event to redirect to another page in following manner,
In your index.xhtml file
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
<f:view>
<ui:insert name="metadata"/>
<f:event type="preRenderView" listener="#{yourBean.methodInManagedBean}" />
<h:body></h:body>
</f:view>
</html>
In managed bean,
1st way is
public class yourClass{
FacesContext fc = FacesContext.getCurrentInstance();
ConfigurableNavigationHandler nav = (ConfigurableNavigationHandler)fc.getApplication().getNavigationHandler();
public void methodInManagedBean() throws IOException {
nav.performNavigation("list.do");//add your URL here, instead of list.do
}
}
or you can use 2nd way
public class yourClass{
public void methodInManagedBean() throws IOException {
FacesContext.getCurrentInstance().getExternalContext().redirect("list.do");//add your URL here, instead of list.do
}
}

jsf viewparam lost after validation error [duplicate]

This question already has answers here:
Retaining GET request query string parameters on JSF form submit
(2 answers)
Closed 6 years ago.
I'm facing the following issue: in one page, I list all users of my application and have an "edit" button for each one, which is a "GET" link with ?id=<userid>.
The edit page has a <f:viewParam name="id" value="#{editUserBean.id}"/> in metadata.
If I made some input mistakes and submit (I use CDI Weld Bean validation), the page is displayed again, but I've lost the ?id=... in the URL and so lose the user id of the user I'm editing.
I've looked at a similar problem described in JSF validation error, lost value, but the solution with inputhidden (or worse, with tomahawk, which looks overkill) requires lot of uggly code.
I've tried adding a "Conversation" with CDI, and it is working, but it looks like too much overkill to me again.
Does there exists a simple solution in JSF to preserve view parameters in case of validation errors?
[My environment: Tomcat7 + MyFaces 2.1.0 + Hibernate Validator 4.2.0 + CDI(Weld) 1.1.2]
Interesting case. For everyone, the following minimal code reproduces this:
Facelet:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
>
<f:metadata>
<f:viewParam id="id" name="id" value="#{viewParamBean.id}"/>
</f:metadata>
<h:body>
<h:messages />
#{viewParamBean.id} <br/>
<h:form>
<h:inputText value="#{viewParamBean.text}" >
<f:validateLength minimum="2"/>
</h:inputText>
<h:commandButton value="test" action="#{viewParamBean.actionMethod}"/>
</h:form>
</h:body>
</html>
Bean:
#ManagedBean
#RequestScoped
public class ViewParamBean {
private long id;
private String text;
public void actionMethod() {
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
}
If you call the Facelet with viewparam.xhtml?id=12 it will display the 12 onscreen. If you then input something valid, e.g. aaaaa, the id will disappear from the URL, but keeps being displayed on screen (owning to the stateful nature of ui components).
However... as OP mentioned, as soon as any validator error occurs (e.g. entering a), the id will be permanently lost. Entering valid input afterwards will not bring it back. It almost seems like a bug, but I tried both Mojarra 2.1 and Myfaces 2.1 and both have the same behavior.
Update:
After some inspection, the problem seems to be in this method of `UIViewParameter' (Mojarra):
public void encodeAll(FacesContext context) throws IOException {
if (context == null) {
throw new NullPointerException();
}
// if there is a value expression, update view parameter w/ latest value after render
// QUESTION is it okay that a null string value may be suppressing the view parameter value?
// ANSWER: I'm not sure.
setSubmittedValue(getStringValue(context));
}
And then more specifically this method:
public String getStringValue(FacesContext context) {
String result = null;
if (hasValueExpression()) {
result = getStringValueFromModel(context);
} else {
result = (null != rawValue) ? rawValue : (String) getValue();
}
return result;
}
Because hasValueExpression() is true, it will try to get the value from the model (the backing bean). But since this bean was request scoped it will not have any value for this request, since validation has just failed and thus no value has ever been set. In effect, the stateful value of UIViewParameter is overwritten by whatever the backing bean returns as a default (typically null, but it depends on your bean of course).
One workaround is to make your bean #ViewScoped, which is often a better scope anyway (I assume you use the parameter to get a user from a Service, and it's perhaps unnecessary to do that over and over again at every postback).
Another alternative is to create your own version of UIViewParameter that doesn't try to get the value from the model if validation has failed (as basically all other UIInput components do).
You don't actually loose the view parameter. f:viewParam is stateful, so even if it's not in the URL, it's still there. Just put a break point or system.out in the setter bound to view param.
(if you google on viewParam stateless stateful you'll find some more info)
I've the same in my Application. I switched to #ViewAccessScoped which allows way more elegant implementations.
<f:metadata>
<f:viewParam id="id" name="id" value="#{baen.id}"/>
</f:metadata>
Or when you the first time get parameter from url, save it in session map and continue use from that map, and after save/or update the form clean map.
This is tricky, but you can try to restore view parameters with History API:
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
<f:metadata >
<f:viewParam name="param1" value="#{backingBean.viewParam1}" />
<f:viewParam name="param2" value="#{backingBean.viewParam2}" />
<f:viewAction action="#{view.viewMap.put('queryString', request.queryString)}" />
</f:metadata>
<h:head>
<title>Facelet Title</title>
</h:head>
<h:body>
<ui:fragment rendered="#{facesContext.postback}" >
<script type="text/javascript">
var url = '?#{view.viewMap.get('queryString')}';
history.replaceState({}, document.title, url);
</script>
</ui:fragment>
<h:form>
<h:inputText id="name" value="#{backingBean.name}" />
<h:message for="name" style="color: red" />
<br />
<h:commandButton value="go" action="#{backingBean.go}" />
</h:form>
<h:messages globalOnly="true" />
</h:body>
</html>

Resources