Acces one managed bean from another by #ManagedProperty - jsf

I have 2 jsf pages and 2 beans for each.
First page is login page, where user types his login-password and then he is redirecting to his mailbox page. I want to get data from login page to mailbox page.
My bean for login page:
#ManagedBean(name = "login")
#ConcurrencyManagement(ConcurrencyManagementType.CONTAINER)
#RequestScoped
public class LoginFormBean {
#EJB
private LoginService loginService;
private String email;
private String password;
public String getEmail() {
return email;
}
public String getPassword() {
return password;
}
public void setEmail(String email) {
this.email = email;
}
public void setPassword(String password) {
this.password = password;
}
public String login() {
if (loginService.loginUser(email, password))
return "mailBox.xhtml?faces-redirect=true";
else return "";
}
}
My bean for mailbox page:
#ManagedBean(name = "mailBox")
#ConcurrencyManagement(ConcurrencyManagementType.CONTAINER)
#RequestScoped
public class MailBoxFormBean {
#ManagedProperty(value = "#{login}")
private LoginFormBean login;
private String email = login.getEmail();
public void setLogin(LoginFormBean login) {
this.login = login;
}
public void setEmail(String email) {
this.email = email;
}
public String getEmail() {
return email;
}
}
But when I'm redirecting to mailbox page, login bean is null and I can't get data from it.
What I'm doing wrong?
I've seen a lot of tutorials and answers (for example,
Using #ManagedProperty to call method between Managed beans or
http://www.techartifact.com/blogs/2013/01/access-one-managed-bean-from-another-in-jsf-2-0.html
)
I do exactly the same, but it isn't working for me.

The problem is that your login bean is marked as #RequestScoped, so as soon as you redirect away from the login page, the value is discarded. Try #SessionScoped instead: that's usually the correct scope for user login information.

Related

Invalidating old httpsession drops current httpsession's context

