We have recently moved to Tomcat 8.5.4 (from 8.5.3) and to Omnifaces 2.4 (from 2.3), and we have also changed a few things in our Web Application. Since then, our Web Application does not start anymore, with the following exception in the logs:
Exception sending context initialized event to listener instance of class org.omnifaces.ApplicationListener
java.lang.ExceptionInInitializerError
at org.omnifaces.ApplicationListener.checkCDIAvailable(ApplicationListener.java:77)
at org.omnifaces.ApplicationListener.contextInitialized(ApplicationListener.java:61)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4716)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5178)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:152)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1403)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1393)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.IllegalStateException: CDI BeanManager instance is not available in JNDI.
at org.omnifaces.config.BeanManager.<init>(BeanManager.java:100)
at org.omnifaces.config.BeanManager.<clinit>(BeanManager.java:49)
... 11 more
Caused by: java.lang.IllegalStateException: javax.naming.NamingException: WELD-001300: Unable to locate BeanManager
at org.omnifaces.util.JNDI.lookup(JNDI.java:95)
at org.omnifaces.config.BeanManager.<init>(BeanManager.java:96)
... 12 more
Caused by: javax.naming.NamingException: WELD-001300: Unable to locate BeanManager
at org.jboss.weld.resources.ManagerObjectFactory.getObjectInstance(ManagerObjectFactory.java:62)
at org.apache.naming.factory.FactoryBase.getObjectInstance(FactoryBase.java:94)
at javax.naming.spi.NamingManager.getObjectInstance(NamingManager.java:321)
at org.apache.naming.NamingContext.lookup(NamingContext.java:840)
at org.apache.naming.NamingContext.lookup(NamingContext.java:160)
at org.apache.naming.NamingContext.lookup(NamingContext.java:828)
at org.apache.naming.NamingContext.lookup(NamingContext.java:160)
at org.apache.naming.NamingContext.lookup(NamingContext.java:828)
at org.apache.naming.NamingContext.lookup(NamingContext.java:174)
at org.apache.naming.SelectorContext.lookup(SelectorContext.java:163)
at javax.naming.InitialContext.lookup(InitialContext.java:417)
at org.omnifaces.util.JNDI.lookup(JNDI.java:90)
... 13 more
Exception sending context initialized event to listener instance of class com.sun.faces.config.ConfigureListener
java.lang.RuntimeException: java.lang.NoClassDefFoundError: Could not initialize class org.omnifaces.config.BeanManager
at com.sun.faces.config.ConfigureListener.contextInitialized(ConfigureListener.java:292)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4714)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5178)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:152)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1403)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1393)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.NoClassDefFoundError: Could not initialize class org.omnifaces.config.BeanManager
at org.omnifaces.util.Beans.getManager(Beans.java:88)
at org.omnifaces.util.Beans.getReference(Beans.java:113)
at org.omnifaces.application.OmniApplication.<init>(OmniApplication.java:70)
at org.omnifaces.application.OmniApplicationFactory.createOmniApplication(OmniApplicationFactory.java:89)
at org.omnifaces.application.OmniApplicationFactory.getApplication(OmniApplicationFactory.java:54)
at com.sun.faces.application.InjectionApplicationFactory.getApplication(InjectionApplicationFactory.java:93)
at com.sun.faces.config.InitFacesContext.getApplication(InitFacesContext.java:142)
at com.sun.faces.lifecycle.ClientWindowFactoryImpl.<init>(ClientWindowFactoryImpl.java:62)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at java.lang.Class.newInstance(Class.java:442)
at javax.faces.FactoryFinderInstance.getImplGivenPreviousImpl(FactoryFinderInstance.java:405)
at javax.faces.FactoryFinderInstance.getImplementationInstance(FactoryFinderInstance.java:251)
at javax.faces.FactoryFinderInstance.getFactory(FactoryFinderInstance.java:543)
at javax.faces.FactoryFinder.getFactory(FactoryFinder.java:283)
at com.sun.faces.config.processor.FactoryConfigProcessor.verifyFactoriesExist(FactoryConfigProcessor.java:328)
at com.sun.faces.config.processor.FactoryConfigProcessor.process(FactoryConfigProcessor.java:236)
at com.sun.faces.config.ConfigManager.initialize(ConfigManager.java:439)
at com.sun.faces.config.ConfigureListener.contextInitialized(ConfigureListener.java:227)
Our configuration:
The BeanManager resource entry:
<Resource name="BeanManager"
auth="Container"
type="javax.enterprise.inject.spi.BeanManager"
factory="org.jboss.weld.resources.ManagerObjectFactory"/>
We've moved back to Tomcat 8.5.3 and to omnifaces 2.3, and tried different combinations of component versions (8.5.3 with 2.4, 8.5.4 with 2.3, etc...) in order to identify the root cause of the problem, but to no avail.
Finally, we suspect a racing condition issue between the initialization of all these components (Tomcat, Weld, Onmnifaces, ...).
In a last resort, I have removed the BeanManager resource entry from the context XML file.
Removed from the context:
<Resource name="BeanManager"
auth="Container"
type="javax.enterprise.inject.spi.BeanManager"
factory="org.jboss.weld.resources.ManagerObjectFactory"/>
And it fixed the problem.
I had a look to the change logs of Tomcat 8.5.4, and I could find this change:
Do not attempt to start web resources during a web application's initialisation phase since the web application is not fully configured at that point and the web resources may not be correctly configured. (markt)
I don't know if this Web Application's initialization phase issue reported in the Tomcat change logs could be linked to the problem we had. The reason why the removal of the BeanManager resource from the context fixed the problem is still unclear.
Any idea?
javax.naming.NamingException: WELD-001300: Unable to locate BeanManager
This basically means that the BeanManager
JNDI resource definition (as defined in context.xml
) is found, but that the concrete BeanManager
instance behind the JNDI resource isn't created yet.
This indeed matches the described change in Tomcat 8.5.4.
Do not attempt to start web resources during a web application's initialisation phase since the web application is not fully configured at that point and the web resources may not be correctly configured. (markt)
I can't tell the reasoning of Mark Thomas for this decision and there's also no issue link behind it. I guess he was trying to avoid confusing behavior caused by intermittently broken deployments caused by potential initialization ordering issues. This is perhaps a good thing, but I think Mark actually overlooked the possibility of defining the initialization order via <ordering>
element in web.xml
and web-fragment.xml
files. I indeed recall that Tomcat never respected this as to invocation order of @WebListener
-annotated or programmatically created instances (it however does that as to <listener>
declared instances). Perhaps Mark should better have fixed that part instead of disabling JNDI altogether during initialization phase.
As to the change in OmniFaces 2.4, as per issue 243 this version added a fallback to a Weld-specific servlet context attribute. This will be used when the JNDI resource doesn't exist, and Weld is being used as CDI implementation. Namely, Weld internally stores the BeanManager instance as a servlet context attribute too, so OmniFaces could just grab it without the need for JNDI. This means, the context.xml
is no longer necessary. In Tomcat 8.5.4, you should actually remove the context.xml
too because OmniFaces 2.4 still first tries to inspect the JNDI resource, which would eventually throw an exception because the BeanManager
instance is unexpectedly unavailable as consequence of that Tomcat 8.5.4 change.
In OmniFaces 2.5, the CDI initialization has been reworked and improved as per issue 281 which describes the migration of CDI 1.0 to 1.1. OmniFaces no longer uses JNDI to inspect the BeanManager
. OmniFaces will now use CDI 1.1-introduced CDI
API.
BeanManager beanManager = CDI.current().getBeanManager();
This works regardless of JNDI configuration/initialization.
OmniFaces 2.5 is not final yet, but the 2.5-RC1 is available in Maven central as of yesterday.