3

Ok here is my session bean. I can always retrieve the currentUser from any Servlet or Filter. That's not the problem The problem is the fileList, and currentFile. I've tested with simple int's and Strings and its' the same effect. If I set a value from my view scoped bean I can get the data from another class.

@ManagedBean(name = "userSessionBean")
@SessionScoped
public class UserSessionBean implements Serializable, HttpSessionBindingListener {

    final Logger logger = LoggerFactory.getLogger(UserSessionBean.class);

    @Inject
    private User currentUser;

    @EJB
    UserService userService;

    private List<File> fileList;   

    private File currentFile;

    public UserSessionBean() {

        fileList = new ArrayList<File>();
        currentFile = new File("");
    }

    @PostConstruct
    public void onLoad() {

        Principal principal = FacesContext.getCurrentInstance().getExternalContext().getUserPrincipal();
        String email = principal.getName();

        if (email != null) {
            currentUser = userService.findUserbyEmail(email);
        } else {

            logger.error("Couldn't find user information from login!");
        }
    }

Here is an example.

My view scoped bean. This is how it is decorated.

 @ManagedBean
 @ViewScoped
 public class ViewLines implements Serializable {

    @Inject
    private UserSessionBean userSessionBean; 

Now the code.

    userSessionBean.setCurrentFile(file);
    System.out.println("UserSessionBean : " + userSessionBean.getCurrentFile().getName());

I can see the current file name perfectly. This is actually being printed from a jsf action method. So obviously the currentFile is being set.

Now if I do this.

@WebFilter(value = "/Download")
public class FileFilter implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {        
        HttpSession session = ((HttpServletRequest) request).getSession(false);
        UserSessionBean userSessionBean = (UserSessionBean) session.getAttribute("userSessionBean");       

        System.out.println(userSessionBean.getCurrentUser().getUserId()); //works

        System.out.println("File filter" + userSessionBean.getCurrentFile().getName()); //doesn't work


        chain.doFilter(request, response);
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void destroy() {
    }
}

currentUser shows up fine but I can't see the file. It's just blank. The same thing happens with Strings, int's, etc.

Thanks for any help you can provide on this.

INFO: UserSessionBean : Line 3B--8531268875812004316.csv (value printed from view scoped bean)

INFO: File filter tester.csv (value printed when filter is ran.)

**EDIT**

This worked.