My app handles logins with a #ViewScoped LoginBean, which is injected with a #SessionScoped SessionBean that stores user information and the current HttpSession. This app allows a user N separate sessions. After reaching that limit the user can only create another by killing off the oldest. This is done in the same LoginBean by asking the unmanaged UserSessionManager for the oldest SessionBean, and then invalidating its HttpSession.
Thus, logging in with session "A", we invalidate session "B". This all goes according to plan. But then, sometime during the remaining JSF phases, we also lose the SessionBean for session "A". Tracing down into the CDI code it appears that the session context for session "A" is being destroyed so when the redisplay finishes we have all new session beans.
We are using MyFaces 2.3.6, OpenWebBeans 2.0.16, OpenJDK 11
Is this a bug in OWB, or expected bahavior?
I'm also wondering if I have a fundamental misconception. If I save a SessionBean in my UserSessionManager and the retrieve it during a different session, should it retain its original state or does it get re-evaluated in the new SessionScoped context? I've been finding debugging difficult because my objects seem to actually be proxies, and the UI and debugger show different values at times.
Update 4/27/20:
The #SessionScoped SessionBean is being destroyed by org.apache.webbeans.web.context.WebContextsService#destroyRequestContext() where it destroys the "PropagatedSessionContext". This PropagatedSessionContext is being set by WebContextsService#destroySessionContext(), which is designating the local session to be destroyed despite being given a different specific session. This is where I'm wondering if it's a bug in OWB.
Here's a simplified example of the code:
(In this test code I've made the SessionManager an #ApplicationScoped bean. In the original code it isn't, but the behavior is the same.)
#Named("loginbean")
#ViewScoped
public class LoginBean implements Serializable {
private static final long serialVersionUID = 1L;
private String username;
#Inject private ExternalContext externalContext;
#Inject private SessionBean session;
#Inject private SessionManager sessionMgr;
public String killOldestDoLogin() {
List<SessionInfo> sessions = sessionMgr.getSessions();
SessionInfo oldest = sessions.get(0);
sessionMgr.killSession(oldest.getSessionId());
return doLogin();
}
public String doLogin() {
username = username.trim();
if (username != null && username.length() > 0) {
// After a successful login, avoid session fixation attacks by
// rotating the session ID. This isn't strictly necessary as Faces has
// its own session ID that a third party wouldn't have access to
if (externalContext != null) {
HttpServletRequest request = (HttpServletRequest) externalContext.getRequest();
if (request != null && request.isRequestedSessionIdValid()) {
newSessionId = request.changeSessionId();
}
}
HttpSession http = (HttpSession)externalContext.getSession(false);
session.setUsername(username);
session.setHttpSession(http);
sessionMgr.addSession(http, session);
}
return "startPage.jsf");
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
.
#Named("sessionbean")
#SessionScoped
public class SessionBean implements Serializable {
private static final long serialVersionUID = 1L;
private String username;
private HttpSession httpSession;
public void reset() {
username = null;
httpSession = null;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public HttpSession getHttpSession() {
return httpSession;
}
public void setHttpSession(HttpSession session) {
this.httpSession = session;
}
public String getSessionId() {
return httpSession == null ? "null" : this.httpSession.getId();
}
}
.
#Named("sessionmanager")
#ApplicationScoped
public class SessionManager {
private HashMap<String,HttpSession> sessionMap = new HashMap<>();
private HashMap<String,SessionBean> beanMap = new HashMap<>();
public void addSession(HttpSession http, SessionBean bean) {
beanMap.put(http.getId(), bean);
sessionMap.put(http.getId(), http);
}
public boolean killSession(String sessionId) {
HttpSession session = sessionMap.get(sessionId);
sessionMap.remove(sessionId);
beanMap.remove(sessionId);
if (session != null) {
session.invalidate();
}
return session != null;
}
public List<SessionInfo> getSessions() {
List<SessionInfo> result = new ArrayList<>();
for (String sessionId : sessionMap.keySet()) {
SessionBean bean = beanMap.get(sessionId);
HttpSession http = sessionMap.get(sessionId);
SessionInfo info = new SessionInfo();
info.setUsername(bean.getUsername());
info.setSessionId(sessionId);
info.setHttpSession(http));
result.add(info);
}
return result;
}
}
.
public class SessionInfo {
private String username;
private String sessionId;
private HttpSession httpSession;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getSessionId() {
return sessionId;
}
public void setSessionId(String sessionId) {
this.sessionId = sessionId;
}
public HttpSession getHttpSession() {
return httpSession;
}
public void setHttpSession(HttpSession httpSession) {
this.httpSession = httpSession;
}
}

JSF beans and object [duplicate]

This question already has an answer here:
How to send form input values and invoke a method in JSF bean
(1 answer)
Closed 5 years ago.
I have a JSF project, and I am trying to do a login page, in my project I have a managed bean that has a validate method for the username and password, and I have a bean class with setters and getters which has the user info that get filled for a database eg.(username, password, isActive, Full name), my question is how can I call the user info in JSF el expression in my xhtml pages if they are not in the managed bean?
Here is my java bean:
#Table(name="students_info")
public class User {
#Column(name="std_record_id")
private int id;
#Column(name="std_id")
private String userId;
#Column(name="first_name")
private String firstName;
#Column(name="web_password")
private String password;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
And here is my MBLogin:
#ManagedBean
#SessionScoped
public class MBLogin {
User user = new User();
LoginDAO loginDao = new LoginDAO();
public String validteStudent() {
boolean valid = loginDao.validateStudent(user.getUserId(), user.getUserId());
if (valid) {
HttpSession session = SessionUtils.getSession();
session.setAttribute("username", user);
return "student";
} else {
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_WARN,
"Incorrect Username and Passowrd", "Please enter correct username and Password"));
return "login";
}
}
}
Add a getter for the user:
#ManagedBean
#SessionScoped
public class MBLogin {
User user = new User();
LoginDAO loginDao = new LoginDAO();
public String validteStudent() {
boolean valid = loginDao.validateStudent(user.getUserId(), user.getUserId());
if (valid) {
HttpSession session = SessionUtils.getSession();
session.setAttribute("username", user);
return "student";
} else {
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_WARN,
"Incorrect Username and Passowrd", "Please enter correct username and Password"));
return "login";
}
}
public User getUser() {
return user;
}
}
Then in your xhtml you can call it like this:
#{user.id}, #{user.firstName}

JSF2 facelets and mvc

