picketlink, envers and cdi injection - cdi

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);
}

Related

Show how many Users logged in with JSF

i trie to run this code
#ManagedBean
#ApplicationScoped
public class Controller implements Serializable {
private static final long serialVersionUID = 1L;
private Benutzer benutzer;
private List<Erfasst> bisherErfasst = new ArrayList<Erfasst>();
private EntityManagerFactory emf = Persistence
.createEntityManagerFactory("CP Kontrolle");
private static Controller instance = new Controller();
public Benutzer getBenutzer() {
return benutzer;
}
public boolean anmelden(String email, int kdnr) {
EntityManager em = emf.createEntityManager();
Query query = em
.createQuery("SELECT b FROM Benutzer b WHERE b.email = :email AND b.kdnr = :kdnr");
query.setParameter("email", email);
query.setParameter("kdnr", kdnr);
List<Benutzer> liste = query.getResultList();
em.close();
if (liste.size() == 1) {
benutzer = liste.get(0);
AngemeldeteBenutzer.getAb().hinzufuegen(benutzer);
return true;
} else {
return false;
}
}
public static Controller getInstance() {
return instance;
}
[....]
}
}
The above code is my ControllerBean. From the Login-Form, user data will be checked in the "anmelden" Class and return true or false if it was successfully.If successfully, the user will be store into a list, as you can see.
#ManagedBean
#ApplicationScoped
public class AngemeldeteBenutzer implements Serializable {
private static final long serialVersionUID = 1L;
private List<Benutzer> online = new LinkedList<Benutzer>();
private static AngemeldeteBenutzer ab = new AngemeldeteBenutzer();
public static AngemeldeteBenutzer getAb() {
return ab;
}
public List<Benutzer> getOnline() {
return online;
}
public void hinzufuegen(Benutzer benutzer) {
online.add(benutzer);
}
}
This is my other Bean, which store the successfully logged user into a list.
Now i want to list all user into my table, but my table is still empty. No errors!
<h:panelGrid columns="2" id="onlinePanel" >
<h:dataTable value="#{angemeldeteBenutzer.online}" var="on">
<h:column>
<f:facet name="header">Email</f:facet>
<h:outputText value="#{on.email}"></h:outputText>
</h:column>
</h:dataTable>
</h:panelGrid>
The mistake is here:
private static Controller instance = new Controller();
public static Controller getInstance() {
return instance;
}
private static AngemeldeteBenutzer ab = new AngemeldeteBenutzer();
public static AngemeldeteBenutzer getAb() {
return ab;
}
You seem to have missed the point of a bean management framework with dependency injection support. You seem to be expecting that #{angemeldeteBenutzer} in the JSF page is referring exactly the same instance as you manually created there with new operator and are filling with users.
This is Wrong! You have there two instances of the class, one automatically created by JSF and available via #{angemeldeteBenutzer} and another one manually created by yourself and available via that getAb() method only.
Get rid of all those static fields and methods. They don't belong there. Instead, use #ManagedProperty to let JSF inject managed beans in each other. Add this code to the Controller class.
#ManagedProperty("#{angemeldeteBenutzer}")
private AngemeldeteBenutzer ab;
public AngemeldeteBenutzer getAb() {
return ab;
}
public void setAb(AngemeldeteBenutzer ab) {
this.ab = ab;
}
And replace in the same Controller class this line
AngemeldeteBenutzer.getAb().hinzufuegen(benutzer);
by
ab.hinzufuegen(benutzer);
Note: if you're already on Java EE 7, consider using CDI #Named instead of JSF #ManagedBean. When injecting via #Inject instead of #ManagedProperty, you don't need those ugly getter/setter anymore.
#Named
#ApplicationScoped
public class AngemeldeteBenutzer {
}
#Named
#ApplicationScoped
public class Controller {
#Inject
private AngemeldeteBenutzer ab;
}
Unrelated to the concrete problem, the Controller doesn't seem to be a legit application scoped bean. It looks too much like a view scoped bean due that view-specific variables and business logic. Make sure you understand the scopes: How to choose the right bean scope?

Access Session Bean Property/Inject Session Bean

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!

GlassFish ManagedBeanCreationException and NullPointerException

