6

Mojarra 2.2.12

Here is the piece of code taking over the instantiation of the FacesContext:

FacesContext context = facesContextFactory.getFacesContext
              (servletConfig.getServletContext(), request, response, lifecycle);

The expression is perfectly clear. Once we get a request, we acquire a global information from it and create the FacesContext instance using it. So, the instance is created for each request. But obtaining the intance of facesContextFactory seemed to me much more tricky.

// Acquire our FacesContextFactory instance
try {
    facesContextFactory = (FacesContextFactory)
        FactoryFinder.getFactory
        (FactoryFinder.FACES_CONTEXT_FACTORY);
} catch (FacesException e) {
    //others
}

Where

String javax.faces.FactoryFinder.FACES_CONTEXT_FACTORY = "javax.faces.context.FacesContextFactory"

JavaDocs for the FactoryFinder describes the so called

standard discovery algorithm for all factory objects specified in the JavaServer Faces APIs.

This is what I was confused by.

Now, Let's consider the the actual method that creates the factory instance: javax.faces.FactoryFinderInstance#getFactory(String factoryName)

try {
      factoryOrList = factories.get(factoryName);
      if (!(factoryOrList instanceof List)) {
          return factoryOrList;
      }
} finally {
      lock.readLock().unlock();
}

The factories field is initialized as follows copyInjectionProviderFromFacesContext():

private void copyInjectionProviderFromFacesContext() {
    InjectionProvider injectionProvider = null;
    FacesContext context = FacesContext.getCurrentInstance(); //USE FACES CONTEXT!!!!!
    if (null != context) {
        injectionProvider = (InjectionProvider) context.getAttributes().get("com.sun.faces.config.ConfigManager_INJECTION_PROVIDER_TASK");
    }
    if (null != injectionProvider) {
        factories.put(INJECTION_PROVIDER_KEY, injectionProvider);
    } else {
        if (LOGGER.isLoggable(Level.SEVERE)) {
            LOGGER.log(Level.SEVERE, "Unable to obtain InjectionProvider from init time FacesContext. Does this container implement the Mojarra Injection SPI?");
        }
    }
}

So, creating used FacesContext instance, but the factory itself is used for creating the FacesContext. Couldn't you explain that cycle?

Tiny
  • 27,221
  • 105
  • 339
  • 599
St.Antario
  • 26,175
  • 41
  • 130
  • 318

1 Answers1

7

There's a special "init FacesContext" which is available during servlet container initialization, ensuring that there's at least "a" FacesContext around during JSF initialization. This special "init FacesContext" has a lot of empty/null/default properties, particularly the ones depending on HTTP servlet request/response, but application and configuration related properties such as ones available via FacesContext#getApplication() are already available based on a.o. faces-config.xml.

In case of Mojarra, this "init FacesContext" is created in a.o. the com.sun.faces.config.FacesInitializer, a ServletContainerInitializer implementation which runs during webapp startup. During that moment, factories are created.

Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • So, this is the case for creating InitFacesContext: `FacesContextFactory privateFacesContextFactory = (FacesContextFactory) FactoryFinder.getFactory("com.sun.faces.ServletContextFacesContextFactory");`? It doesn't appear in the [Mojarra 2.2.4](http://grepcode.com/file/repo1.maven.org/maven2/com.sun.faces/jsf-api/2.2.4/javax/faces/context/FacesContext.java#FacesContext.getCurrentInstance%28%29) though... – St.Antario Sep 04 '15 at 10:25
  • No, it's created in `FacesInitializer`. Click the "created" link in my answer. – BalusC Sep 04 '15 at 10:26
  • 1
    How come I'm getting JSF related error when trying to run a Spring app on GF 4.1.1 without any references to Mojarra: Info: WebModule[null] ServletContext.log():No Spring WebApplicationInitializer types detected on classpath Info: Initializing Mojarra 2.2.12 for context '/sm-shop-2.0.3-SNAPSHOT' Severe: Unable to obtain InjectionProvider from init time FacesContext. Does this container implement the Mojarra Injection SPI? Severe: Unable to call @PreDestroy annotated methods because no InjectionProvider can be found. Does this container implement the Mojarra Injection SPI? – developer10 Nov 29 '16 at 11:51
  • 1
    @developer10: because GF is a Java EE server. I.e. it implements anything from Java EE API, including JSF. Normally, Spring applications are deployed to non-Java EE servers such as Tomcat. See also a.o. http://stackoverflow.com/questions/7295096/what-exactly-is-java-ee – BalusC Nov 29 '16 at 11:54
  • @BalusC Yes, I've been trying to run it with Tomcat but it's giving me hard time by not starting, etc. Is there any easy way to overcome this JSF related issue on GF (just to tell it to ignore/stop looking for JSF)? – developer10 Nov 29 '16 at 11:56
  • @developer10: your concrete problem is just caused by classpath pollution, not by JSF. Perhaps you've for some reason a `javaee.jar` lingering around in your non-Java EE application. That's by the way most likely the same reason as why your Tomcat was giving troubles. I suggest to take a step back http://xyproblem.info – BalusC Nov 29 '16 at 12:04
  • @BalusC Could it be just this one in Glassfish4/lib directory? Or there must be one in the project itself? – developer10 Nov 29 '16 at 12:13
  • 1
    @developer10: in the project itself of course. You shouldn't touch the server's libraries. – BalusC Nov 29 '16 at 12:13