This question already has an answer here:
#SessionScoped bean looses scope and gets recreated all the time, fields become null
(1 answer)
Closed 8 years ago.
Using PrimeFaces 5.10, JSF 2, and Wildfly, I am trying to get my xhtml page to interact with a single instance of a #SessionScoped bean with a PF poll component. Each time the poll calls the bean method, a new instance of the bean is created. I've tried #ViewScoped and #SessionScoped with no change in behavior. I've noticed other similar questions, but have not seen any with a solution I have been able to implement.
I know the println's are not a reliable way to show order of method calls, but i'm using them to merely demonstrate which methods are being called and it appears that the init() method gets called over and over, even though I have #PostConstruct, so it's new instantiations. I'm even printing out "this" and it's showing different hashes each time it prints.
It never gets through the if statement in refreshTweets() because the stopPolling field never gets set to false in the right context.
I've run into this problem before and have been able to work around it rather than solve it. If anyone has any ideas as to what I am doing wrong, please let me know.
Below is the relevant xhtml code:
<p:layoutUnit id="center" position="center" styleClass="dataBox">
<h:form id="TwitterFeed">
<p:panelGrid columns="2">
<p:outputLabel value="Twitter topic to query: " />
<p:inputText value="#{dataBean.tweetTopic}"/>
<p:outputLabel value="Number of Twitter Results: " />
<p:inputText value="#{dataBean.tweetCount}" />
<p:commandButton value="Submit" action="#{dataBean.toggleRenderTweets}" update="tweets"/>
<p:commandButton value="Polling" action="#{dataBean.togglePolling}" update="tweets"/>
</p:panelGrid>
<p:panel visible="#{dataBean.renderTweets}" id="tweets">
<p:panelGrid columns="1">
<p:dataTable id="twitterTable" value="#{dataBean.tweetList}" var="tweetStatus">
<p:columns value="#{dataBean.tweetColumns}" var="column" columnIndexVar="colIndex">
<f:facet name="header">
<h:outputText value="#{column.header}"/>
</f:facet>
<h:outputText value="#{tweetStatus[column.property]}"/>
</p:columns>
</p:dataTable>
<p:poll interval="10" listener="#{dataBean.refreshTweets}" update="twitterTable" widgetVar="tweetPoll" id="tweetPoll" autoStart="true"/>
</p:panelGrid>
</p:panel>
</h:form>
</p:layoutUnit>
The relevant bean code is below:
import javax.enterprise.context.SessionScoped;
import javax.faces.bean.ManagedBean;
import javax.annotation.PostConstruct;
import java.io.Serializable;
#SessionScoped
#ManagedBean
public class DataBean implements Serializable {
private List<TwitterStatusModel> tweetList;
private boolean renderTweets;
private boolean stopPolling;
#PostConstruct
public void init() {
<<initialize fields>>
stopPolling = true;
System.out.println(this + " init()");
}
private void getTweets() {
<<this method sets the List above tweetList>>
}
public void refreshTweets() {
if (!stopPolling) {
<<Method never passes the if statement because stopPolling is set to true in init()
}
public void togglePolling() {
stopPolling = !(stopPolling);
System.out.println(this + "Toggling polling - now " + stopPolling);
}
You should use the correct imports of #SessionScoped etc.
With a #ManagedBean you need the javax.faces.bean.* ones not the javax.enterprise.context ones or javax.faces.view
See also Why are there different bean management annotations
Related
I have a common task to choose one or more 'LocalizacaoTO' before doing anything else on the page.
Currently the logic of data retrieval/process/ajax events and so on are maintained on a ViewScoped bean called "SeletorLocalizacaoMB" and I’d like to use multiple instances of the same bean on the same page.
Firstly I used composite component but when I chose a node, it were stored on the last bean on the page.
If I had 3 instances declared on TesteSeletorMB:
#Named
#ViewScoped
public class TesteSeletorMB implements Serializable {
#Inject
#Getter #Setter
private SeletorLocalizacaoMB instanceOne;
#Inject
#Getter #Setter
private SeletorLocalizacaoMB instanceTwo;
#Inject
#Getter #Setter
private SeletorLocalizacaoMB instanceThree;
}
No matter which component on page I used, instanceThree always hold the values.
Based on some research I understood that composite component is not the ideal solution for this problem.
So I changed the UI implementation and used Facelets to create a 'template' named seletor.xhtml.
<ui:composition 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:c="http://java.sun.com/jsp/jstl/core"
xmlns:p="http://primefaces.org/ui"
xmlns:o="http://omnifaces.org/ui">
<p:dialog header="Busca Hierarquica"
id="#{id}ModalTree"
widgetVar="dlgSelecaoHierarquica"
showEffect="fade"
hideEffect="fade"
closeOnEscape="true"
modal="#{bloqueiaModal}"
height="400px"
width="500px">
<h:panelGrid columns="2">
<p:commandButton id="#{id}btnSelecao"
value="Selecionar e Voltar"
action="#{mb['selecionarLocalHierarquico']}"
update="#(.#{id}-auto-complete)"
oncomplete="bloqueiaAutoMulti();"/>
<p:commandButton value="Voltar"
type="button"
onclick="PF('dlgSelecaoHierarquica').hide();" />
</h:panelGrid>
<p:scrollPanel style="width:100%;height:350;" mode="native">
<p:tree id="#{id}Tree"
style="width:100%;height:100%;"
styleClass="estilo-arvore"
value="#{mb.arvoreHierarquica}"
var="local"
selectionMode="multiple"
dynamic="true"
animate="true">
<p:ajax event="select" listener="#{mb['onNodeSelect']}" update="#this"/>
<p:treeNode >
<h:outputText value="#{local.cdClasseLocal}: #{local.cdLocalizacao} #{local.niveis}" />
</p:treeNode>
</p:tree>
</p:scrollPanel>
</p:dialog>
</ui:composition>
Test page using <ui:include>
<f:subview id="seletorAlpha">
<ui:include src="/template/seletor.xhtml">
<ui:param name="mb" value="#{testeSeletorMB.seletorAlpha}" />
<ui:param name="id" value="alpha" />
</ui:include>
</f:subview>
<f:subview id="seletorBravo">
<ui:include src="/template/seletor.xhtml">
<ui:param name="mb" value="#{testeSeletorMB.seletorBravo}" />
<ui:param name="id" value="bravo" />
</ui:include>
</f:subview>
Test Bean holding multiple instances:
import javax.inject.Named;
import org.omnifaces.cdi.ViewScoped;
#Named
#ViewScoped
public class TesteSeletorMB implements Serializable {
#Inject
#Getter #Setter
private SeletorLocalizacaoMB seletorAlpha;
#Inject
#Getter #Setter
private SeletorLocalizacaoMB seletorBravo;
}
CDI Bean used on 'seletor.xhtml'
import javax.inject.Named;
import org.omnifaces.cdi.ViewScoped;
#Named
#ViewScoped
public class SeletorLocalizacaoMB implements Serializable {
private List<LocalizacaoTO> locaisHierarquicosSelecionados;
private TreeNode arvoreHierarquica;
//PostConstruct, Ajax events and things :)
}
In my example, I want that TesteSeletorMB variables (seletorAlpha and seletorBravo) hold different values on their lists. Is it possible?
I tried to change SeletorLocalizacaoMB scoped to #Dependent but it didn't work neither. Here is where the things got confused. Reading CDI API, the first state says:
Beans declared with scope #Dependent behave differently to beans with other >built-in scope types. When a bean is declared to have scope #Dependent:
No injected instance of the bean is ever shared between multiple injection >points.
It should't hold the same instance, right?!
Environment
WebSphere Application Server 8.5.5.2
Apache MyFaces 2.0.2
PrimeFaces 5.0
OmniFaces 1.7
I can provide additional data if necessary. I didn't paste all 'SeletorLocalizacaoMB' code because it has many dependencies and I had the feeling that the problem is not related to how the class handles actions.
Here is my code,
search.xhtml page
<h:form id="searchform">
<h:inputText id="deptId" value="#{searchBean.departmentId}"></h:inputText>
<h:inputText id="deptName" value="#{searchBean.deparmentName}"></h:inputText>
<h:commandButton value="Click to Search" action="#{searchBean.searchEmployees}">
</h:commandButton>
</h:form>
searchresults.xhtml page
<rich:dataTable value="#{searchBean.employeeList}" var="e" id="table">
<rich:column>
<f:facet name="header">
<h:outputText value="FNAME"/>
</f:facet>
<h:outputText value="#{e.fName}"/>
</rich:column>
<rich:column>
<f:facet name="header">
<h:outputText value="LNAME"/>
</f:facet>
<h:outputText value="#{e.lName}"/>
</rich:column>
<rich:column>
<f:facet name="header">
<h:outputText value="DEPARTMENT"/>
</f:facet>
<h:outputText value="#{e.dept}"/>
</rich:column>
</rich:dataTable>
In the managed bean
ManagedBean
#ManagedBean(name="searchBean")
#RequestScoped
public class SearchBean implements Serializable{
private String departmentId;
private String deparmentName;
private List<EmpBean> employeeList;
//....get/set 's
public String searchEmployees(){
employeeList = service.getEmployees(departmentId,deparmentName);
return "searchresults.xhtml";
}
Issue: searchresults page is is not displaying records though it fetched records from table
I'm able to achieve this using search bean as session scope but i want to use the scope as Requestscope, bec of performance.
Please suggest...!
The Problem
The reason you're not seeing the results is because you have an incorrect understanding of the #RequestScope and consequently, improbable expectations of the scope
searchEmployees executes during the INVOKE_APPLICATION phase, the second to the last phase of the JSF request processing lifecycle. By the time the user is redirected to searchResults.xhtml, the instance of your SearchBean that holds the search results has been destroyed and a brand new one created, resulting in an empty list.
This is the rule for every bean scope except the #SessionScoped: a navigation action will cause the old bean to be destroyed and a new one created. This is not to say that #SessionScoped should be your scope of choice (it's generally a terrible idea to back a page with a #SessionScoped bean).
The Solution
Use the FlashScope to temporarily stash the results just for display on the other page. For example
employeeList = service.getEmployees(departmentId,deparmentName);
Flash theFlashScope = FacesContext.getCurrentInstance().getExternalContext().getFlash();
theFlashScope.put("searchResults",employeeList);
return "searchresults.xhtml";
Then in searchResults.xhtml
<rich:dataTable value="#{flash.searchResults}" var="e" id="table">
Here, #{flash} is an implicit EL object; you don't have to do anything else.
EDIT: Based on your "answer", you should be aware that the Flash object keeps variables stored in it for only the first render of the page. Subsequent HTTP requests will clear the content of the flash object.
If you're interested in keeping the content of the flash object beyond the first render, you should use the Flash#keep:
<rich:dataTable value="#{flash.keep.searchResults}" var="e" id="table">
Further Reading
Max Katz's blog on the Flash object
This question already has answers here:
Adding <h:form> causes java.lang.IllegalStateException: Cannot create a session after the response has been committed
(5 answers)
Closed 7 years ago.
I get this error when I click on a p:commandButton in my page
java.lang.IllegalStateException: PWC3999: Cannot create a session
after the response has been committed
The button is in an h:form and looks like this:
<p:commandButton value="Save" action="#{discussionManager.save}" ajax="false"/>
But an h:commandButton works fine:
<h:commandButton value="Save" action="#{discussionManager.save}"/> (this works)
This is the bean with the method in it
#Named
#RequestScoped
public class DiscussionManager {
private static final Logger logger = Logger.getLogger("DiscussionManager");
#Inject
private DiscussionDao discussionDao;
private Discussion discussion = new Discussion();
#Produces
#Named
#RequestScoped
public Discussion getDiscussion() {
return discussion;
}
public String save() {
logger.info("Hello");
discussionDao.create(discussion);
return "list";
}
}
I've waited all day before posting this question because I feel like I should know how to get this working. But I've read and re-read my book, and loads of other posts. I just don't understand why it's not working.
I can't comment on your final answer so I have to add another answer. I believe what you did to make your example work was to add widgetVar to your editor component. I had this problem as well. The example on the PrimeFaces Demo wouldn't work properly until I added the widgetVar line. You need to reference the widgetVar name in your onclick call rather than the id. I use different names between the id and widgetVar for clarity so I would change your editor code to:
<h3>Write your message below</h3>
<p:editor id="editorID"
value="#{discussion.message}"
widgetVar="editorWidget"
width="600"
required="true"/>
<h:message for="editor"/>
<h:panelGrid columns="2" style="margin-top:10px">
<p:commandButton id="submitButton" value="Save" action="#{discussionManager.save}" ajax="false" icon="ui-icon-disk"/>
<p:commandButton id="clearButton" type="button" value="Clear" onclick="editorWidget.clear()" icon="ui-icon-close" />
</h:panelGrid>
I hope that helps clarify.
I suspect that it is because the bean goes out of scope. When you turn off ajax it submits the form and you are actually dealing with a new request. Try expanding your scope to a view scope.
Not quite sure what I changed to get it working, because now the whole thing is working fine. But for completeness, here's the relevant part of my page
<h3>Write your message below</h3>
<p:editor id="editor"
value="#{discussion.message}"
widgetVar="editor"
width="600"
required="true"/>
<h:message for="editor"/>
<h:panelGrid columns="2" style="margin-top:10px">
<p:commandButton id="submitButton" value="Save" action="#{discussionManager.save}" ajax="false" icon="ui-icon-disk"/>
<p:commandButton id="clearButton" type="button" value="Clear" onclick="editor.clear()" icon="ui-icon-close" />
</h:panelGrid>
And here's my bean. Hope someone finds this useful...
#Named
#RequestScoped
public class DiscussionManager implements Serializable {
private static final Logger logger = Logger.getLogger("DiscussionManager");
#Inject
private DiscussionDao discussionDao;
private Discussion discussion = new Discussion();
#Produces
#Named
#RequestScoped
public Discussion getDiscussion() {
return discussion;
}
public String save() {
logger.info("Hello");
discussionDao.create(discussion);
return "list";
}
}
i m using JSF2.0 and i m making one dataTable in that datatable i m getting the value from managed bean.And in managed bean in post construct annoted method i m calling my web service from another file.
Following is code for that
<h:dataTable
value="#{bean1.getList}" var="c" styleClass="order-table"
headerClass="order-table-header" width="100%"
rowClasses="order-table-odd-row,order-table-even-row" rows="8"
columnClasses="first,second">
<h:column>
<f:facet name="header">
<h:selectBooleanCheckbox></h:selectBooleanCheckbox>
</f:facet>
<h:selectBooleanCheckbox value="#{c.id}"></h:selectBooleanCheckbox>
</h:column>
<h:column>
<!-- <f:facet name="header"/> -->
<h:outputLabel value="From: "></h:outputLabel>
<h:outputLabel value="#{c.from}"></h:outputLabel>
<br></br>
<!-- -->
<h:outputLabel value="Sub: "></h:outputLabel>
<h:outputLabel value="#{c.sub}"/>
<h:commandLink immediate="true" action="#{bean2.doRead}" value="Read" id="Read"></h:commandLink>
</h:column>
<!-- Footer Setting -->
<f:facet name="footer">
</f:facet>
</h:dataTable>
My Bean1 class
#PostConstruct
public void prepareList(){
{
web service call
}
public List<InboxBean> getemailList(){
return list;
}
Now when i m clicking on commandlink which has id Read at that time my bean1 post construct taged property also called. That i dont want to perform. So,how to get out from this problem and i also want to set the subject value in bean2 setProperty. Thanks in advance
That can happen if the bean is put in request scope. Every single HTTP request will then reconstruct the bean. Put the bean in view or session scope instead.
E.g. in the view scope:
#ManagedBean
#ViewScoped
public class Bean {}
A view scoped bean lives as long as you're interacting with the same view by returning null or void in action methods.
Or in the session scope:
#ManagedBean
#SessionScoped
public class Bean {}
A session scoped bean lives as long as the established browser session. That is, from the very first HTTP request involving the bean until the client closes the entire browser instance or when the session expires on the server side (which defaults to 30 minutes).
For your particular case, a view scoped bean is most likely the best choice.
See also:
How to choose the right bean scope?
What I'm trying to achieve is very similar to the one posted in the following link.
How to save an array in JSF with ui:repeat + h:inputText + managed bean?
I'm particularly fascinated with the answer provided by Arjan Tijms in the link above however what I want to achieve is slightly different. Consider the following code snippets.
The bean
import javax.annotation.PostConstruct;
import javax.inject.Named;
import javax.enterprise.context.RequestScoped;
#RequestScoped
#Named
public class MyBean {
List<String> choices;
public List<String> getChoices() {
return choices;
}
#PostConstruct
public void initChoices() {
choices= new ArrayList<String>();
}
public String save() {
// should save all the choices into some repository
return "";
}
}
and the facelet page
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h:body>
<h:form>
<ui:repeat value="#{myBean.choices}" varStatus="status">
<h:inputText value="#{myBean.choices[status.index]}" />
</ui:repeat>
<h:commandButton value="Save" action="#{myBean.save}" />
</h:form>
</h:body>
</html>
The thing is, this will work if we have some initial data in the list at the beginning. What about situations where the initial list will be empty?
The ideal solution which I'm looking for is to have 1 h:inputText for each choice and when save button is clicked, all choices in each h:inputText is then added to the choices list. I've searched high and low but can't seem to find any hints on how this can be done.
If JSF 2 really doesn't support this, I guess I'll have to use the ugly way with just one h:inputText and use a converter to convert to and from a list but I'm still hoping that an ideal solution can be found.
Hopefully someone from stackoverflow can shed a light in the right direction for me.
Just add an "add" button which adds a new String to the list.
<ui:repeat value="#{myBean.choices}" varStatus="status">
<h:inputText value="#{myBean.choices[status.index]}" />
</ui:repeat>
<h:inputText value="#{myBean.newChoice}" />
<h:commandButton value="Add" action="#{myBean.add}" />
<h:commandButton value="Save" action="#{myBean.save}" />
with
private String newChoice;
public void add() {
choices.add(newChoice);
newChoice = null;
}
// ...
Note that this only works if bean is put in view scope. A request scoped one would be constructed on every request and hereby recreate the list everytime.