I heav the following bean
#RequestScoped
public class MyJWT {
#Inject
JsonWebToken jwt;
private User loggedUser;
private String rawToken;
#PostConstruct
public void init() {
if (jwt != null && jwt.getRawToken() != null) {
this.loggedUser = User.findByEmail( jwt.getClaim(Claims.email.name()).toString());
this.rawToken = jwt.getRawToken();
}
}
but I don't see init is called ever. I mean, my debugger doesn't stop on any breakpoints inside. In case debugger is confused by instrumentation, I was also trying to add exception throwing inside, but didn't see any effect.
How is this possible?
Related
I am seeing this strange behavior when using #ManagedProperty. I have 2 beans:
UserManager (SessionScoped)
#ManagedBean
#SessionScoped
public class UserManager extends BaseBean implements Serializable
{
private static final long serialVersionUID = 1861000957282002416L;
private User currentUser;
public String login()
{
// set value of currentUser after authentication
}
public User getCurrentUser() {
return currentUser;
}
public boolean isLoggedIn() {
return getCurrentUser() != null;
}
}
CartBean (ALSO SessionScoped)
...
import javax.faces.bean.ManagedProperty;
...
#ManagedBean
#SessionScoped
public class CartBean extends BaseBean implements Serializable
{
#ManagedProperty(value = "#{userManager.loggedIn}")
private boolean loggedIn;
public void updateCart(Movie selectedMovie)
{
if (!loggedIn) {
return;
}
System.out.println("UPDATE CART REQUEST");
int id = selectedMovie.getMovieID();
if (cart.containsKey(id)) {
cart.remove(id);
}
else {
cart.put(id, selectedMovie);
}
}
public void setLoggedIn(boolean loggedIn) {
this.loggedIn = loggedIn;
}
}
After logging in successfully, the value of loggedIn still remains false.
However, if I change the scope of CartBean to #ViewScoped, the value of loggedIn gets updated and I see the sysout.
As per my understanding and also after reading various articles, one can inject a managed bean or its property only if it is of the same or broader scope. But the "same scope" case does not seem to work in my code. What am I missing here?
I am using:
Mojarra 2.1.16
Spring 3.2
Hibernate 4.1
Tomcat 7.0.37
#ManagedProperty annotation can only provide static injection, which means that the annotated property will get injected when and only when the holding #ManagedBean is instantiated.
When you deploy your application, I believe your CartBean was referenced right at the beginning through things like the View cart button, etc. As a consequence, the injection took place too early and since the bean is #SessionScoped, you will carry the initial false value till the end of time :).
Instead of injecting only the boolean field, you should, instead, inject the whole UserManager bean:
#ManagedBean
#SessionScoped
public class CartBean extends BaseBean implements Serializable {
#ManagedProperty(value = "#{userManager}")
private UserManager userManager;
public void updateCart(Movie selectedMovie) {
if (!userManager.isLoggedIn()) {
return;
}
...
}
}
The solution is using Omnifaces it worked for me each time the value change you will get the new value
#ManagedBean
#ViewScoped
public class CartBean extends BaseBean implements Serializable {
private boolean loggedIn;
public void updateCart(Movie selectedMovie) {
loggedIn=Faces.evaluateExpressionGet("#{userManager.loggedIN}");
if (!userManager.isLoggedIn()) {
return;
}
...
}
}
In our JavaEE6 project (EJB3, JSF2) on JBoss 7.1.1, it seems we have a memory leak with SeamFaces #ViewScoped.
We made a little prototype to check the fact :
we use JMeter to call a page 200 times;
the page contains and calls a viewscoped bean which injects a stateful EJB;
we fix the session timeout at 1 minute.
At the end of the test, we check the content of the memory with VisualVM, and here what we got:
with a #ViewScoped bean, we still get 200 instances of the stateful MyController - and the #PreDestroy method is never called;
with a #ConversationScoped bean, #preDestroy method is called a the session end and then we got a clean memory.
Do we badly use the view scope, or is it truly a bug?
Here's the XHTML page:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:s="http://jboss.org/seam/faces">
<f:metadata>
<f:viewParam name="u" value="#{myBean.uselessParam}" />
<s:viewAction action="#{myBean.callService}" />
</f:metadata>
<h:body >
<f:view>
</f:view>
</h:body>
</html>
Now the included bean myBean. For the #ConversationScoped variant, all commented parts are uncommented.
#ViewScoped
// #ConversationScoped
#Named
public class MyBean implements Serializable
{
#Inject
MyController myController;
//#Inject
//Conversation conversation;
private String uselessParam;
public void callService()
{
//if(conversation.isTransient())
//{
// conversation.begin();
//}
myController.call();
}
public String getUselessParam()
{
return uselessParam;
}
public void setUselessParam(String uselessParam)
{
this.uselessParam = uselessParam;
}
}
And then the injected stateful bean MyController:
#Stateful
#LocalBean
public class MyController
{
public void call()
{
System.out.println("call ");
}
#PreDestroy
public void destroy()
{
System.out.println("Destroy");
}
}
I see many developers are satisfied with #ViewAccessScoped in Myface CODI.
Could you please give it a try and tell the feedback.
I have faced the above mentioned problem in JSF managed #ViewScoped bean. After referring to few blogs I understood that JSF saves view bean states in http session and gets destroyed only when session is invalidated. Whenever we click on the jsf page every time new view scope bean referred in page is created. I did a work around using Spring Custom View Scope. It works fine. Below is the detail code.
For JSF 2.1:
Step 1: Create a View Scope Bean Post Construct Listener as follows.
public class ViewScopeBeanConstructListener implements ViewMapListener {
#SuppressWarnings("unchecked")
#Override
public void processEvent(SystemEvent event) throws AbortProcessingException {
if (event instanceof PostConstructViewMapEvent) {
PostConstructViewMapEvent viewMapEvent = (PostConstructViewMapEvent) event;
UIViewRoot viewRoot = (UIViewRoot) viewMapEvent.getComponent();
List<Map<String, Object>> activeViews = (List<Map<String, Object>>)
FacesContext.getCurrentInstance().getExternalContext().getSessionMap(). get("com.org.jsf.activeViewMaps");
if (activeViews == null) {
activeViews = new ArrayList<Map<String, Object>>();
activeViews.add(viewRoot.getViewMap());
FacesContext.getCurrentInstance().getExternalContext().getSessionMap(). put("com.org.jsf.activeViewMaps", activeViews);
} else {
activeViews.add(viewRoot.getViewMap());
}
}
}
Step 2: Register event listener in faces-config.xml
<system-event-listener>
<system-event-listener-class>
com.org.framework.custom.scope.ViewScopeBeanConstructListener
</system-event-listener-class>
<system-event-class>javax.faces.event.PostConstructViewMapEvent</system-event-class>
<source-class>javax.faces.component.UIViewRoot</source-class>
</system-event-listener>
Step 3: Create a Custom View Scope bean as follows.
public class ViewScope implements Scope {
#Override
public Object get(String name, ObjectFactory objectFactory) {
Map<String, Object> viewMap = FacesContext.getCurrentInstance().getViewRoot().getViewMap();
if (viewMap.containsKey(name)) {
return viewMap.get(name);
} else {
List<Map<String, Object>> activeViewMaps = (List<Map<String, Object>>)
FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get("com.org.jsf.activeViewMaps");
if (activeViewMaps != null && !activeViewMaps.isEmpty()
&& activeViewMaps.size() > 1) {
Iterator iterator = activeViewMaps.iterator();
if (iterator.hasNext()) {
Map<String, Object> oldViewMap = (Map<String, Object>)
iterator.next();
oldViewMap.clear();
iterator.remove();
}
}
Object object = objectFactory.getObject();
viewMap.put(name, object);
return object;
}
}
Note : Other overridden methods can be empty.
For JSF 2.2:
JSF 2.2 saves the navigated view maps in http session in 'com.Sun.faces.application.view.activeViewMaps' as key. So add the below code in Spring Custom View Scope. No need of listeners as in JSF 2.1
public class ViewScope implements Scope {
public Object get(String name, ObjectFactory objectFactory) {
Map<String, Object> viewMap =
FacesContext.getCurrentInstance().getViewRoot().getViewMap();
if (viewMap.containsKey(name)) {
return viewMap.get(name);
} else {
LRUMap lruMap = (LRUMap) FacesContext.getCurrentInstance().
getExternalContext().getSessionMap().get("com.sun.faces.application.view.activeViewMaps");
if (lruMap != null && !lruMap.isEmpty() && lruMap.size() > 1) {
Iterator itr = lruMap.entrySet().iterator();
while (itr.hasNext()) {//Not req
Entry entry = (Entry) itr.next();
Map<String, Object> map = (Map<String, Object>) entry.getValue();
map.clear();
itr.remove();
break;
}
}
Object object = objectFactory.getObject();
viewMap.put(name, object);
return object;
}
}
Chances are this is a bug. Honestly the Seam 3 implementation wasn't all that great and the CODI one (and also what will be in DeltaSpike) is much better.
I've tried to learn the JSF 2.0 with bean validation at the class level as the following: -
The utility
#Singleton
public class MyUtility {
public boolean isValid(final String input) {
return (input != null) || (!input.trim().equals(""));
}
}
The constraint annotation
#Retention(RetentionPolicy.RUNTIME)
#Target({
ElementType.TYPE,
ElementType.ANNOTATION_TYPE,
ElementType.FIELD
})
#Constraint(validatedBy = Validator.class)
#Documented
public #interface Validatable {
String message() default "Validation is failure";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
The constraint validator
public class Validator extends ConstraintValidator<Validatable, MyBean> {
//
//----> Try to inject the utility, but it cannot as null.
//
#Inject
private MyUtility myUtil;
public void initialize(ValidatableconstraintAnnotation) {
//nothing
}
public boolean isValid(final MyBean myBean,
final ConstraintValidatorContext constraintContext) {
if (myBean == null) {
return true;
}
//
//----> Null pointer exception here.
//
return this.myUtil.isValid(myBean.getName());
}
}
The data bean
#Validatable
public class MyBean {
private String name;
//Getter and Setter here
}
The JSF backing bean
#Named
#SessionScoped
public class Page1 {
//javax.validation.Validator
#Inject
private Validator validator;
#Inject
private MyBean myBean;
//Submit method
public void submit() {
Set<ConstraintViolation<Object>> violations =
this.validator.validate(this.myBean);
if (violations.size() > 0) {
//Handle error here.
}
}
}
After running I've faced the exception as java.lang.NullPointerException at the class named "Validator" at the line return this.myUtil.isValid(myBean.getName());. I understand that the CDI does not inject my utility instance. Please correct me If I'm wrong.
I'm not sure if I'm doing something wrong or it is a bean validation limitation. Could you please help to explain further?
Your right, Hibernate Constraint Validator is not registered as a CDI-Bean by default (and though cannot receive dependencies).
Just put the Seam-Validation module on your classpath, and everything should run fine.
BTW: studying the source-code of the module is an excellent example of the elegance and simplicity of CDI extension. It's doesn't need more than a few dozens lines of code to bridge from CDI to hibernate validations...
I have this Service bean:
#Stateless
public class BookService
{
#PersistenceContext(unitName="persistentUnit")
protected EntityManager entityManager;
public BookModel find(Long id) {
return entityManager.find(BookModel.class, id);
}
}
And the backing bean for the Facelet page is:
#ManagedBean(name = "bookBean")
#RequestScoped
public class BookBean implements Serializable
{
#EJB
private BookService bookService;
#ManagedProperty(value="#{param.id}")
private Long id;
private DataModel<BookModel> books;
private BookModel currentBook;
#PostConstruct
public void init() {
if (id == null) {
// UPDATE: Retrieve a list of books.
} else {
// UPDATE: id shouldn't be null here.
// Get detail info about a book using the id
currentBook = bookService.find(id);
}
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public BookModel getCurrentBook() {
return currentBook;
}
public void setCurrentBook(BookModel currentBook) {
this.currentBook = currentBook;
}
}
Why is the value of id always returns null even though the URL returned as bookedit.jsf?id=5418 I don't understand this.
Also, I find the EntityManager#find method quite restrictive in that it only accept a primary key value as the second parameter. What if I want to pass a [hashed] value instead of the primary key. How can I do this with the EntityManager#find method?
P.S. I notice the EntityManager#find requirement is the same for both OpenJPA and EclipseLink implementations. Hmm...
I just tried this in one of my managed beans, and it is working. Here's the relevant code, it's basically the same as yours:
#ManagedBean
#RequestScoped
public class TestBean {
#ManagedProperty(value = "#{param.id}")
private Long prop;
#PostConstruct
public void init() {
System.out.println(prop);
// prints 1234 if I go to the url with http://localhost/page.jsf?1234
}
public Long getProp() {
return prop;
}
public void setProp(Long prop) {
this.prop = prop;
}
}
I'm running this on glassfish 3.1.1. The only thought I had is maybe the injected EJB is somehow messing up the request scope in the ManagedBean?
I have a class :
#SessionScoped
public class LoggedUser {
private User user;
...
}
that I use to keep track if a user is logged in my application.
In my Struts2 application I have a Interceptor to check if the user is logged, if not he's forwarded to the login page.
public class LoggedUserInterceptor extends AbstractInterceptor {
private static final long serialVersionUID = 2822434409188961460L;
#Inject
private LoggedUser loggedUser;
#Override
public String intercept(ActionInvocation invocation) throws Exception {
if(loggedUser==null || !loggedUser.isLogged()){
return "login";
}
return invocation.invoke();
}
}
The problem occur when the session timeout. The object LoggdeUser is never null or deleted. I have always the last instance.
I added A session listener.
public class SessionListener implements HttpSessionListener {
private static Logger logger = Logger.getLogger(SessionListener.class.getName());
#Override
public void sessionCreated(HttpSessionEvent event) {
logger.info("sessionCreated = " + event.getSession().getId());
}
#Override
public void sessionDestroyed(HttpSessionEvent event) {
logger.info("sessionDestroyed = " + event.getSession().getId());
}
}
I see that sessionDestroyed is called, but when I enter again in my Interceptor.. LoggedUser is never recreated for a new session.
why ?
my Struts2 Action for the login is this
public class LoginUserAction extends ActionSupport implements ModelDriven<LoggedUser>, ServletRequestAware {
...
#Inject
private LoggedUser loggedUser;
public String execute() throws Exception {
...
loggerUser.setLoggedTime(now);
...
return SUCCESS;
}
I add that too in web.xml
session-config
session-timeout 2 /session-timeout
/session-config
I don't know anything about Struts2, but my guess is that the interceptor's scope is wider than session scope. In other words, the interceptor instance is kept around longer than the session. Guice can't and won't set an injected field to null when the session ends, nor will it ever re-inject an object automatically.
What you need to do if you use an object with a shorter lifecycle inside an object with a longer lifecycle (such as a RequestScoped object inside a SessionScoped object or a SessionScoped object inside a singleton) is inject a Provider for the shorter lived object.
In your case, I think this is probably what you need:
public class LoggedUserInterceptor extends AbstractInterceptor {
private static final long serialVersionUID = 2822434409188961460L;
#Inject
private Provider<LoggedUser> loggedUserProvider;
#Override
public String intercept(ActionInvocation invocation) throws Exception {
LoggedUser loggedUser = loggedUserProvider.get();
if(loggedUser==null || !loggedUser.isLogged()){
return "login";
}
return invocation.invoke();
}
}
I don't know guice but the session is available to the interceptor and can be made readily available to the action via SessionAware :
ActionInvocation provides access to the session. The following is part of a "Authentication" interceptor. If there is not a "User" object then Action.LOGIN is returned.
public String intercept(ActionInvocation invocation) throws Exception {
Map session = invocation.getInvocationContext().getSession();
appLayer.User user = (appLayer.User) session.get("User");
if (user == null){
return Action.LOGIN;
}
return invocation.invoke();
}
I only place the user object on the session when the user logs in.
In the login action I place the user object on the session:
public class Login extends ActionSupport implements SessionAware {
private Map<String, Object> session;
private String userName;
private String password;
public String execute() {
//use DB authentication once this works
//if ("ken".equalsIgnoreCase(userName) && "ken".equalsIgnoreCase(password)){
try {
User user = new User(userName, password);
session.put("User", user);
return ActionSupport.SUCCESS;
} catch (Exception e) {
System.out.println("There was an exception" + e.getMessage());
return ActionSupport.LOGIN;
}
}
public void validate() {
String user = this.getUserName();
String pass = this.getPassword();
//This block is a bit redundant but I couldn't figure out how
//to get just the hibernate part to report an exception on Username/pass
if (!StringUtils.isBlank(this.getUserName()) && !StringUtils.isBlank(this.getPassword())) {
try {
Class.forName("com.ibm.as400.access.AS400JDBCDriver").newInstance();
String url = "jdbc:as400://192.168.1.14";
DriverManager.getConnection(url, user, pass).close();
} catch (Exception e) {
addFieldError("login.error.authenticate", "Bad Username / Password");
}
}
if (StringUtils.isBlank(getUserName())) {
addFieldError("login.error.name", "Missing User Name");
}
if (StringUtils.isBlank(getPassword())) {
addFieldError("login.error.password", "Missing Password");
}
//else both are blank don't report an error at this time
}
... getters/setters....
}//end class
If I remember correctly this comes from at least in part from "Struts2 in Action". Anyways I'm a big believer in DI but since the Session is pretty accessible from the interceptors and the action I don't bother.
the easiest way to do that is finally to put the token in the session at the login and check it with an Interceptor
#Override
public String intercept(ActionInvocation invocation) throws Exception {
loggedUser = (LoggedUser) invocation.getInvocationContext().getSession().get(LoggedUser.SESSIONTOKEN);
if(loggedUser==null || !loggedUser.isLogged()){
logger.info("loggedUser not present in session");
return "login";
}
return invocation.invoke();
}
in the Action
request.getSession().setAttribute(LoggedUser.SESSIONTOKEN, loggedUser);