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

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.

Related

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

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

#ConversationScoped bean reconstructed during page-to-page navigation

I just found a strange behavior when I change from one page to another.
I'm using CDI, Jsf 2.2 API 2.2.8, Omnifaces 2.2, Primefaces 5.2, wildfly 8.2.
Most of the controllers and pages work as expected, but some of them, when I access the page, call the method #PostConstruct, which starts the conversation, then, when I leave the page, the #PostConstruct is called again. I realized that something in page.xhtml is the cause, so I started to look for it. But is a strange behaviour anyway.
Following my code and some examples:
Controller which uses abstract class methos like beginconversation() and list()
import javax.inject.Named;
import javax.enterprise.context.ConversationScoped;
#Named
#ConversationScoped
public class PromptConfigurationController extends BaseController<PromptConfiguration> implements Serializable {
public PromptConfigurationController() {
super(PromptConfiguration.class);
}
#PostConstruct
public void init() {
list();
loadFilters();
}
}
Abstract class
public abstract class BaseController<T extends BaseEntity> {
public void list() {
logger.info("list()");
items = getService().findAll(entityClass);
item = null;
beginConversation();
}
protected void beginConversation() {
logger.info("beginConversation()");
if (conversation != null && conversation.isTransient()) {
conversation.begin();
conversation.setTimeout(CONVERSATION_TIMEOUT);
logger.info("Conversation iniciada: " + conversation.getId());
}
}
}
some xhtml pages which I found problem and the solution (when I found) was:
Error:
<f:convertDateTime pattern="#{webChatSearchController.dateHelper.getLocalizedDatePattern()}" />
The method above just return a pattern.
Working
<f:convertDateTime dateStyle="dd/MM/yyyy" pattern="dd/MM/yyyy" />
Error:
<p:commandButton id="commandButton-active" action="#{satisfactionSurveyController.changeQuestionStatus(true)}" update="form-content" binding="#{satisfactionSurveyController.activeButton}" value="#{bundle['common.active.3.message']}">
Working:
<p:commandButton id="commandButton-active" action="#{satisfactionSurveyController.changeQuestionStatus(true)}" update="form-content" value="#{bundle['common.active.3.message']}" disabled="#{satisfactionSurveyController.disableActiveButton}">
The problem was just the "binding".
Error:
<p:dataTable id="dataTable-group-email" var="emailMonitor" value="#{emailMonitorController.listEmailGroup}" selectionMode="single" rowKey="#{emailMonitor}" filteredValue="#{emailMonitorController.listEmailGroupFiltered}">
Working:
<p:dataTable id="dataTable-group-email" var="emailMonitor" value="#{emailMonitorController.listEmailGroup}" selectionMode="single" rowKey="#{emailMonitor}" >
Just removing 'filteredValue' started working. But without it, I can't use the filter properties.
The navigation is made by a menu of primefaces, all the pages are the same logic:
<p:menuitem id="satisfactionSurvey" action="#{satisfactionSurveyController.listPage}" value="#{bundle[satisfactionSurvey.message']}" ajax="false" immediate="true">
<f:param name="nocid" value="true" />
</p:menuitem>
and the Method:
public String listPage() {
return baseViewPath + "/list.xhtml?faces-redirect=true";
}

A potential method invoking after a POST (basically Ajaxical) request finishes