I'm trying to use mvc in my JSF2 facelets webapplication.
This is my logincontroller:
#ManagedBean
#ApplicationScoped
public class LoginControllerImpl implements LoginController{
#ManagedProperty(value = "#{applicationBean}")
private ApplicationBean applicationBean;
#Override
public boolean checkLogin(String username, String password) {
Store store = applicationBean.getStore(); //my model and my data are in this object
try {
store.checkLogin(username, password);
return true;
} catch (LoginException ex) {
return false;
}
}
}
This is my loginBean:
#ManagedBean
#SessionScoped
public class LoginBean implements Serializable{
#ManagedProperty(value="#{loginController}")
private LoginController loginController;
private String username;
private String password;
public void checkLogin(){
loginController.checkLogin(username, password);
}
}
Now I want to redirect the user to a welcome page when checklogin is true. Any ideas/tips how i should do that?
You can use implicit navigation, just return the page to which you want to access (relative to the current URL)
#ManagedBean
#SessionScoped
public class LoginBean implements Serializable{
#ManagedProperty(value="#{loginController}")
private LoginController loginController;
private String username;
private String password;
public String checkLogin(){
if (loginController.checkLogin(username, password)) {
return "welcome.xhtml";
}
return null; // won't change page
}
}

JSF display username when the user login

How can I display the username from the userindex page once the user successfully login. Should I be pass it to the constructor and use it? or is there any better solution for this?
Create a session-scoped bean that stores either the user's ID (so you can lookup the user per request) or the actual user object itself.
#Named // or #ManagedBean
#SessionScoped
public class SessionGlobals {
private Integer userId;
public boolean isLoggedIn() {
return userId != null;
}
public Integer getUserId() {
return userId;
}
public void login(int userId) {
this.userId = userId;
}
public void logout() {
this.userId = null;
}
Inject this bean wherever it is required. When you login and logout, call the appropriate methods above.
For example:
#Named // or #ManagedBean
#RequestScoped
public class RequestGlobals {
public User getUser() {
return sessionGlobals.isLoggedIn()
? userDao.findById(sessionGlobals.getUserId())
: null;
}
#Inject
private UserDao userDao;
#Inject
private SessionGlobals sessionGlobals;
}
and in your page or template:
<h:outputText value="Welcome, #{requestGlobals.user.firstName}"
rendered="#{sessionGlobals.loggedIn}"/>

JSF - Get the SessionScoped Bean instance

I have this configuration on my web application. 2 beans :
1° Bean - It checks the login;
#ManagedBean(name="login")
#SessionScoped
public class Login {
private String nickname;
private String password;
private boolean isLogged;
public String getNickname() { return nickname; }
public void setNickname(String newValue) { nickname=newValue; }
public String getPassword() { return password; }
public void setPassword(String newValue) { password=newValue; }
public void checkLogin() {
... i check on db the nickname and the password ...
if(USER EXIST) {
isLogged=true;
} else {
isLogged=false;
}
return true;
}
}
2° Bean - Manage User parameter :
#ManagedBean(name="user")
#SessionScoped
public class User {
private String name;
private String surname;
private String mail;
public User() {
String[] record=null;
Database mydb=Configuration.getDatabase();
mydb.connetti();
ArrayList<String[]> db_result=null;
db_result=mydb.selectQuery("SELECT name, surname, mail, domicilio FROM users WHERE nickname='???????'");
int i = 0;
while (i<db_result.size() ) {
record=(String[]) db_result.get(i);
i++;
}
}
... getter and setter methods...
}
As you can see, I would like to know how get the nickname setted previously on my login bean, so i can do the query on my DB.
In fact i need to get the instance of the current-session bean login : how can I get it? I should use somethings like session.getBean("login") :)
Hope this question is clear :)
Use #ManagedProperty to inject it and use #PostConstruct to access it after bean's construction (because in a normal constructor it would be still null).
#ManagedBean
#SessionScoped
public class User {
#ManagedProperty(value="#{login}")
private Login login;
#PostConstruct
public void init() {
// Put original constructor code here.
}
// Add/generate getters/setters and other boilerplate.
}
That said, this is not the correct approach. You'd like to do it the other way round. Inject User in Login by #ManagedProperty(value="#{user}") and do the job during submit action method.
You'd also like to put the password in WHERE clause as well. There's absolutely no need to haul the entire users table into Java's memory and determine it one by one. Just let the DB do the job and check if it returns zero or one row.
Also try using the following code:
ExternalContext tmpEC;
Map sMap;
tmpEC = FacesContext.getCurrentInstance().getExternalContext();
sMap = tmpEC.getSessionMap();
login loginBean = (login) sMap.get("login");

Resources