 FacesContext context = FacesContext.getCurrentInstance();
    userSessionBean = (UserSessionBean) context.getApplication().evaluateExpressionGet(context, "#{userSessionBean}", UserSessionBean.class);

I put this in the constructor of the ViewScoped and everything was fine. Now why isn't the inject doing what I thought? At first I thought maybe because I was using JSF managed beans instead of the new CDI beans. But I changed the beans to the new style(with named) and that was the same effect.

Does the inject only allow you to access the beans but not change their attributes?

BalusC
  • 992,635
  • 352
  • 3,478
  • 3,452
Drew H
  • 4,629
  • 9
  • 55
  • 88
  • 1
    What's the functional requirement? Do you realize that the `Filter` runs *before* JSF? – BalusC Mar 14 '11 at 20:23
  • Yes. I'm basically wanting to delete the file in the session listener. That doesn't work either. The file is never in the session bean. I've kind of been using the filter as a testing method. I kind of also want to apply a token to the user session so that when they hit the servlet the user session object has to have that string defined to download the file. Just some extra security. It's not a must. I would like to store a few more things in the session bean. I just can't get anything to store at this point, and be able to access the data outside that one viewscoped bean. – Drew H Mar 14 '11 at 21:35
  • The session listener should be the right tool. If the file is not there then you're simply accessing the wrong bean or overriding the bean and/or the file list somewhere else. Run a debugger. – BalusC Mar 15 '11 at 01:50
  • Hey Balus. Getting the sessionbean in the viewscoped bean using faces context worked perfectly. The bean showed updated values in filter and servlet, and sessionListener..! What is going on here? – Drew H Mar 15 '11 at 12:58

2 Answers2

5

You're mixing JSF and CDI. Your UserSessionBean is a JSF @ManagedBean, yet you're using CDI @Inject to inject it in another bean. CDI doesn't reuse the JSF managed one, it instead creates a brand new one. Use the one or the other, not both. The correct annotation to inject a JSF-managed bean is @ManagedProperty.

Replace

@Inject
private UserSessionBean userSessionBean; 

by

@ManagedProperty(value="#{userSessionBean}")
private UserSessionBean userSessionBean; 

and ensure that you don't have a import javax.enterprise.context anywhere in your code (which is the package of CDI annotations).

Alternatively, migrate all JSF bean management annotations to CDI bean management annotations.

import javax.inject.Named;
import javax.enterprise.context.SessionScoped;

@Named
@SessionScoped
public class UserSessionBean implements Serializable {}

import javax.inject.Named;
import javax.faces.view.ViewScoped;

@Named
@ViewScoped
public class ViewLines implements Serializable {}

Additional advantage is that you can just @Inject it inside a regular servlet or filter without the need to manually grab it as request/session/application attribute.

Moreover, JSF bean management annotations are deprecated since JSF 2.3. See also Backing beans (@ManagedBean) or CDI Beans (@Named)?

BalusC
  • 992,635
  • 352
  • 3,478
  • 3,452
0

My best GUESS as to why this is happening, is because the variable file, is being set in view scope, and then passed by reference into the session scoped bean. Maybe this is happening because when the view scope bean is destroyed, it still has a reference to that variable, but doesn't bother to see if there's any other references to it in session scope, where it should be preserved. Hence, when it's destroyed, it's removed from both view and session scope in this case.

Could you try calling setCurrentFile with an object instantiated with 'new'? That might prove or disprove this hypothesis of mine.

Otherwise, my best advice would be to crack open the debugger, and see exactly where getCurrentFile is being changed.

user470714
  • 2,788
  • 26
  • 33
  • Yea I've tried using new too. Forgot to specify that. userSessionBean.setCurrentFile(new File(file.getAbsolutePath())); Same thing. – Drew H Mar 14 '11 at 19:53
  • Ok as soon as I hit the button for download the filter gets fired. This is when the file object goes to "". The only thing that sets the value to that is the constructor for the session bean. I debugged it and that constructor is not getting fired. I don't know what is happening here. – Drew H Mar 14 '11 at 20:15
  • This is a head scratcher... other things I'd try: 1) Changing the constructor to set the value to something crazy, to make sure the empty string isn't coincidence. 2) calling setCurrentFile with a File object which makes absolutely no references to file; make up some crazy path. 3) Setting a watch on that variable in the debugger to see if you can get it to break on the point where it's being reset. 4) I noticed currentUser has Inject annotation. Is it a bean too? Maybe try wrapping fileList and currentFile in that class, since currentUser seems unaffected by this strange behavior. – user470714 Mar 14 '11 at 20:26
  • Ok I've been messing with it some more. I set the current file object to another file instead of "". When I print the file name from the view scoped bean it shows correctly. If I print it from the filter it shows the file that is set in the constructor. This is really weird. It's like there are two sessionbeans. Am I misunderstanding what inject does? That should only give me the current instance of that bean. Updated original post. Btw: the currentUser is an JPA entity. – Drew H Mar 14 '11 at 21:31
  • Hmm, I've not really used the inject annotation myself, so I can't talk to it very much. But I just noticed that you're using it in conjunction with the view scoped bean, so maybe also try: 1) Changing ViewLines to SessionScope temporarily, to see if ViewScope is the problem. 2) Access the session bean directly, without injection. My experience with JSF is solely based around maintaining an existing code base, and I've found out since I began that the the guy before me did some questionable things, but I could give you a code snippet for accessing the SessionBean directly, if you need it. – user470714 Mar 14 '11 at 22:06
  • Updated the post. Getting the sessionbean using faces context in the ViewScoped bean worked perfectly. I don't know what is going on. – Drew H Mar 15 '11 at 12:57