In my work is used the following pattern: ManagedBeans always have a single Service. When we need to use a different service in ManagedBean, create a method in Service using the Service needed.
But I was wondering if the most correct would be to have all necessary Services injected directly into ManagedBean because I found it very annoying to have to always create methods in the Services only to call other Services. Also apparently it decreases the cohesion of the Service as it will eventually having methods that should not have.
This is the way used in my work.
#ManagedBean
#ViewScoped
public class UserController {
private User user;
private List<Job> jobs;
#Inject
private UserService userService;
#PostConstruct
public void init() {
users = userService.listAllJobs();
}
public User getUser() {
return user;
}
public List<Job> getJobs() {
return jobs;
}
public void saveUser() {
userService.save(user);
}
}
#Stateless
public class UserService{
#Inject
private JobService jobService;
public List<Job> listAllJobs(){
jobService.listAll();
}
}
This is the way I prefer and also think more correct. Instead of create listAllJobs method in UserService, making it less cohesive, i just injected the JobService into UserController. And that's how I will do with all the services i need for this ManagedBean
#ManagedBean
#ViewScoped
public class UserController {
private User user;
private List<Job> jobs;
#Inject
private UserService userService;
#Inject
private JobService jobService;
#PostConstruct
public void init() {
users = jobService.listAll();
}
public User getUser() {
return user;
}
public List<Job> getJobs() {
return jobs;
}
public void saveUser() {
userService.save(user);
}
}
i want to use in second way in my work but dont know if is the best way. Please tell me whats the best and the advantages
Related
Still learning JSF and Java and having trouble understanding how to access a session bean property.
I have a LoggedUser session bean which sets the user that is logged in(using the login method).
#ManagedBean(name="loggedUser")
#Stateless
#LocalBean
#SessionScoped
public class LoggedUser {
#EJB
UserEJB userEJB;
#PersistenceContext
private EntityManager em;
private UserEntity loggedUser;
private String loginUserName;
private String loginPassword;
public LoggedUser() {}
public UserEntity getLoggedUser() {
return loggedUser;
}
public void setLoggedUser(UserEntity loggedUser) {
this.loggedUser = loggedUser;
}
public String authenticate() {
if (loggedUser == null) {
return "login.xhtml";
} else {
return "";
}
}
public String login() {
if (userEJB.validateLogin(loginUserName, loginPassword)) {
setLoggedUser(userEJB.fetchUser(loginUserName));
return "index.xhtml";
}
return "";
}
public String getLoginUserName() {
return loginUserName;
}
public void setLoginUserName(String loginUserName) {
this.loginUserName = loginUserName;
}
public String getLoginPassword() {
return loginPassword;
}
public void setLoginPassword(String loginPassword) {
this.loginPassword = loginPassword;
}
}
I want to be able to view the logged user from other areas in the application. I think I am injecting it incorrectly because loggedUser is always null when I am in a different bean for example something like..
#Stateless
#LocalBean
public class HistoryEJB {
#PersistenceContext
EntityManager em;
#ManagedProperty(value = "#{loggedUser}")
private LoggedUser loggedUser;
public LoggedUser getLoggedUser() {
return loggedUser;
}
public void setLoggedUser(LoggedUser loggedUser) {
this.loggedUser = loggedUser;
}
public void testLoggedUser() {
loggedUser.getLoggedUser();
// Just an example but would be null here - why?
}
}
How can I access this property from other areas in my application? Thanks for any help.
You can't use #ManagedProperty in an EJB and you shouldn't inject a view component into a business-tier component, period. #ManagedProperty is strictly web-tier stuff and is able to inject only and into web-tier, JSF components.
Your EJB ought to have a method that accepts a LoggedUser. This way, you can then pass your logged-in user to the EJB (which is the proper flow of data in a web application). What you have now is just turning best practice on its head.
So
Add a provideLoggedUser(LoggedUser loggedUser) method to your EJB
Call that method on your instance of UserEJB from within your managed bean
Rule of Thumb: Your EJB should not be aware of the web application
It seems you are missing the setter and getter for loggedUser. In principe it is there but it is convention to name it as follows
setProperty
and
setProperty
for a field named property. Note the capital first letter of the field name in the setter and getter!
I have a little javaee webproject and i need bean injection in it. i have a tomee server with cdi enabled. Here is a little test case.
Here is my #SessionScoped User object
import javax.enterprise.context.SessionScoped;
import java.io.Serializable;
#SessionScoped
public class User implements Serializable {
String userName;
public User () {}
public User (String userName) { this.userName = userName; }
public String getUserName() { return userName; }
public void setUserName(String userName) { this.userName = userName; }
}
and here are my two nearly identical beans:
#Named
#RequestScoped
public class BeanOne {
private String message;
#Inject User user;
#PostConstruct
public void init() { user = new User("TestName"); }
public String getMessage() { return user.getUserName(); }
}
In this bean i create a new user. the method getMessage returns the correct user name. I thought the user should still exist in the second bean because its #SessionScoped. Here is my second bean.
#Named
#RequestScoped
public class BeanTwo {
private String message;
#Inject User user;
public String getMessage() { return user.getUserName(); }
}
But in this bean the user.getUserName() returns null. How am i supposed to inject a #SessionScoped bean?
This happens because you have manually initialized user object in BeanOne init method. The purpose of dependency injection is to let some container create instances of objects for you, so you should never initialize objects manually. So just set a name for this user and it will be visible during session for all other beans.
#PostConstruct
public void init() { user.setUserName("TestName"); }
I want to use the same object "User" within the Farma and the Pata objects. The object user is first initialized inside the Farma object. I tried to annotated with #inject, but the object user inside Pata, has the name with null value. Please, can anyone help me understand what I am doing wrong? Thank!
#Named
#SessionScoped
public class Farma implements Serializable {
#Inject private User user;
#PostConstruct
public void initialize(){
user.setName("MyName");
}
// Getters and Setters
}
#Named
#SessionScoped
public class Pata implements Serializable {
#Inject private User user;
public String getFuzzyName() {
// Here I want to use the object "user" with the name "MyName" to do some logic
}
// Getters and Setters
}
public class User implements Serializable {
private String name;
// Getters and Setters
Just scoping a User object won't allow you to initialize it.
Use "producer method" to control bean's creation.
Try this:
#SessionScoped
public class Pata implements Serializable {
#Inject
#SessionUser // inject here using the producer method
private User user;
public String getFuzzyName() {
return user.getName();
}
}
#SessionScoped
public class Farma implements Serializable {
#Produces
#SessionUser // qualifier to tie injection points to this method
#SessionScoped // to ensure it will be called once per session for any number of injection points
public User produceUser() {
System.out.println("Creating user");
User u = new User();
u.setName("User");
return u;
}
}
////// that's your custom qualifier, it's in a separate file
#Qualifier
#Retention(RetentionPolicy.RUNTIME)
#Target({METHOD, FIELD, PARAMETER, TYPE})
public #interface SessionUser {}
// no scopes here, it is defined by the producer method
public class User implements Serializable {
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
You need to understand scoping of CDI beans. The default scope, if none is specified, is the #Dependent scope, which means that an object exists to serve exactly one client (bean) and has the same lifecycle as that client (bean).
In this case it means that the user in Farma only exists for the Farma class and lives for the life of the Farma class.
The user in Pata is a different instance, and its lifecycle matches that of Pata.
You need to properly scope the User object.
As axiopisty said, adding #Named #SessionScoped is the correct way.
I tried and it works great.
#Named
#SessionScoped
public class Pata implements Serializable {
#Inject
private User user;
public String getFuzzyName() {
System.out.println(user.getName());
return user.getName();
}
public User getUser() {
return user;
}
public void setUser(final User user) {
this.user = user;
}
}
#Named
#SessionScoped
public class Farma implements Serializable {
#Inject
private User user;
#PostConstruct
public void initialize() {
user.setName("MyName");
}
// Getters and Setters
public User getUser() {
return user;
}
public void setUser(final User user) {
this.user = user;
}
}
#Named
#SessionScoped
public class User implements Serializable {
private String name = "Default";
public String getName() {
return name;
}
public void setName(final String name) {
this.name = name;
}
}
<h:outputText value="#{farma}"></h:outputText><br />
<h:outputText value="#{pata}"></h:outputText><br />
<h:outputText value="#{pata.fuzzyName}"></h:outputText>
I am using picketlink to authenticate a user on project. I also created a #produces annotated method, so I would be able to inject the authenticated user in other places. Now, I am using envers and besides the default information, I would like to store the user that performed the action, but I cannot inject it in the envers listener. It is always null. How can I make this injection, or retrieve this information?
The producer class:
#SessionScoped
public class Resources implements Serializable {
private static final long serialVersionUID = 1L;
#EJB
private AuthenticationManagerBean authenticator;
#Inject
private Identity credentials;
#CurrentUser
private AuthenticatedUser currentUser;
#Produces
#CurrentUser
#SessionScoped
private AuthenticatedUser createAuthenticatedUser() {
AuthenticatedUser user = new AuthenticatedUser();
org.picketlink.idm.model.basic.User loggedInUser = (org.picketlink.idm.model.basic.User) credentials.getAccount();
User pu = authenticator.getUserRoles(loggedInUser.getLoginName());
if (pu != null) {
user.setUser(pu.getName());
for (Role role : pu.getRoles()) {
user.getRoles().add(role.getName());
}
}
return user;
}
#Produces
public Logger produceLog(InjectionPoint injectionPoint) {
return LoggerFactory.getLogger(injectionPoint.getMember().getDeclaringClass().getName());
}
and the envers listener:
public class AuditListener implements RevisionListener, Serializable {
private static final long serialVersionUID = 1L;
#Inject
#CurrentUser
private AuthenticatedUser identity; //this is always null
public void newRevision(Object revisionEntity) {
System.out.println(identity.getUser());
}
}
I had a similiar problem. The injection does not work because RevisionListener is not managed by CDI. That way, you have to lookup for the bean yourself. This is the way you could do it:
public AuthenticatedUser getAuthenticatedUser() {
BeanManager beanManager = (BeanManager) new InitialContext().lookup("java:comp/BeanManager");
Bean<AuthenticatedUser> bean = (Bean<AuthenticatedUser>) beanManager.getBeans(AuthenticatedUser.class, new AnnotationLiteral<CurrentUser>() {
}).iterator().next();
CreationalContext<AuthenticatedUser> ctx = beanManager.createCreationalContext(bean);
return (AuthenticatedUser) beanManager.getReference(bean, AuthenticatedUser.class, ctx);
}
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");