I have an EJB that handles creation of customer user accounts that needs access to a managed bean (account scoped) which manages user verification keys for user accounts (the keys are transient, so they don't need to be handled by database calls). However, I can't figure out a way to send the verification key to the EJB (which generates the verification email that is send to a user).
AccountVerifierBean.java
#ManagedBean(name = "accountVerifierBean", eager = true)
#ApplicationScoped
public class AccountVerifierBean implements Serializable {
private HashMap<String, String> verificationKeyMapping;
public AccountVerifierBean() {}
public boolean verifyKey(String username, String key) {
return key.equals(verificationKeyMapping.get(username));
}
public String generateKey(String username) {
Date time = new Date();
String key = username + time.toString();
key = Encryption.hashSHA(key);
verificationKeyMapping.put(username, key);
return key;
}
}
CustomerService.java
#Named
#Stateless
#LocalBean
public class CustomerService {
#PersistenceContext(unitName = "MovieProject-ejbPU")
private EntityManager em;
private String username;
private String password;
//getters and setters
public void validateEmail() {
Properties serverConfig = new Properties();
serverConfig.put("mail.smtp.host", "localhost");
serverConfig.put("mail.smtp.auth", "true");
serverConfig.put("mail.smtp.port", "25");
try {
Session session = Session.getInstance(serverConfig, new Authenticator() {
#Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication("<ACCOUNT>","<PASSWORD>");
}
});
MimeMessage message = new MimeMessage( session );
message.setFrom(new InternetAddress("accounts#minimalcomputers.com","VideoPile"));
message.addRecipient(
Message.RecipientType.TO, new InternetAddress(username)
);
message.setSubject("Welcome to VideoPile!");
message.setContent("<p>Welcome to VideoPile, Please verify your email.</p><p>" + verifierKey + "</p>", "text/html; charset=utf-8"); //verifierKey is what I'm trying to get from AccountVerifierBean.
Transport.send( message );
}
catch (MessagingException ex){
Logger.getLogger(CustomerService.class.getName()).log(Level.SEVERE, null, ex);
}
catch (Exception e) {
Logger.getLogger(CustomerService.class.getName()).log(Level.SEVERE, null, e);
}
}
public String encrypt(String password) {
try {
return new String(Base64.encode(MessageDigest.getInstance("SHA").digest(password.getBytes())));
} catch (NoSuchAlgorithmException ex) {
Logger.getLogger(CustomerService.class.getName()).log(Level.SEVERE, null, ex);
return null;
}
}
}
I've tried #Inject, #ManagedProperty, using the Application map, and using the ELContext. Nothing seems to work.
EDIT:
I think there is something wrong with the bean. Any methods called from bean don't seem to do anything (EL is resolved, no bean method calls though).
I've tested the annotations that it uses (both are javax.faces.bean.*)
So, the issue was in the AccountVerifierBean.
I added the following lines to faces-config.xml and it is now working.
<managed-bean eager="true">
<managed-bean-name>accountVerifierBean</managed-bean-name>
<managed-bean-class>org.Videotheque.beans.AccountVerifierBean</managed-bean-class>
<managed-bean-scope>application</managed-bean-scope>
</managed-bean>
I'm fairly certain that the problem was because my bean needed to be in the EJB package instead of the WAR so that the EJBs can access it, but because of that, the WAR didn't know that the bean existed.
Related
I'm just testing to migrate from Seam3 to DeltaSpike, everything is ok if there is only one EntityManager in a bean, but there will be a error if add other EntityManager(other datasource):
JBAS010152: APPLICATION ERROR: transaction still active in request with status 0
the error project:
https://github.com/yuanqixun/hellodeltaspike
run this project environment:
wildfly 8.2.0.Final
H2 datasource
MySql datasource
The EntityManagerProducer code:
#ApplicationScoped
public class EntityManagerProducer {
#PersistenceUnit(unitName = "hellodeltaspike")
EntityManagerFactory emf;
#PersistenceUnit(unitName = "hellodeltaspike2")
EntityManagerFactory mysqlemf;
#Produces
#ConversationScoped
EntityManager createEntityManager(){
return this.emf.createEntityManager();
}
#Produces
#MySqlEm
#ConversationScoped
EntityManager createMysqlEntityManager(){
return this.mysqlemf.createEntityManager();
}
}
The Action code:
#ConversationScoped
#Named
public class PersonAction implements Serializable{
#Inject
EntityManager em;
#Inject
#MySqlEm
EntityManager mysqlEm;
Person person;
List<Person> personList;
#PostConstruct
void afterCreate(){
person = new Person();
personList = queryPersonList();
}
private List<Person> queryPersonList() {
String jql = "select o from Person o ";
List<Person> result = em.createQuery(jql,Person.class).getResultList();
if(result == null)
return new ArrayList<Person>();
return result;
}
#Transactional
public void btnDoSave(ActionEvent event){
try {
if(StringUtils.isEmpty(person.getUuid())){
em.persist(person);
}else{
em.merge(person);
}
em.flush();
String msg = "Saved:"+person.getName();
FacesContext.getCurrentInstance().addMessage(null,new FacesMessage(FacesMessage.SEVERITY_INFO,msg,null));
person = new Person();
personList = queryPersonList();
} catch (Exception e) {
e.printStackTrace();
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, e.getMessage(), null));
}
}
...getter and setter
}
and there will be error:
ERROR [org.jboss.as.txn] (default task-6) JBAS010152: APPLICATION ERROR: transaction still active in request with status 0
Modify the method's annotation,add the special qualifier of the right EntityManager, so the problem will be solved. But also has another problem, how to support multiple entityManager's transaction in one method?
#Transactional(qualifier = {H2Em.class})
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 problem with entities not being refreshed when values in the database are changed from outside the JPA session. For instance, I have a user entity:
#Entity
#Cacheable(false)
public class UserBean implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#OneToMany(mappedBy = "receiver")
#JoinTable(name = "NOTIFICATIONS_RECEIVED")
private List<NotificationBean> notificationsReceived;
...
}
And notifications entity:
#Entity
#Cacheable(false)
public class NotificationBean implements Serializable{
#Id
#GeneratedValue
private Long id;
#ManyToOne
private UserBean receiver;
...
}
I use this inside a JSF application and have a SessionScoped bean, which loads the user after login and stores it:
#Named("sessionManager")
#SessionScoped
public class SessionManagerBean implements Serializable {
#PersistenceUnit(unitName = "PU")
private EntityManagerFactory emf;
private UserBean user;
public UserBean getUser() throws Exception {
if (user == null) {
FacesContext context = FacesContext.getCurrentInstance();
HttpServletRequest request = (HttpServletRequest) context.getExternalContext().getRequest();
String username = request.getRemoteUser();
if (username != null) {
EntityManager em = null;
try {
utx.begin();
em = emf.createEntityManager();
Query query = em.createQuery("SELECT u from UserBean u WHERE u.username = ?1");
query.setParameter(1, username);
user = (UserBean) query.getSingleResult();
}
catch (Exception e) {
try {
utx.rollback();
} catch (Exception e) {
} finally {
utx.commit();
em.close();
}
}
return user;
}
}
}
public void refreshUser() {
EnitytManager em = emf.createEntityManager();
// similar code as above to retrieve the user from the database
em.refresh(user);
}
}
The page which displays the notifications calls refreshUser() when it loads:
<f:metadata>
<f:event type="preRenderView" listener="#{sessionManager.refreshUser()}" />
</f:metadata>
The user data is not refreshed though and notifications which are displayed on the page are not updated when I refresh the page.
However, if I change refreshUser() to:
public void refreshUser() {
EntityManager em = emf.createEntityManager();
List<NotificationBean> notifications = em.createNativeQuery("SELECT * FROM NOTIFICATIONBEAN WHERE RECEIVER_ID = " +
user.getId() + ";").getResultList();
user.setMatchChallengesReceived(notifications);
}
the notifications are updated.
I have more variable than notifications that I need to refresh from the database and it would be a lot of code to do the same for each one. I thought em.refresh(user) should reload all variables that have changed from the database for me. I thought it is a caching issue, so I added #Cacheable(false) to UserBean and NotificationBean, but it has no effect.
What am I doing wrong?
If the problem is with notifications, then itis because refreshing user is not set to cascade the refresh. Set the CascadeType.REFRESH on the notificationsReceived mapping.
I am using a stateful EJB for keeping my login information:
#Stateful
public class SecurityService {
private static final Logger log4jLogger = Logger.getLogger(SecurityService.class);
#Inject UtenteDao utenteDao;
#Inject AutorizzazioneDao autorizzazioneDao;
private Utente utenteCorrente;
private Negozio negozioCorrente;
public SecurityService() {
}
public boolean authenticate() {
boolean result = false;
Principal principal = FacesContext.getCurrentInstance().getExternalContext().getUserPrincipal();
if (principal!=null) {
utenteCorrente = utenteDao.findByUsername(principal.getName());
}
if (negozioCorrente!=null && utenteCorrente!=null) {
Autorizzazione a = autorizzazioneDao.cercaPerNegozioAndUtente(negozioCorrente, utenteCorrente);
result = a!=null;
}
return result;
}
// ...
}
My JSF login page is controlled by:
#Named
#RequestScoped
public class LoginController {
#Inject private SecurityService securityService;
private String username;
private String password;
private Negozio negozio;
public void login() throws IOException {
FacesContext context = FacesContext.getCurrentInstance();
ExternalContext externalContext = context.getExternalContext();
HttpServletRequest request = (HttpServletRequest) externalContext.getRequest();
try {
if (request.getUserPrincipal() != null) {
request.logout();
}
request.login(username, password);
securityService.setNegozioCorrente(negozio);
if (!securityService.authenticate()) {
throw new ServletException("Utente non abilitato.");
}
externalContext.redirect("/pippo/");
} catch (ServletException e) {
e.printStackTrace();
context.addMessage(null, new FacesMessage("Accesso Negato"));
}
}
public void logout() throws IOException {
//...
}
public String getLoggedUsername() {
Utente utenteCorrente = securityService.getUtenteCorrente();
String fullName = "";
if (utenteCorrente!=null) {
fullName = utenteCorrente.getNomeCompleto();
} else {
System.out.println("Utente NULLO");
}
return fullName;
}
//...
}
My users actually can login the way I want (programmatic security with some adds from my domain).
The problem I have is in the next page, when you're already logged in. I want to display in all pages header "Welcome! You're logged in as #{loginController.loggedUsername}.
I keep getting a null securityService.getUtenteCorrente().
SecurityService EJB behaves like a Stateless session bean! I want to know whether I am misunderstanding something about the Stateful EJBs, or I just omitted something for this to work as I expect.
My goal is just to have a "session-wide" bean for keeping user state. Is a EJB necessary or can I just use a SessionScoped JSF ManagedBean?
LoginController is request-scoped and your SecurityService is dependent-scoped (for all purposes it is not session-scoped unless you specify it as such). Therefore, when the second JSF page references the LoginController in a EL expression, a new instance of LoginController would be created that would have a reference to a different instance of the SecurityService SFSB.
If you need to access the original SecurityService instance, you should mark it as #SessionScoped so that clients like the LoginController can access them across requests. But then, you might also want to consider why you need a #Stateful annotation in the first place, since this task could be done by an #SessionScoped managed bean. You don't really need a SFSB to store a reference to your User/Principal objects.
In order to be managed session beans must be declared using the #EJB annotation or looked up using the JNDI, the way you inject it just gives you a plain object not managed by the app server, in fact you create a new object any time you use it.
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");