While performing CRUD operations using JSF/PrimeFaces, a common method that resets managed bean fields/properties is generally needed which is to be invoked basically after one such operation is successfully completed so that the fields in the backing bean are reset to their initial (default) value.
Imaginary code :
#Named
#ViewScoped
public class Bean extends LazyDataModel<Entity> implements Serializable {
#Inject
private Service service; // EJB.
// Holds a list of selected rows in a <p:dataTable>.
private List<Entity> selectedValues; // Getter & setter.
private String someField; // Getter & setter.
// Other fields depending upon the business requirement.
public Bean() {}
#PostConstruct
private void init() {
// Do something.
}
#Override
public List<Entity> load(int first, int pageSize, List<SortMeta> multiSortMeta, Map<String, Object> filters) {
setRowCount(service.rowCount());
// Other complex logic as and when required.
return service.getList(first, pageSize, map, filters); // Returns a List<Entity>.
}
// Resets fields to their default value.
public void reset() {
someField = null;
selectedValues = null;
// Reset other fields to their default value.
}
// Add (insert submitted values to the database).
// This method is basically bound to an action(Listener) of <p:commandButton>.
public void submit() {
if (service.insert(someField)) {
// Add a FacesMessge to indicate a success.
reset(); // Calling reset.
} else {
// Add a FacesMessge to indicate a failure.
}
}
// Update the database using submitted values.
public void onRowEdit(RowEditEvent event) {
if (event.getObject() instanceof Entity) {
Entity entity = (Entity) event.getObject();
Entity newEntity = service.update(entity);
if (newEntity != null) {
// Update the model.
// Other things like adding a FacesMessage to indicate a success.
} else {
// Add a FacesMessage to warn against the null entity returned by the service layer.
}
} else {
// Add a FacesMessage to indicate a failure.
}
reset(); // Finally reset the fields to their initial/default value.
}
// Similarly, performing the delete operation also requires to call the reset() method.
}
The submit() method performing "insert" is basically associated with JSF/PrimeFaces command components like <p/h:commandButton> or <p/h:commandLink>. Such as.
<p:inputText value="#{bean.someField}"/>
<p:commandButton value="Submit"
actionListener="#{bean.submit}"
oncomplete="if(args && !args.validationFailed) {updateTable();}"/>
<!-- Updating a p:dataTable in question after the above p:commandButton completes. -->
<p:remoteCommand name="updateTable" update="dataTable" process="#this"/>
The following AJAX events associated with a <p:dataTable> also require to call the reset() method.
<p:ajax event="rowEdit"
onstart="..."
oncomplete="..."
update="..."
listener="#{bean.onRowEdit}"/>
<p:ajax event="rowEditCancel"
onstart="..."
oncomplete="..."
update="..."
listener="#{bean.reset}"/>
<p:ajax event="page"
onstart="..."
oncomplete="..."
update="..."
listener="#{bean.reset}"/>
<p:ajax event="sort"
onstart="..."
oncomplete="..."
update="..."
listener="#{bean.reset}"/>
<p:ajax event="filter"
onstart="..."
oncomplete="..."
update="..."
listener="#{bean.reset}"/>
As can be seen, the reset() method needs to be memorized carefully as it is invoked from several places. The way is somewhat difficult to maintain.
Does there exist a way to invoke such a common method automatically after each POST request performing one of the CRUD operations has finished its job successfully?
JSF doesn't have any tag for this.
Ideally, you'd like to have something like a <f:event type="postInvokeAction" listener="#{bean.reset}"> directly attached to the <p:dataTable>. But that event doesn't exist in JSF 2.2. OmniFaces has one, but it's only supported on UIViewRoot, UIForm, UIInput and UICommand.
The <f:phaseListener> comes close, but it gets attached to UIViewRoot directly, even though you place it inside <p:dataTable>. And, it requires a whole PhaseListener implementation.
The <f:view afterPhase> seems your best bet. You only need some additional checking on the phase ID and the source component.
<p:dataTable binding="#{table}" ...>
<f:view afterPhase="#{bean.reset(table)}" />
<p:ajax ... />
<p:ajax ... />
<p:ajax ... />
<p:ajax ... />
...
</p:dataTable>
public void reset(UIData table) {
FacesContext context = FacesContext.getCurrentInstance();
if (context.getCurrentPhaseId() != PhaseId.INVOKE_APPLICATION) {
return;
}
String source = context.getExternalContext().getRequestParameterMap().get("javax.faces.source");
if (!table.getClientId(context).equals(source)) {
return;
}
// Reset logic here.
// ...
}
(binding could if necessary be replaced by a hardcoded table client ID)
I understand that this is awkward. So, for the upcoming OmniFaces 2.2 I have altered the existing InvokeActionEventListener to support this use case too. It now supports being attached on any UIComponent.
<p:dataTable ...>
<f:event type="postInvokeAction" listener="#{bean.reset}" />
<p:ajax ... />
<p:ajax ... />
<p:ajax ... />
<p:ajax ... />
...
</p:dataTable>
public void reset() {
// ...
}

Button not submit PrimeFaces 3.5

