I have a very simple app. One bean annotated with #Named #SessionScoped and 2 web pages. home.xhtml and list.xhtml. When I set searchForm.hostanme on the first page, and access it again on the 2nd page. I can see from sysout statements that hostname is getting set, but there is a space where that value should be on the list.xhtml page. It's disappearing between home and list. Why?
home.xhtml
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html">
<h:head></h:head>
<h:form>
<h:outputText value="Hi Mama" />
<h:inputText value="#{searchForm.hostname}" />
<h:commandButton action="list?faces-redirect=true" value="Devices" />
<h:commandButton action="#{searchForm.reset}" value="Reset" immediate="true" type="reset" />
</h:form>
</html>
list.xhtml
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html">
<h:outputText value="Device is #{searchForm.hostname}" />
</html>
SearchForm.java
import javax.enterprise.context.RequestScoped;
import javax.inject.Named;
#Named
#RequestScoped
public class SearchForm {
String hostname;
public String getHostname() {
return hostname;
}
public void setHostname(String hostname) {
System.out.println("hostname is "+ hostname);
this.hostname = hostname;
}
public String reset(){
System.out.println("RESETTING");
System.out.println("hostname is "+ hostname);
return "/index.xhtml";
}
}
I'm thinking it might be a scoping issue, but I've tried several scopes and still searchForm.hostname is not avaible by the time I navigate to the list.xhtml page.
I've been reading and reading and reading up on JSF2, but I still can't resolve I hope is a simple problem.
I have a beans.xml file is in WEB-INF.
I come from a seam 2 background so decided I was comfortable with ConversationScoped in this context. It worked like a charm.
Some more thoughts that might help a confused person like me.
As I commented above, I grappled with a similar issue before in this question. As the comments above suggest, this is a scope issue. I realized that it is not only a scoping issue, it is an issue of confusion between CDI and JSF2 managed beans.
Both have a unique set of scopes, but there is some overlap, and in order to not be scratching your head over what should really not be a difficult problem, it is important to
Decide whether to use CDI beans or JSF2 managed beans
Thoroughly learn the scopes assocated with either type of bean
Know which one you are selecting when eclipse offers you 2 choices!
That last one has messed me up more times than I should admit.
Whether to use CDI or JSF2 just google "cdi vs. jsf2". I chose CDI since most things I read said to use CDI. I'm not sure it really makes a difference for my simple app.
Learn your scopes!! There are many articles about scopes, unfortunately I don't understand them as well as I should.
This is a classic for JSF2 users: Communication in JSF2 and I found this helpful as well. (notice same author - BalusC is a good resource for anything JSF2)
As for CDI just stick with the tutorial on Oracle's website.
And as for which library to import -- both JSF and CDI have a SessionScoped, and I think also RequestScoped:
CDI scopes are in javax.enterprise.context.SessionScoped
JSF scopes are in javax.faces.bean.SessionScoped
I consistently just take the first thing eclipse offers me. It can really screw you up so pay attention!
Related
I use flash scope to pass a setting object between #viewscoped contollers. But if I make a page reload on one of them, then the flash map is empty and the setting object is not initialized. Is it possible to keep flash scope on page reload?
My source code to store/retrieve settings:
FistPage.xhtml
...
<p:commandButton value="next"
action="#{firstPageController.transferConfig}"
process="#this" />
...
FirstPageController.java
#ManagedBean(name = "firstPageController")
#ViewScoped
public class FirstPageController {
...
public String transferConfig() {
FacesContext.getCurrentInstance().getExternalContext().getFlash().put("searchConfig", searchConfig);
return "/secondPage.xhtml?faces-redirect=true";
}
...
}
SecondPage.xhtml
...
<h:outputLabel value="value">
<f:event type="preRenderComponent" listener="#{secondPageController.onPageLoad()}"/>
</h:outputLabel>
...
SecondPageController.java
#ManagedBean(name = "secondPageController")
#ViewScoped
public class SecondPageController {
...
public void onPageLoad()
{
flash = FacesContext.getCurrentInstance().getExternalContext().getFlash();
searchConfig = ((SearchFilterConfig) flash.get("searchConfig"));
flash.putNow("searchConfig", searchConfig);
flash.keep("searchConfig");
}
...
}
I use Mojarra 2.1.29
Thanks
I just did some tests in my playground project and realized it's actually possible to keep the state of the flash parameters even if you GET the page again, using {flash.keep}. That's how the JSF docs explain it:
The implementation must ensure the proper behaviour of the flash is preserved even in the case of a <navigation-case> that contains a <redirect />. The implementation must ensure the proper behavior of the flash is preserved even in the case of adjacent GET requests on the same session. This allows Faces applications to fully utilize the Post/Redirect/Get design pattern.
Here you've got a nice basic test case:
page1.xhtml
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:c="http://java.sun.com/jsp/jstl/core">
<h:head />
<h:body>
<h:form>
<h:button id="nextButton" value="Next (button)" outcome="page2.xhtml" />
<c:set target="#{flash}" property="foo" value="bar" />
</h:form>
</h:body>
</html>
page2.xhtml
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html">
<head />
<body>foo = #{flash.keep.foo}
</body>
</html>
Just open the first page and click on the button which will redirect you to the second one. Then refresh the second page as many times as you want and you'll find the parameter persisting.
Tested in Mojarra 2.2.6
I'm new in developing web applications and I installed the ICEfaces plugin. I found this tutorial to learn how to work with it and the first given example dont work in my IDE.
Its about the last part of the tutorial where it shows how to use a dateTimeEntry in a webapp.
So I followed the instructions so that my index.xhtml looks like this:
<?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:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:icecore="http://www.icefaces.org/icefaces/core"
xmlns:ace="http://www.icefaces.org/icefaces/components"
xmlns:ice="http://www.icesoft.com/icefaces/component">
<h:body>
<form>
<ace:dateTimeEntry id="dateTimeEntryId"
value="#{yourBean.selectDateProperty}" timeZone="Canada/Mountain"
pattern="MMM/dd/yyyy" style="width: 729px; " renderAsPopup="true">
</ace:dateTimeEntry><br />
</form>
</h:body>
</html>
And my java bean like this:
package org.icefaces.view;
import java.io.Serializable;
import java.util.Date;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import org.icefaces.ace.event.DateSelectEvent;
#ManagedBean(name= "yourBean")
#ViewScoped
public class YourBean implements Serializable {
/**
*
*/
private static final long serialVersionUID = 5058131064162864510L;
private Date selectDateProperty = new Date(System.currentTimeMillis());
public Date getSelectDateProperty() {
return selectDateProperty;
}
public void setSelectDateProperty(Date selectDateProperty) {
this.selectDateProperty = selectDateProperty;
}
public void dateSelectListener(DateSelectEvent event) {
setSelectDateProperty(event.getDate());
}
}
The structure of the project looks like this:
The point is, that in the tutorial there is no location given where to save the java beans. So I thougt it has to saved in the java resources directory, but I'm not sure because the app dont work. I just get a blank screen. The server and the configuration of it is valid I think because I can drop some Img or buttons and see the result in the browser. So I think I did not really understand how the java beans are connected with the xhtml files. I thougt it works with ManagedBean - attribute but I'm not sure about that.
Complete list of sample codes you can find here
http://anonsvn.icesoft.org/repo/icefaces3/trunk/icefaces/samples
Well I found out, that the connection of the javabeans and the variables in the xhtml file has to created in faces-config.xml in this form:
<managed-bean>
<managed-bean-name> [bean-name-of-java-class] </managed-bean-name>
<managed-bean-class> [fullpath-to-java-file] </managed-bean-class>
<managed-bean-scope>[scope]</managed-bean-scope>
</managed-bean>
I want to invoke one method through a link from Facelets:
My Facelets code is like:
<h:commandButton value="A" actionListener="#{customerData.searchedCustomerListA}" />
<h:commandLink value="A" actionListener="#{customerData.searchedCustomerListA}"/>
Backing bean code is like:
public void searchedCustomerListA(ActionEvent ae){
customerName = "A";
leftCustomerListAvailable.clear();
if(customerDataBean.getSearchedCustomerList(customerName)!= null)
leftCustomerListAvailable =customerDataBean.getSearchedCustomerList("A");
}
The same code is working for <h:commandButton> but not working for <h:commandLink>. How is this caused and how can I solve it?
The technical difference between <h:commandLink> and <h:commandButton> is that the link uses JavaScript to submit the parent form. So if it doesn't work while a syntactically equivalent button works fine, then that can only mean that either JavaScript is disabled in browser, or that the jsf.js file containing the mandatory helper functions isn't included in the page (which you should easily have noticed by seeing JS errors in the JS console of browser's builtin developer toolset).
So, to fix this problem, you need to verify if JS is enabled in browser and that you've a <h:head> component instead of plain HTML <head> in the template, so that JSF will be able to auto-include the jsf.js file.
Or, if your application's business requirements requires that the application functions as designed with JS disabled, then you should stick to <h:commandButton> and throw in some CSS to make it to look like a link (e.g. remove background, padding, border, inset, etc).
Try this, This sould work.
<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:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui">
<h:form>
<h:commandLink type="button" action="#{testBean.tsetLink}">
<h:outputText value="A" />
</h:commandLink>
</h:form>
</html>
ManagedBean
#ManagedBean
#RequestScoped
public class TestBean {
public void tsetLink(){
System.out.println("Link clicked!!!!!!!!!!!!");
}
}
I my case the cause of this issue was a poorly configured url rewriting filter. One of the filters patterns unintentionally matched http://localhost:8080/mysite/javax.faces.resource/jsf.js.xhtml?ln=javax.faces which prevented jsf.js from being loaded. Check this answer: Clicking h:commandLink causes Uncaught ReferenceError: mojarra is not defined.
i have already spent 3 days searching for a possible workaround, so my ViewScoped beans do not lead to an OutOfMemoryException, but without any luck.
First my environment:
JBoss AS 7.1.1.final with
Mojarra 2.1.7
I thought, that ViewScoped beans would be destroyed on a session expiration, but they will not get destroyed (checked with heap dumps). I found the following new feature for Mojarra 2.1.16, which fixes this problem, but sadly upgrading to this version is currently not an option:
http://java.net/jira/browse/JAVASERVERFACES-2561
This problem is also related to the following thread:
Destroying view-scoped beans when session ends
Is there anything i can do, to remove all created ViewScoped beans, when a session ends (logout or session expired)? Saving viewMap in a SessionScoped bean and call clear() also not destroy those beans.
Thanks in advance,
Daniel
To nail down this bug i have stripped my code to the following parts:
One JSF2 page that is very simple:
<!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://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
<h:head>
<f:facet name="first">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Simple OOM Check</title>
</f:facet>
</h:head>
<h:body>
<h:outputText value="#{oomCheckBean.testString}"/>
</h:body>
</html>
And the used #ViewScoped bean oomCheckBean:
#ViewScoped
#ManagedBean(name = "oomCheckBean")
public class OomCheckBean implements Serializable {
private static final long serialVersionUID = 6325712415478215045L;
private String testString;
#PostConstruct
public void init() {
testString = "Hello World";
System.out.println("I will survive ....");
}
#PreDestroy
public void destroy() {
System.out.println("... klaaatsch!");
}
/**
* #return the testString
*/
public String getTestString() {
return testString;
}
/**
* #param testString the testString to set
*/
public void setTestString(String testString) {
this.testString = testString;
}
}
After this i changed my JMeter testcase to login, call this oomCheck.xhtml page and logout. After a short time i stopped test execution, and used JMX to first call manually the garbage collector (java.lang.Memory --> Operations --> gc()). After this i call method to create a heap dump (com.sun.management.HotSpotDiagnostic --> Operations --> dumpHeap()).
Result is like i mentioned in my question, there are a lot OomCheckBean objects in memory. The owner object is org/jboss/as/web/deployment/ConcurrentReferenceHashMap$HashEntry. Any help to fix this problem is appreciated. Like i mentioned above, these #ViewScoped beans will be destroyed, if JSF version is upgraded to 2.1.16, leaving other "bugs" like missing doctype and AJAX problems. So i would be happy, if someone knows how to destroy #ViewScoped beans, when session becomes invalid.
I'm trying with Javaee6 with GlassFish3.1.
I created a web project (with JSF2.0), with only one file, one.xhtml
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html">
<h:head>
<meta http-equiv="Content-Type"
content="text/html; charset=ISO-8859-1" />
<title>ONE</title>
</h:head>
<h:body>
<h:form id="oneForm">
<h:commandButton id="oneButton" value="To Two" action="two" />
</h:form>
</h:body>
</html>
I've not added web.xml, as it is optional for javaee6.
I added faces-config.xml, so that default servlet mapping works. (with only top element)
<faces-config version="2.0" .../>
When I hit command-button on the page, I'm expecting 'Page Not Found' error. But the page just reloads. If I actually put file two.xhtml, it works correctly, but in it's absence, does not give error, which I'm expecting.
Am I missing something, some config?
Thanks in advance.
This is expected. JSF works with so-called navigation cases. If it doesn't find a matching case, it will just postback to the same view. This is specified in the JSF 2.0 specification (pick the one for evaluation).
7.4.2 Default NavigationHandler Algorithm
...
The default NavigationHandler implementation must behave as if it were performing the following algorithm (although optimized implementation techniques may be utilized):
If no navigation case is matched by a call to the handleNavigation() method, this is an indication that the current view should be redisplayed. As of JSF 2.0, a null outcome does not unconditionally cause all navigation rules to be
skipped.
...
However, when you set the JSF project stage to Development by a context parameter in web.xml,
<context-param>
<param-name>javax.faces.PROJECT_STAGE</param-name>
<param-value>Development</param-value>
</context-param>
then clicking the button should then result in a development warning message in the postback,
Unable to find matching navigation case with from-view-id '/one.xhtml' for action 'two' with outcome 'two'
so that eventual developer mistakes are at least put in attention.