I have written an EJB and a dynamic web project Eclipse on GlassFish server. I used DAO , Facade and JPA. Normally I am calling a method from my service it is giving these errors ;
kitapOduncVerme.xhtml]com.sun.faces.mgbean.ManagedBeanCreationException
PWC1406: Servlet.service() for servlet Faces Servlet threw exceptionjava.lang.NullPointerException
at com.mesutemre.kitapislemleri.KitapOduncVermeBean.initList(KitapOduncVermeBean.java:47)
at com.mesutemre.kitapislemleri.KitapOduncVermeBean.initialize(KitapOduncVermeBean.java:43)
My codes are below;
#ManagedBean(name = "oduncKitapVerBean")
#ViewScoped
public class KitapOduncVermeBean implements Serializable{
private static final long serialVersionUID = 1L;
private List<Kitaplar> entityList = new ArrayList<Kitaplar>();
private Kitaplar selectedEntity;
private Kitaplar entity;
private String kullaniciadi;
private KitaplarFacade service;
public KitapOduncVermeBean() {
entity = new Kitaplar();
selectedEntity = new Kitaplar();
}
#PostConstruct
public void initialize(){
HttpSession session = Util.getSession();
kullaniciadi = Util.getUserName();
initList();
}
private void initList(){
entityList = service.findAllKitaplar();
}
DaoImpl
#SuppressWarnings("unchecked")
public List<Kitaplar> findAllKitaplar(){
return em.createNamedQuery("tumkitaplarigetir").getResultList();
}
Dao
#Stateless
#LocalBean
public class KitaplarDAO extends KitaplarDaoImpl<Kitaplar> implements Serializable{
private static final long serialVersionUID = 1L;
#Override
public List<Kitaplar> findAllKitaplar() {
return super.findAllKitaplar();
}
FacadeImpl
#Stateless
#LocalBean
public class KitaplarFacadeImpl implements KitaplarFacade,Serializable {
private static final long serialVersionUID = 1L;
#EJB
KitaplarDAO kitapDao;
#Override
public List<Kitaplar> findAllKitaplar() {
return kitapDao.findAllKitaplar();
}
}
Facade
#Local
public interface KitaplarFacade {
public abstract List<Kitaplar> findAllKitaplar();
}
I can't see any problem in this codes? But Why am I getting that errors?
ManagedBeanCrearionException is simply wrapping and rethrowing the NullPointerException, that is very easy to debug: you have a null variable at the exact line that appears in the stack trace.
In KitapOduncVermeBean class, you are declaring service property, but you are not initializing it, therefore it's null when invoked in initList() method. Since it's an EJB, annotate it as such and the EJB container will instantiate it automatically:
#EJB
private KitaplarFacade service;
Unrelated to the concrete problem, your code is too complicated: with EJB 3.x, in most web applications, you don't need EJBs to implement or expose interfaces.

How to use CDI and Dependency Injection

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>

CDI not working when Injecting in Generics class - Java

I'm having problems with CDI on tomcat. That's some relevant part of my code:
public class JPAUtil {
private static EntityManagerFactory emf = Persistence.createEntityManagerFactory("unit");
#Produces #RequestScoped
public static EntityManager getEntityManager() {
return emf.createEntityManager();
}
public void close(#Disposes EntityManager em) {
em.close();
}
}
My DAO Class:
public class DAO<T> implements Serializable{
private final Class<T> classe;
#Inject
protected EntityManager em;
public DAO(Class<T> classe) {
this.classe = classe;
}
}
and a child class:
public class UserDao extends DAO<User> implements Serializable{
public UserDao() {
super(User.class);
}
}
Because of the Generics, I used a producer for the DAO class:
public class DAOFactory {
#Produces
#SuppressWarnings({ "rawtypes", "unchecked" })
public DAO createDAO(InjectionPoint injectionPoint) {
ParameterizedType type = (ParameterizedType) injectionPoint.getType();
Class classe = (Class) type.getActualTypeArguments()[0];
return new DAO(classe);
}
}
In this example:
public class Test {
#Inject UserDAO userDAO;
#Inject DAO<User> dao;
}
When I try to use the UserDAO class, everything works fine, but when I use the DAO, the EntityManager remains null. Anyone have any idea?
In DAOFactory you instantiate the DAO with new operator, if you do so, CDI has no chance to inject dependencies in the DAO instance.
While in UserDAO CDI manages the entity manager injection.
So in DAOFactory you should set manually the entity manager in the newly created DAO instance.

Resources