I read BalusC's excellent tutorial on JSF communication and it helped me establish the basics of my app. I would like to share the currently logged in User object that is set in the SessionScoped BaseBean class with all of its subclasses. Can this be done without injecting BaseBean as a @ManagedProperty
for every single backing bean that needs to reference the logged in User?
My classes are listed below. Please let me know if more info is needed and I will be happy to update my question.
BaseBean Class
All other beans are subclasses of this bean. I am doing this to allow code reuse between beans.
@ManagedBean
@SessionScoped
public class BaseBean {
@EJB
protected UserDao userDao;
// Other DAOs along with methods (like isLoggedIn()) shared between beans
private User loggedInUser;
public User getLoggedInUser() {
return loggedInUser;
}
public void setLoggedInUser(User user) {
loggedInUser = user;
}
public boolean isLoggedIn() {
return loggedInUser != null;
}
}
LoginBean Class
Backing bean for the login page. To reduce number of DB calls I used the @ManagedProperty approach from the above tutorial to set the User object in the @SessionScoped BaseBean. Right now logging in and setting loggedInUser
works as expected.
@ManagedBean
@RequestScoped
public class LoginBean extends BaseBean {
@ManagedProperty(value = "#{baseBean}")
protected BaseBean baseBean;
private String username;
private String password;
public String login() {
Subject currentUser = SecurityUtils.getSubject();
try {
currentUser.login(username, password);
} catch (Exception e) {
e.printStackTrace();
} finally {
baseBean.setLoggedInUser(userDao.getUser(username));
}
return "index";
}
public String getUserFirstName() {
return baseBean.getLoggedInUser().getFirstName();
}
// Getters and Setters, including for the @ManagedProperty baseBean.
}
CreateReport Class
This is an example of one backing bean from many. I want to reference the currently logged in User in order to create a report, however if the below code runs the User will be null
! The only way I can get it to work is by adding a @ManagedProperty
entry with getters and setters for BaseBean just like in LoginBean class. I would really like to avoid this as I will be copy-pasting this code to almost every single backing bean that I have!
@ManagedBean
@RequestScoped
public class CreateReport extends BaseBean {
private Report report = new Report();
public String createReport() {
report.setOwner(getLoggedInUser()); // Use inherited method
// instead of DI-ing BaseBean
reportDao.create(report);
return "index";
}
}
Used Software
- Glassfish 4
- Mojarra 2.2
Edit
One solution that I found is getting the instance of BaseBean from the FacesContext directly (I guess somehow the other beans are not in the same context or "don't see it?"). The following code (from BaseBean) would do what I want, however any bean subclass would have to invoke base()
and that seems awkward and wrong.
protected FacesContext context = FacesContext.getCurrentInstance();
public BaseBean base() {
return (BaseBean) context.getApplication().evaluateExpressionGet(context, "#{baseBean}", BaseBean.class);
}
@ManagedProperty
and/or managed beans. – Tiny@ManagedProperty
orFacesContext
are the solutions that I have found so far, however I want to find a better approach using Mojarra. Where my flexibility stops is the tech: I have to use Mojarra and Glassfish. – Lev@ManagedProperty
, for readability and maintainability. Having a method that does the magic might not look too good in code, to the next guy – kolossus