10

I need to know what's the best method for accessing a JSF managedBean (which is defined having application scope) from a servlet. Currently I have something like this in my servlet:

  MyApplicationScopeBean bean = null;
  try {
   FacesContext fContext = FacesUtil.getFacesContext(req, resp);
   ServletContext sc = (ServletContext) fContext.getExternalContext().getContext();
   bean = (MyApplicationScopeBean) sc.getAttribute("myManagedBean");   
  } catch (Exception e) {
   e.printStackTrace();
  }

FacesUtil.java (as described in http://balusc.blogspot.com/2006/06/communication-in-jsf.html):

import javax.faces.FactoryFinder;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.faces.context.FacesContextFactory;
import javax.faces.lifecycle.Lifecycle;
import javax.faces.lifecycle.LifecycleFactory;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class FacesUtil {
    // Getters -----------------------------------------------------------------------------------
    public static FacesContext getFacesContext(
        HttpServletRequest request, HttpServletResponse response)
    {
        // Get current FacesContext.
        FacesContext facesContext = FacesContext.getCurrentInstance();
        // Check current FacesContext.
        if (facesContext == null) {
            // Create new Lifecycle.
            LifecycleFactory lifecycleFactory = (LifecycleFactory)
                FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY); 
            Lifecycle lifecycle = lifecycleFactory.getLifecycle(LifecycleFactory.DEFAULT_LIFECYCLE);
            // Create new FacesContext.
            FacesContextFactory contextFactory  = (FacesContextFactory)
                FactoryFinder.getFactory(FactoryFinder.FACES_CONTEXT_FACTORY);
            facesContext = contextFactory.getFacesContext(
                request.getSession().getServletContext(), request, response, lifecycle);
            // Create new View.
            UIViewRoot view = facesContext.getApplication().getViewHandler().createView(
                facesContext, "");
            facesContext.setViewRoot(view);                
            // Set current FacesContext.
            FacesContextWrapper.setCurrentInstance(facesContext);
        }
        return facesContext;
    }
    // Helpers -----------------------------------------------------------------------------------
    // Wrap the protected FacesContext.setCurrentInstance() in a inner class.
    private static abstract class FacesContextWrapper extends FacesContext {
        protected static void setCurrentInstance(FacesContext facesContext) {
            FacesContext.setCurrentInstance(facesContext);
        }
    }     
}

I always get a null when trying to access the bean from the servlet.
What are your suggestions? I'm running JSF 1.2 on Tomcat 6

Thanks for your help.

azathoth
  • 573
  • 2
  • 6
  • 18

1 Answers1

21

JSF stores application scoped managed beans just in the ServletContext. In servlets, the ServletContext is just available by the inherited getServletContext() method. You don't need to manually create a whole FacesContext around it. That's only an unnecessarily expensive task for this purpose.

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    Bean bean = (Bean) getServletContext().getAttribute("bean");
    // ...
}

If it returns null, then it simply means that JSF hasn't kicked in yet to auto-create the bean for you (i.e. the servlet is called too early). You would then need to create and store it yourself. It will be used by JSF if the managed bean name (the attribute key) is the same.

    if (bean == null) {
        bean = new Bean();
        getServletContext().setAttribute("bean", bean);
    }

That said, what's the purpose of this servlet? Aren't you trying to achieve some functional requirement the wrong way?

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • OK, now I see where the problem is. I have a managedBean which has a method that creates the bean that I need, but when I get to the servlet, it's not in the ServletContext, because it was never really loaded on it. The purpose of the servlet is to write a file with OutputStream so my user will be able to save the result of a webservice invocation (a PDF file). I know it's not the best approach, but I'm facing a deadline here Any help is appreciated – azathoth Aug 26 '10 at 20:40
  • You can also do this in a managed bean method. You can find some hints in [this answer](http://stackoverflow.com/questions/2914025/forcing-a-save-as-dialogue-from-any-web-browser-from-jsf-application). You should certainly not use the servletcontext for it. It's been **shared** among all users who are using the webapplication. – BalusC Aug 26 '10 at 20:52
  • Thank you, with the example you provided I've modified my application, now it's using the same bean (session-scoped) for uploading and downloading, not needing to mess with ServletContext at all. – azathoth Aug 27 '10 at 16:09
  • >"BalusC: That said, what's the purpose of this servlet? Aren't you trying to achieve some functional requirement the wrong way?" That's a good point. I was using a plain servlet to do image serving, then based on BalusC's comment, I realized that the bean can do it just as well, and integrates with the page much more easily. – J Slick Nov 18 '15 at 06:54
  • @Milo: image serving is in turn a story apart. Start here: http://stackoverflow.com/q/11649524 – BalusC Nov 18 '15 at 06:56