I'm using Mojarra 2.2.4 on GlassFish 4 with Java 7.
As I understand from BalusC's answer to How and when is a #ViewScoped bean destroyed in JSF?, #ViewScoped beans should be destroyed in three cases:
Post-back with non-null outcome
Session expiration
Maximum number of logical views in session exceeded
My beans are being destroyed in the first two cases, but not when the maximum number of logical views is exceeded. I have verified that the beans do expire when the maximum is exceeded (I get a ViewExpiredException), but they are still not destroyed until the session itself expires.
For memory consumption reasons, I would like to have the beans destroyed in this third case, especially since they are not usable after expiration.
Questions
Why are the beans not destroyed when they expire?
Is this a bug or expected behavior?
What would be a clean work-around to make sure the beans get destroyed?
Update: OmniFaces ViewScoped annotation destroys beans as soon as they expire.
Minimal Example
Here is my bean:
#javax.inject.Named("sandboxController")
#javax.faces.view.ViewScoped
public class SandboxController implements Serializable {
private static final Logger log = Logger.getLogger(SandboxController.class.getName());
#PostConstruct
public void postConstruct() {
log.log(Level.INFO, "Constructing SandboxController");
}
#PreDestroy
public void preDestroy() {
log.log(Level.INFO, "Destroying SandboxController");
}
public String getData() {
return "abcdefg";
}
}
and my sandbox.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">
<body>
<h:form>
<h:outputText value="#{sandboxController.data}"/>
</h:form>
</body>
</html>
and part of my web.xml:
<context-param>
<param-name>com.sun.faces.numberOfLogicalViews</param-name>
<param-value>3</param-value>
</context-param>
<context-param>
<param-name>com.sun.faces.numberOfViewsInSession</param-name>
<param-value>3</param-value>
</context-param>
If I refresh the sandbox.xhtml 50 times, I get 50 copies of INFO: Constructing SandboxController in the log. The beans are not destroyed, regardless of how many times I refresh. VisualVM confirms that the beans are still referenced by the UIViewRoot's ViewMap. In my full-size bean, which maintains a fair bit of state, I quickly get an OutOfMemoryException.
When I manually expire the session, I get 50 copies of INFO: Destroying SandboxController.
If I add a submit button to sandbox.xhtml and load it up in 4 different tabs, then try to submit the first one, I get a ViewExpiredException, as expected, but the bean is still not destroyed.
The behavior is the same if I instead use the javax.faces.bean.ManagedBean and javax.faces.view.ViewScoped annotations. However, the OmniFaces annotation org.omnifaces.cdi.ViewScoped works properly.
To clarify...
My #ViewScoped beans are being destroyed on session expiration, unlike problems described in related questions such as Linked ViewScoped beans lead to memory leaks
I am not asking why each bean is not destroyed immediately on subsequent refresh as questioned here: JSF 2.1 ViewScopedBean #PreDestroy method is not called. I want to know why it is that even when they expire, and are no longer useful, they are still not destroyed, and thus continue consuming memory.
I was able to find a clean work-around by using the OmniFaces #ViewScoped annotation (org.omnifaces.cdi.ViewScoped) instead of the standard #ViewScoped (javax.faces.view.ViewScoped).
The OmniFaces ViewScoped correctly destroys the beans as soon as they expire.
See here for more details:
http://showcase.omnifaces.org/cdi/ViewScoped
Related
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!
I'm passing a parameter p1 to another page page.xhtml:
<ui:include src="page.xhtml">
<ui:param name="p1" value="#{someObject}"/>
</ui:include>
Is this possible to evaluate #{p1} inside #PostConstruct method of the backing bean of page.xhtml? Using the following piece of code, #{p1} cannot resolve:
FacesContext currentInstance = FacesContext.getCurrentInstance();
currentInstance.getApplication().evaluateExpressionGet(currentInstance, "#{p1}", String.class);
Why do I need this?
I'm using an xhtml file (say component.xhtml) as a custom UI component. This file has a backing bean from which I should get component data. Since I'm including this xhtml file twice or more in my main JSF page, I want to pass different objects to each of component.xhtml so that my component work with my custom data each time included.
In Mojarra, you can get it as an attribute of the FaceletContext. You can get it in the #PostConstruct of a managed bean which is guaranteed to be referenced/constructed for the first time in the included page (and thus not in the parent page before the <ui:param> is declared in the component tree).
FaceletContext faceletContext = (FaceletContext) FacesContext.getCurrentInstance().getAttributes().get(FaceletContext.FACELET_CONTEXT_KEY);
Object p1 = faceletContext.getAttribute("p1");
In MyFaces, the whole FaceletContext isn't available in managed beans as it's discarded by end of view build time and this construct would then not work. To be JSF implementation independent, you might want to consider to set it via <c:set scope="request"> instead. It's then available as a request attribute.
As to the concrete functional requirement, consider creating a comoposite component with a backing component. For some examples, see our composite component wiki page and this blog about using multiple input components in a composite component. See also When to use <ui:include>, tag files, composite components and/or custom components?
The param is not available in the #PostConstruct method; you can use the preRenderComponent event to initialize the parameters inside your backing bean; just put it after the ui:composition of the included page, it will be executed before the rendering of the included page itself.
Following the OP example of a passing a p1 parameter to a page.xhtml template
the main page:
<ui:include src="page.xhtml">
<ui:param name="p1" value="#{someObject}"/>
</ui:include>
page.xhtml:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
...>
<ui:composition>
<f:event listener="#{backingBean.init(p1)}" type="preRenderComponent"/>
...
</ui:composition>
</html>
BackingBean.java:
#ViewScoped
public class BackingBean{
private Object p1;
public void init(Object value){
this.p1=p1;
}
...
}
the event is fired before the render of the ui:composition tag, that is before the render of page.xhtml
This works for me:
<ui:include src="page.xhtml">
<ui:param name="p1" value="#{someObject}"/>
</ui:include>
page.xhtml:
<c:set var="data" value="#{p1}" scope="request"/>
Your bean:
#ViewScoped
public class ManagedBean{
private Object someObject;
public Object getSomeObject(){
if(someObject== null){
HttpServletRequest request = (HttpServletRequest)FacesContext.getCurrentInstance().getExternalContext().getRequest();
someObject= request.getAttribute("data");
}
return someObject;
}
public void setSomeObject(Object someObject){
this.someObject = someObject;
}}
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 have a very strange problem where a bean is not resolved but ONLY on submit. It works fine on view but on submit, it errors out saying that the identifier is null
My JSF
<h:form id="edit" styleClass="form">
<rich:panel>
<f:facet name="header">
<h:outputText value="Edit Data" />
</f:facet>
<rich:graphValidator value="#{myModel}" id="gv">
<rich:messages for="gv" />
<rich:messages id="goal-messages" globalOnly="true" />
<!-- form fields that reference #{myModel.fields} -->
<h:commandButton id="save" value="Save"
action="#{myModel.save}" />
</rich:graphValidator>
</rich:panel>
</h:form>
The Model class
#Named("myModel")
#RequestScoped
public class MyModelImpl implements Model {
#Inject
#RequestParam("objectId")
private Long objectId;
// Getters & Setters for the various fields
public void save() {
// does nothing just now
}
}
I know that I should move the save operation into a controller which I will once I have it working. I have another instance of this working without issues (in another but related module). In fact, I copied the code to start with and modified as necessary.
The main difference in this module is that I name it differently from the class.
The view loads up ok without any issues, but on submit, I get the following:
The root exception is:
Caused by: javax.el.PropertyNotFoundException: /edit.xhtml #26,71 value="#{myModel.name}": Target Unreachable, identifier 'myModel' resolved to null
at com.sun.faces.facelets.el.TagValueExpression.setValue(TagValueExpression.java:133) [jsf-impl-2.1.7-jbossorg-2.jar:]
at org.richfaces.el.ValueExpressionAnalayserImpl$SetValueCommand.resolve(ValueExpressionAnalayserImpl.java:42) [richfaces-components-ui-4.2.2.Final.jar:4.2.2.Final]
at org.richfaces.el.ValueExpressionAnalayserImpl.resolveValue(ValueExpressionAnalayserImpl.java:64) [richfaces-components-ui-4.2.2.Final.jar:4.2.2.Final]
at org.richfaces.el.ValueExpressionAnalayserImpl.updateValueAndGetPropertyDescriptor(ValueExpressionAnalayserImpl.java:90) [richfaces-components-ui-4.2.2.Final.jar:4.2.2.Final]
at org.richfaces.validator.BeanValidatorServiceImpl.validateExpression(BeanValidatorServiceImpl.java:157) [richfaces-components-ui-4.2.2.Final.jar:4.2.2.Final]
... 41 more
Bearing in mind that it works on viewing the page, I am at a real loss as to why it doesn't work on submit.
I have tried various things including:
changing the scope to #ViewScoped,
removing the bulk of the fields displayed (bar one - the name),
passing in the requestParam again (but I realised that i wasn't even picked up in the first place and it works fine.
I have found lots of different people with the same final error but not the same circumstances .
all with no joy. Anybody have any thoughts on what might be the issue?
I am testing using Arquillian on JBoss 7.1.1.Final
Any help appreciated.
As it turns out - the culprit was eclipse. After wasting a whole afternoon yesterday, I tried running the tests through maven this morning and it worked fine.
I had tried cleaning the projects in eclipse but that seemed to not have any effect yesterday. Doing it again today seemed to clear the issue.
In fact, the issue cropped up again which I was again able to fix by cleaning the project.
:-/
May be try #ManagedBean?:
#ManagedBean(name="myModel")
#RequestScoped
public class MyModelImpl implements Model {
#Inject
#RequestParam("objectId")
private Long objectId;
// Getters & Setters for the various fields
//should save return some outcome?
public String save() {
return "index.xhtml";
}
public String getName() {
retrun "Your error shows that somewhere in your xhtml this property is called";
}
}
Check that your faces-config.xml is in the META-INF directory in the root directory of your web application.
http://docs.oracle.com/javaee/7/api/javax/faces/webapp/FacesServlet.html
Here's the scenario. In my managed bean, I create a new FacesMessage object and add it to the FacesContext, without associating it with any UI component, like so:
FacesContext context = FacesContext.getCurrentInstance();
FacesMessage message = new FacesMessage();
message.setSummary("Hi there!");
context.addMessage(null, message);
In my xhtml page, I output my message like so:
<h:messages id="someId" globalOnly="true" showSummary="true" showDetail="false" styleClass="startUpMessages"/>
However, the generated html displays the summary of the message twice, like so:
<ul id="mainForm:someId" class="startUpMessages"><li> Hi there! </li><li> Hi there! </li></ul>
<ul id="javax_faces_developmentstage_messages" title="Project Stage[Development]: Unhandled Messages"></ul>
Can anyone explain this behaviour?
Turns out this issue was caused by an oversight in a phase listener in the application, that wasn't mentioned in the question.
This phase listener was designed to solve an issue with persisting FacesMessages across two adjacent requests, in one particular instance of the application. It would store all of the FacesMessages that were created in a request scoped bean into the session temporarily.
However, the phase listener was mistakingly implemented to execute during every request. So FacesMessages that were created in session scoped beans (like the one in question) ended up being duplicated, which explains why I was seeing the summary of the message displayed twice.
Try to change your Web.xml.
Change PROJECT_STAGE from Development to Production
<!-- Web application context parameters -->
<context-param>
<description>One of Production, Development, UnitTest, SystemTest, Extension
Default is Production.
</description>
<param-name>javax.faces.PROJECT_STAGE</param-name>
<param-value>Production</param-value>
</context-param>