I'm new to jsf technology and I'm trying to understand when and how the ViewScoped jsf bean is initialized.
I have a sample app with 2 beans
ApplicationScopedBean.java
#ManagedBean
#ApplicationScoped
public class ApplicationScopedBean implements Serializable {
private int incrementedCounter =0;
public int getIncrementedCounter() {
incrementedCounter += 1;
return incrementedCounter;
}
}
ViewScopedBean.java
#ManagedBean
#ViewScoped
public class ViewScopedBean implements Serializable {
#ManagedProperty(value = "#{applicationScopedBean}")
private ApplicationScopedBean applicationScopedBean;
private int reincarnationNumber;
private int accessCounter;
#PostConstruct
public void initialize() {
accessCounter = 0;
reincarnationNumber = applicationScopedBean.getIncrementedCounter();
System.out.println("Initializing viewScoped stateManager with reincarnationNumber value = " + String.valueOf(reincarnationNumber));
}
public void noAction() {
//do nothing
}
public int getReincarnationNumber() {
return reincarnationNumber;
}
public int getAccessCounter() {
accessCounter += 1;
return accessCounter;
}
public ApplicationScopedBean getApplicationScopedBean() {
return applicationScopedBean;
}
public void setApplicationScopedBean(ApplicationScopedBean applicationScopedBean) {
this.applicationScopedBean = applicationScopedBean;
}
}
ApplicationScoped bean is created only once for the application launch.
Every time ViewScoped bean is being created, the reincarnationNumber is being increased by 1.
I also have a simple jsf page to display these values:
index.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://java.sun.com/jsf/html">
<h:head>
<title>View Scoped bean test</title>
</h:head>
<h:body>
<h:form>
<p>ViewScoped bean reincarnation is <h:outputText value="#{viewScopedBean.reincarnationNumber}"/></p>
<p>ViewScoped bean access counter is <h:outputText value="#{viewScopedBean.accessCounter}"/></p>
<h:commandButton type="submit" value="no action" action="#{viewScopedBean.noAction()}"/>
<h:commandButton type="submit" value="reload this page" action="index"/>
</h:form>
</h:body>
</html>
The problem:
When I launch the application the first time, I already have reincarnationNumber value equal to 3.
In other words, I have this info displayed in browser:
ViewScoped bean reincarnation is 3
ViewScoped bean access counter is 1
Why is that?
Why ViewScoped bean has bean created 3 times?
Thanks in advance!
SOLUTION
As it is stated in the comments, the cause was "start browser" checkbox checked in Run Configurations in my IntelliJ IDEA. The trick is when browser is auto-started from IDE I have viewScopedBean initialized 3 times.
It's not created 3 times, just called the getter several times... and that's because... you can check this answer:
Why JSF calls getters multiple times
Related
i have a simple file.xhtml in a JSF2.2 application, that's its code:
<!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://xmlns.jcp.org/jsf/core"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:ez="http://xmlns.jcp.org/jsf/composite/ezcomp">
<head>
<title>Insert title here</title>
</head>
<body>
<f:view>
<h:form id="greeting">
<h:inputText id="num1" value="#{jSFeatBean.num1}" />
<h:inputText id="num2" value="#{jSFeatBean.num2}"/>
<h:commandButton type="submit"
value="Submit"
action="#{jSFeatBean.addNumbers()}"/>
<h:outputText value="#{jSFeatBean.result}"/>!
</h:form>
</f:view>
</body>
</html>
and this is my #ManagedBean:
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
#ManagedBean(name = "jSFeatBean", eager = true)
#SessionScoped
public class JSFeatursBean {
private String result;
public int num1 = 1;
int num2;
public int getNum1() {
return num1;
}
public void setNum1(int num1) {
this.num1 = num1;
}
public int getNum2() {
return num2;
}
public void setNum2(int num2) {
this.num2 = num2;
}
public String getResult() {
return result;
}
public void setResult(String result) {
this.result = result;
}
public Object addNumbers() {
setResult("il risultato e': "+ Integer.toString(num1+num2));
return null;
}
}
after i start jboss from Eclipse the browser display all elements of my file.xhtml properly but the values in the first (id = num1) inputText is 0 and not 1. Why this happens? If i put new values in the inputText boxes everything works fine, so i think that the Mbean is instantiated and working.
I have the same problem with a h:SelectOneListbox element, that doesn't show the list i create when i call the MBean constructor.
It looks like the MBean gets instatiated right after the display of html page.
The code looks fine to me with just one thing that might cause the problem.
Try remove "eager = true" attribute in your ManagedBean annotation. "eager = true" only works with ApplicationScoped Beans.
JSF 2.1
Tomcat 7.0
Is this a wrong use of dependency injection?
It works ok moving around the page. But "it works" is not the same as "it's correct".
I would use this pattern also for search purpose. I have a request and i like to use it to populate a table in the same page. Is this possible?
index.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://java.sun.com/jsf/html">
<h:head>
<link rel="SHORTCUT ICON" href= "resources/img/onlyT.ico"></link>
<title>title</title>
<h:outputStylesheet library="css" name="compass.css"/>
</h:head>
<h:body>
Login system
<br />
<h:form>
User : <h:inputText value="#{user.username}" />
Password : <h:inputSecret value="#{user.password}" />
<h:commandButton action="#{loginBean.performLogin()}" value="Submit" />
<h:commandButton value="reset" type="reset" />
<h:commandButton value="ChangePsW" action="changePassword"></h:commandButton>
</h:form>
<h:message for="" style="color:red;margin:8px;"/>
</h:body>
</html>
LoginBan.java
#ManagedBean
#RequestScoped
public class LoginBean {
#ManagedProperty(value="#{user}")
private UserBean userBean;
//must povide the setter method
public void setUserBean(UserBean userBean) {
this.userBean = userBean;
}
public LoginBean() {}
public String performLogin(){
//Mi connetto al db
if(userBean.getUsername().equalsIgnoreCase( "mario")){
//effettuo i controlli per stabilire se esiste l'utente
userBean.setRoles("-EE-E-E-E-E-E");
return "/mainPortal/mainPortal";
}
return "/mainPortal/index";
}
}
UserBean.java
#ManagedBean (name="user")
#SessionScoped
public class UserBean implements Serializable {
private String Username;
private String Password;
private String Roles;
/** Creates a new instance of UserBean */
public UserBean() {
}
/**
* #return the Username
*/
public String getUsername() {
return Username;
}
/**
* #param Username the Username to set
*/
public void setUsername( String Username ) {
this.Username = Username;
}
/**
* #return the Password
*/
public String getPassword() {
return Password;
}
/**
* #return the Roles
*/
public String getRoles() {
return Roles;
}
/**
* #param Roles the Roles to set
*/
public void setRoles( String Roles ) {
this.Roles = Roles;
}
/**
* #param Password the Password to set
*/
public void setPassword( String Password ) {
this.Password = Password;
}
change password also use the userBean and has his changePasswordBean.
JSF 2 allows you injecting managed beans in other managed beans. This is only limited by the scope of the bean you're actually injecting, which has to be greater than the scope of the bean you actually are in. I mean, you can inject #SessionScoped bean in a #ViewScoped one, but not in the other way. As you follow that convention, I think you're doing it well.
Generally, your application should be composed by #ViewScoped or #RequestScoped beans to handle current user input/outputs and wider scoped beans for session or application means. So, when user logs in, it's a good idea to maintain his data in a session context, however I suggest you not to maintain user's password into session, at least if you're not going to use it once the login has been succesfully done.
Finally the question you make about search requests, I think you can implement a search input in your page and make your result table load dinamically depending on the search. Just use ajax to obtain it without having to reload the whole page. You can implement everything in a #ViewScoped bean, but remember not to return navigation results in your listener methods if you want to maintain the bean working.
I put this problem in a simple example, a composite component that calculates the sum of 2 inputs and prints the result in an outputText
Main JSF page:
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:ez="http://java.sun.com/jsf/composite/ezcomp/">
<h:head></h:head>
<h:body>
<ez:Calculator />
<br/>
<br/>
<ez:Calculator />
<br/>
<br/>
<ez:Calculator />
</h:body>
</html>
Composite component 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:composite="http://java.sun.com/jsf/composite"
xmlns:h="http://java.sun.com/jsf/html">
<h:head>
<title>This content will not be displayed</title>
</h:head>
<h:body>
<composite:interface componentType="calculator">
</composite:interface>
<composite:implementation>
<h:form>
<h:inputText id="first" value="#{cc.firstNumber}" />
<h:commandButton value="+" action="#{cc.sum}"/>
<h:inputText id="second" value="#{cc.secondNumber}" />
</h:form>
<h:outputText id="result" value="#{cc.result}" />
</composite:implementation>
</h:body>
</html>
Composite component backing bean:
package ez;
import javax.faces.component.FacesComponent;
import javax.faces.component.UINamingContainer;
#FacesComponent("calculator")
public class Calculator extends UINamingContainer {
private Long firstNumber;
private Long secondNumber;
private Long result;
public Calculator() {
}
#Override
public String getFamily() {
return "javax.faces.NamingContainer";
}
public void setFirstNumber(String firstNumber) {
this.firstNumber = Long.parseLong(firstNumber);
}
public String getFirstNumber() {
if(firstNumber == null) {
return null;
}
return firstNumber.toString();
}
public void setSecondNumber(String secondNumber) {
this.secondNumber = Long.parseLong(secondNumber);
}
public String getSecondNumber() {
if(secondNumber == null) {
return null;
}
return secondNumber.toString();
}
public String getResult() {
if(result == null) {
return null;
}
return result.toString();
}
public void setResult(String result) {
this.result = Long.parseLong(result);
}
public void sum() {
this.result = this.firstNumber + this.secondNumber;
}
}
So, I have 3 Composite Components that all should do the same thing, but when I press a SUM button, after the server processes the request, the result is printed out on the page, but the other 2 components are cleared of their values.
How can I prevent this? How can I force it to retain those values?
UIComponent instances are recreated on every request, hereby losing all instance variables everytime. They basically act like request scoped managed beans, while you intend to have them in the view scope. You need to take view state saving into account on a per-attribute basis. This is normally by default already done for all attributes of #{cc.attrs}. So, if you can, just make use of it:
<cc:interface componentType="calculator">
<cc:attribute name="firstNumber" type="java.lang.Long" />
<cc:attribute name="secondNumber" type="java.lang.Long" />
</cc:interface>
<cc:implementation>
<h:form>
<h:inputText id="first" value="#{cc.attrs.firstNumber}" />
<h:commandButton value="+" action="#{cc.sum}"/>
<h:inputText id="second" value="#{cc.attrs.secondNumber}" />
</h:form>
<h:outputText id="result" value="#{cc.attrs.result}" />
</cc:implementation>
with just this (nullchecks omitted; I recommend to make use of required="true" on the inputs)
#FacesComponent("calculator")
public class Calculator extends UINamingContainer {
public void sum() {
Long firstNumber = (Long) getAttributes().get("firstNumber");
Long secondNumber = (Long) getAttributes().get("secondNumber");
getAttributes().put("result", firstNumber + secondNumber);
}
}
Otherwise, you'd have to take state saving into account yourself by delegating all attribute getters/setters to UIComponent#getStateHelper(). Based on the very same Facelets code as you have, the entire backing component would look like this:
#FacesComponent("calculator")
public class Calculator extends UINamingContainer {
public void sum() {
setResult(getFirstNumber() + getSecondNumber());
}
public void setFirstNumber(Long firstNumber) {
getStateHelper().put("firstNumber", firstNumber);
}
public Long getFirstNumber() {
return (Long) getStateHelper().eval("firstNumber");
}
public void setSecondNumber(Long secondNumber) {
getStateHelper().put("secondNumber", secondNumber);
}
public Long getSecondNumber() {
return (Long) getStateHelper().eval("secondNumber");
}
public void setResult(Long result) {
getStateHelper().put("result", result);
}
public Long getResult() {
return (Long) getStateHelper().eval("result");
}
}
See, no local variables anymore. Note that I also removed the need for those ugly manual String-Long conversions by just declaring the right getter return type and setter argument type. JSF/EL will do the conversion automagically based on default converters or custom Converters. As there's already a default one for Long, you don't need to provide a custom Converter.
Unrelated to the concrete problem, you can safely remove the getFamily() method. The UINamingContainer already provides exactly this. If you were implementing NamingContainer interface instead, then you'd indeed need to provide it yourself, but this is thus not the case here. The above backing component examples have it already removed.
I created an ejb
#Stateless
#LocalBean
public class BasitBean {
public String helloBasit() {
return "Basit";
} //end of helloBasit()
} //end of class BasitBean
I am calling it from JSF like
<h:body>
<h:outputLabel value="#{helloBasit.callBasit()}" />
</h:body>
#ManagedBean
#SessionScoped
public class HelloBasit {
#EJB
private BasitBean basitBean;
/** Creates a new instance of HelloBasit */
public HelloBasit() {
}
public String callBasit() {
return basitBean.helloBasit();
} //end of callBasit()
} //end of class HelloBasit
This code is working fine. But when i change the code like this
<h:body>
<h:outputLabel value="#{helloBasit.label}" />
</h:body>
#ManagedBean
#SessionScoped
public class HelloBasit {
#EJB
private BasitBean basitBean;
String label;
/** Creates a new instance of HelloBasit */
public HelloBasit() {
System.out.println();
String label = basitBean.helloBasit();
System.out.println(label);
}
public BasitBean getBasitBean() {
return basitBean;
}
public void setBasitBean(BasitBean basitBean) {
this.basitBean = basitBean;
}
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
} //end of class HelloBasit
Then i get the exception
SEVERE: Error Rendering View[/index.xhtml]
com.sun.faces.mgbean.ManagedBeanCreationException: Cant instantiate class: pk.mazars.basitMahmood.HelloBasit.
at com.sun.faces.mgbean.BeanBuilder.newBeanInstance(BeanBuilder.java:193)
at com.sun.faces.mgbean.BeanBuilder.build(BeanBuilder.java:102)
......
Why i am getting this exception? The flow should be what i understand is when my page encounters #{helloBasit.label} then my constructor get call, instance variable get initialized, injected the bean instance into the basitBean, then the bean method should call. But i am getting null in the bean instance in this case why? Why previous code is working and it is not ? How can i call bean from the constructor ?
Thank you.
try to move your content of the constructor into a post constructor instead...
like this
#PostConstruct
private void init() {
System.out.println();
String label = basitBean.helloBasit();
System.out.println(label);
}
Cause the ejb bean should be injected only after the managed bean has been initiated
The #PostConstruct is being run after the constructor (after that the managed bean itself was created by the JSF) and only then the EJB is being injected into the bean and can be accessed...
Your idea is correct, but I see some things that may be fixed.
#LocalBean annotation is not required if your EJB is not directly implementing an interface. In this case, with or without the #LocalBean annotation you have the same effect. You may leave that if you want to make it explicit though. See this.
Make sure both #ManagedBean and #SessionScoped import from javax.faces.bean package.
Please, see this working sample:
EJB
import javax.ejb.Stateless;
#Stateless
public class PersonService {
public String getName() {
return "Cloud Strife";
}
}
Managed Bean
import javax.annotation.PostConstruct;
import javax.ejb.EJB;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
#ManagedBean
#SessionScoped
public class PersonBean {
#EJB
private PersonService ps;
private String name;
#PostConstruct
public void init() {
name = ps.getName();
}
public String getName() {
return name;
}
}
XHTML Page
<?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:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html">
<f:view contentType="text/html">
<h:head>
<title>Test</title>
</h:head>
<h:body>
<h1>Welcome, #{personBean.name}</h1>
</h:body>
</f:view>
</html>
If your value should be loaded only once, say at your bean construction, always prefer a method with #PostConstruct annotation instead of the constructor.
Also, in order to call bean methods before rendering a view you could use a f:event tag, for example:
<f:event type="preRenderView" listener="#{personBean.init}" />
I hope it helps!
I like to know whats the correct way to create a login/logout mechanizm in jsf2 environment.
I have created a login xhtml form and a Admin bean that stores a static boolean (is_authenticated) . I want to check that variable in every xhtml page , if true? continue , else redirect to login page.
this is Admin.java bean:
#ManagedBean
#SessionScoped
public class Admin implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
static Boolean authenticated;
String username;
String password;
#PostConstruct
public void initialisation() { // init bean on new instance
Admin.authenticated = false;
}
public Boolean getAuthenticated(){
return Admin.authenticated;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String doLogout() {
Admin.authenticated=false;
return "login?faces-redirect=true";
}
public String validity() {
if(username.equals("admin") && password.equals("admin")) {
Admin.authenticated=true;
return "success";
} else {
Admin.authenticated=false;
return "failure";
}
}
}
and this is the main.xhtml:
<?xml version="1.0" encoding="UTF-8" ?>
<ui:composition 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:c="http://java.sun.com/jsp/jstl/core"
xmlns:ui="http://java.sun.com/jsf/facelets">
<ui:define name="content">
<c:if test="#{admin.authenticated == false}">
// update Admin.authenticate to false
<meta http-equiv="refresh" content="0;URL=login.xhtml" />
</c:if>
<h1>Statistics</h1>
<div style="margin:10px">
<h:panelGrid columns="3">
Advertisers:
<h:outputText value="#{stats.advertisers}"/>
<h:outputText value=""/>
Publishers:
<h:outputText value="#{stats.publishers}"/>
<h:outputText value=""/>
Campaigns:
<h:outputText value="#{stats.campaigns}"/>
<h:outputText value="(#{stats.activeCampaigns} active)"/>
Banners:
<h:outputText value="#{stats.banners}"/>
<h:outputText value="(#{stats.activeBanners} active)"/>
Games:
<h:outputText value="#{stats.games}"/>
<h:outputText value="(#{stats.activeGames} active)"/>
</h:panelGrid>
</div>
</ui:define>
</ui:composition>
Two questions:
in the jstl 'if' ,I get : "Property 'authenticated' not found on
type com.pkg.name.Admin"
How can I update Admin.authenticate to false from the xhtml file(sorry for the lame question, i'm really new to jsf and web dev in general)
is it good practice to use this static variable? (like an instance of the session variable)
According to me the correct and cleaner way to implement login/logout is to create a filter and apply it to the urls that should be protected(e.g. /admin/*).
If the user sucessfully logs in load his details in session bean. When the user requests a protected page the filter runs first. In the filter get the session from request and call its getAttribute method to get the session bean(jsf stores the session scoped beans as session attributes). If you get the bean object then he is logged in else if you get null he is not authorized and you can redirect him to login page.
For logout you can just call invalidate on the session and all the session scoped attributes will be destroyed.
A working example will be like following:
The SessionScoped bean which will save login information:
UserBean.java
#ManagedBean
#SessionScoped
class UserBean implements Serializable{
private User user;
//getter/setter for user
}
LoginBean.java
#ManagedBean
class LoginBean
{
#ManagedProperty(value="#{userBean}")
private UserBean userBean;
public UserBean getUserBean(){
return userBean;
}
public void setUserBean(UserBean userBean){
this.userBean=userBean;
}
private String username,password;
//getter and setter for username,password
public String checkLogin(){
//check database for user
if(user!=null){
userBean.setUser(user);
}
//...
}
}
LoginFilter.java- We apply this filter to url pattern: /admin/*
#WebFilter("/admin/*")
class LoginFilter implements Filter{
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
HttpSession session=((HttpServletRequest)request).getSession();
userBean userBean=(userBean)session.getAttribute("userBean");
if(userBean!=null){
User user=userBean.getUser();
if(user==null){
((HttpServletResponse)response).sendRedirect("login.jsf");
}
else
chain.doFilter(request, response);
}
else
((HttpServletResponse)response).sendRedirect("login.jsf");
}
public void init(FilterConfig fc){}
public void destroy(){}
}
login.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">
<h:head><title>Login To Admin Panel</title>
</h:head>
<h:body>
<h:form>
Username : <h:inputText value="#{loginBean.username}"/>
Password : <h:inputSecret value="#{loginBean.password}"/>
<h:commandButton value="Login" action="#{loginBean.checkLogin}" />
</h:form>
</h:body>
</html>
For log out you can simply call session.invalidate() which will destroy the session along with any session scoped attributes.
This way you don't have to write conditional jstl tags to determine whether the use is logged in or not.
Hope this helps.