Exception: could not find Factory: javax.faces.context.FacesContextFactory

Yury Litvinov picture Yury Litvinov · Mar 10, 2011 · Viewed 52.3k times · Source

I'm migrating from JBoss 5.1.0.GA to JBoss 6.0.0-Final and facing following exception during FacesServler initialization

2011-03-09 18:07:24,574 ERROR [org.apache.catalina.core.ContainerBase.[jboss.web].[localhost].[/].[Faces Servlet]] (http-0.0.0.0-8080-4) Allocate exception for servlet Faces Servlet: java.lang.IllegalStateException: Application was not properly initialized at startup, could not find Factory: javax.faces.context.FacesContextFactory
    at javax.faces.FactoryFinder$FactoryManager.getFactory(FactoryFinder.java:725) [:1.2_15-20100816-SNAPSHOT]
    at javax.faces.FactoryFinder.getFactory(FactoryFinder.java:239) [:1.2_15-20100816-SNAPSHOT]
    at javax.faces.webapp.FacesServlet.init(FacesServlet.java:164) [:1.2_15-20100816-SNAPSHOT]
    at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1208) [:6.0.0.Final]
    at org.apache.catalina.core.StandardWrapper.allocate(StandardWrapper.java:955) [:6.0.0.Final]
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:188) [:6.0.0.Final]
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191) [:6.0.0.Final]
    at org.jboss.web.tomcat.security.SecurityAssociationValve.invoke(SecurityAssociationValve.java:181) [:6.0.0.Final]
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:501) [:6.0.0.Final]
    at org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:88) [:6.0.0.Final]
    at org.jboss.web.tomcat.security.SecurityContextEstablishmentValve.invoke(SecurityContextEstablishmentValve.java:100) [:6.0.0.Final]
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127) [:6.0.0.Final]
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102) [:6.0.0.Final]
    at org.jboss.web.tomcat.service.jca.CachedConnectionValve.invoke(CachedConnectionValve.java:158) [:6.0.0.Final]
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) [:6.0.0.Final]
    at org.jboss.web.tomcat.service.request.ActiveRequestResponseCacheValve.invoke(ActiveRequestResponseCacheValve.java:53) [:6.0.0.Final]
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:362) [:6.0.0.Final]
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:877) [:6.0.0.Final]
    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:654) [:6.0.0.Final]
    at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:951) [:6.0.0.Final]
    at java.lang.Thread.run(Thread.java:619) [:1.6.0_14]

I've looked into code and found out that FactoryFinder looks up corresponding FactoryManager based on current thread classloader. I also found that my FactoryFinder.FACTORIES_CACHE contains two entries for two class loaders:

* BaseClassLoader which loads my EAR and
* WebCtxLoader.ENCLoader which is used during web app running and which was current context classloaded for failed thread.

My deploy structure is following:

* deploy
      o myapplication.ear
            + lib
                  # richfaces jars (3.3.1.GA)
                  # seam jars (2.2.1.Final)
                  # openfaces jar (2.0.0)
                  # other jars
            + META-INF
                  # jboss-app.xml
                  # application.xml
            + myapplication.war
                  # WEB-INF
                        * web.xml
                        * faces-config.xml
                        * components.xml
* deployers
      o jbossweb.deployer
      o jsf.deployer
      o and others

I'm using Mojarra-1.2 as JSF implementation

    <param-name>org.jboss.jbossfaces.JSF_CONFIG_NAME</param-name>

    <param-value>Mojarra-1.2</param-value>

After some debugging I could sumup:

     1. all JSF initialization is made in BaseClassLoader thread, i.e. when javax.faces.FactoryFinder#setFactory(..) is invoked getClassLoader() returns EAR BaseClassLoader
     2. A servlet thread (which cause exception) tries to look FactoryManager but his current classloader ( Thread.currentThread().getContextClassLoader()) is WebCtxLoader.ENCLoader. So nothing is returned and exception is thrown.

I checked JBoss 5.1.0 and ensured that initialization and access for FactoryManager's were made in threads having same class loader.

I've tried to google by didn't find much information about anybody having same problem - which makes me think something is wrong in my environment.

Can anybody comment on or help with this?

Answer

BalusC picture BalusC · Mar 10, 2011

This is a sign of classpath pollution. JBoss already ships with JSF bundled. This exception can occur if you bundle JSF in your WAR as well. It'll only collide.

There are 2 solutions:

  1. Get rid of jsf-api and jsf-impl JARs in your WAR (i.e. they should not end up in /WEB-INF/lib after build/deploy.

  2. Tell JBoss that your WAR ships with its own version of JSF so that JBoss won't use its own.

    <context-param>
        <param-name>org.jboss.jbossfaces.WAR_BUNDLES_JSF_IMPL</param-name>
        <param-value>true</param-value>
    </context-param>