i'm using jsf + primefaces 3.5. And my button isn't calling one method in my managed bean.
I have this xhtml:
<h:form>
<p:inputText id="name" value="#{userMB.userSelected.name}" />
<p:commandButton id="btnSave" value="Salvar" actionListener="#{userMB.save}"/>
</h:form>
And my managed bean is:
#ManagedBean
#SessionScoped
public class UsuarioMB implements Serializable{
User userSelected;
public void save(){
System.out.println(userSelected.getName());
//call my daos and persist in database
}
}
The most curious is that if i remove the , the method is called!
If i put a atribute in p:commandButton "imediate = true ", the method is called, BUT, the information (userSelected.name) is null !
Thanks very much :)
It failed because it threw a NullPointerException because you never initialized userSelected.
Add this to your bean:
#PostConstruct
public void init() {
userSelected = new User();
}
If you have paid attention to the server logs, you should have seen it. As to the complete absence of feedback about the exception in the webbrowser, whereas in normal synchronous (non-ajax) you would have seen a HTTP 500 error page, it's because you're sending an ajax request without apparently an ExceptionHandler configured.
That it works when you set immediate="true" on the button is simply because it will then bypass the processing of all input components which do not have immediate="true" set.
See also:
What is the correct way to deal with JSF 2.0 exceptions for AJAXified components?
You have not given a name to the managedbean UsuarioMB. As suche it will be named usuarioMB.
#ManagedBean – marks this bean to be a managed bean with the name
specified in name attribute. If the name attribute in #ManagedBean is
not specified, then the managed bean name will default to class name
portion of the fully qualified class name.
read more about it in this blog: http://mkblog.exadel.com/2009/08/learning-jsf2-managed-beans/
Secondly, if your code above is complete, you are lacking public getter and setter for userSelected.
Thirdly you are missing the ActionEvent as you have declared a parameterless actionlistener, see Differences between action and actionListener
In order to get you code working you will need to change your xhtml to
<h:form>
<p:inputText id="name" value="#{usuarioMB.userSelected.name}" />
<p:commandButton id="btnSave" value="Salvar" actionListener="#{usuarioMB.save}"/>
</h:form>
And your managed bean as follows
import javax.faces.event.ActionEvent;
// ...
#ManagedBean
#SessionScoped
public class UsuarioMB implements Serializable{
private User userSelected;
public void save(ActionEvent event){
System.out.println(userSelected.getName());
}
public User getUserSelected() {
return userSelected;
}
public void setUserSelected(User userSelected) {
this.userSelected = userSelected;
}
}

ApplicationScoped Bean is null on rich:tab's actionListener-method

I'm using JSF 2.0 and Richfaces 3.3.2.
I'm having an issue on one of my pages.
First of all I have a main page which contains a rich:tabPanel with several rich:tabs, no problem there switching between them.
On the first tab of my page I have another tabPanel with some other tabs.
They all have an actionListener which will call the ViewScoped ManagedBean to edit some Data, which will be displayed on the clicked tab. The method to edit the data calls a method on an ApplicationScoped Bean which is correctly injected (It works in other tabs). When switching a tab on the second layer and the action-method is called, the ApplicationScoped Bean is null.
This only happens when I switch tabs (so it does not happen on the first tab, which is displayed by default) so I think it's related to the actionListener, but i can't figure out why. Unfortunately I can't provide the actual code but this is the rough structure of my page.
mainPage.xhtml
...
<rich:tabPanel>
<rich:tab>
<ui:include src="tabs/tab1.xhtml" />
</rich:tab>
otherTabs
</rich:tabPanel>
...
tab1.xhtml
...
<rich:tabPanel>
<rich:tab actionListener="#{viewScopedBean.method}">
<ui:include src="subtabs/subtab1.xhtml" />
</rich:tab>
<rich:tab actionListener="#{viewScopedBean.method2}">
<ui:include src="subtabs/subtab2.xhtml" />
</rich:tab>
</rich:tabPanel>
ViewScopedBean.java
#ManagedBean
#ViewScoped
public class ViewScopedBean {
#ManagedProperty(value="#{applicationBean}")
private ApplicationBean applicationBean;
private Data data;
public void init() {
...
data = applicationBean.retrieveData();
...
}
public void method(ActionEvent e) {
...
data = applicationBean.retrieveData();
...
}
public void method2(ActionEvent e) {
...
data = applicationBean.retrieveData();
...
}
// getters/setters
}
ApplicationBean.java
#ManagedBean
#ApplicationScoped
public class applicationBean {
public Data retrieveData() {
...
}
}
When clicking subtab2 I get a NullPointerException at the line data = applicationBean.getData(), so the applicationBean is null. This happens everytime on every tab I'm switching to, but never in the init() method, so the applicationBean should not be null.
I could not find any solution or hints on this problem and hope someone has an idea.
Thanks in advance
regards

Resources