Bug 55282

Summary: JSF PhaseListeners are duplicated
Product: Tomcat 7 Reporter: Val <valiantsinshukaila>
Component: CatalinaAssignee: Tomcat Developers Mailing List <dev>
Status: RESOLVED FIXED    
Severity: normal CC: olgr
Priority: P2    
Version: 7.0.42   
Target Milestone: ---   
Hardware: PC   
OS: All   
Attachments: source code to reproduce the issue

Description Val 2013-07-19 15:41:05 UTC
Created attachment 30604 [details]
source code to reproduce the issue

If using jsf 2 project and add Phase Listeners there, they are created and added to the list of Phase Listeners twice which means on page load same Phase Listeners are executed twice.
This is happening only when com.sun.faces.config.ConfigureListener is defined in web.xml.
Without such declaration in web.xml jsf is initialized one time.
Such behaviour seems to happen on 7.0.42 version.
I was using 7.0.41 and didn't see such behaviour. I didn't have a chance to check it again on 7.0.41 but checked on 7.0.6(because had it installed) and there everything was fine.
Such behaviour can be very critical for applications using jsf and Phase Listeners. And Maybe not only Phase Listeners are duplicated(didn't look), because the problem here is that jsf is initialized twice and other things can get duplicated too.
Attaching eclipse project where you can check the bug on 7.0.42 and compare to other tomcat version. In 7.0.42 there is duplicated message in console that Phase Listener is created.
Comment 1 Mark Thomas 2013-07-23 18:57:34 UTC
A ServletContainerInitializer is defined which is processed by Tomcat as required by the Servlet 3.0 and later Servlet specifications.

It appears that the SCI adds an instance of com.sun.faces.config.ConfigureListener so when it is defined a second time in web.xml everything gets processed twice.

Either disable the SCI or removed the listener definition from web.xml.
Comment 2 Val 2013-08-12 07:50:34 UTC
Yes, changing the web.xml will fix the problem. But also if the servlet version 2.5 is defined in web.xml everything still get's initialized twice.
I believe this is not what supposed to be. Not back compatibility for application that worked fine on older versions of tomcat.
Comment 3 Mark Thomas 2013-08-12 08:42:53 UTC
The Servlet 3.0 EG made very clear that annotations must be processed regardless of any version declared in web.xml. Personally, I think that is the wrong decision but is pre-dates my involvement with the EG.
Comment 4 Val 2013-08-12 09:35:12 UTC
com.sun.faces.config.ConfigureListener is not marked with any annotations but is loaded twice if it is defined as <listener> in web.xml. Not really clear how servlet 3 spec defines this. Maybe post a link in spec to clarify this for me? 
From my opinion this issue means that any of the old applications that were created before tomcat 7 released will work incorrectly on 7.0.42 or just not work at all.
Comment 5 Mark Thomas 2013-08-12 09:48:51 UTC
Sorry, I should have re-read this a little more carefully before commenting. However, the bug is still INVALID.

A Servlet 3.0 container is required to scan for SCIs irrespective of any version declared in the web.xml.

The docs for the library you are using should make clear that the web.xml definition is not required when running on a Servlet 3.0 or later container unless SCI scanning is disabled (e.g. via an absolute ordering) for the JAR that provides the SCI.
Comment 6 Oleksii 2013-08-15 08:34:17 UTC
I have encountered the same problem when used a workoaround solution for a SEAM project (https://issues.jboss.org/browse/JBSEAM-4401). I need the ConfigureListener to be invoked before the SeamListener.

During debugging I found that the com.sun.faces.config.ConfigureListener is added twice in org.apache.catalina.core.StandardContext.

The first instance is added because it is described in the web.xml.

The second instance is added by a JarScanner because the listener is described in jsf-impl.jar/META-INF/jsf_core.tld. My jsf-impl has an Implementation-Version: 2.1.7-SNAPSHOT.

I have no idea how to avoid the situation yet.
Comment 7 Oleksii 2013-08-15 11:26:17 UTC
For now I applied the following workaround. I have added the jsf-impl.jar to the property "tomcat.util.scan.DefaultJarScanner.jarsToSkip" of the TOMCAT\conf\catalina.properties. As a result my application started running properly. But I still have to check that it won't fail in some situations.
Comment 8 Volker 2014-05-22 11:46:53 UTC
I have found the reason for adding com.sun.faces.config.ConfigureListener a second time: Tomcat 7.0.41 contained following method in class org.apache.catalina.core.StandardContext:

public void addApplicationListener(String listener)

This method checks that the same listener isn't added twice:

...
for (int i = 0; i < applicationListeners.length; i++) {
  if (listener.equals(applicationListeners[i])) {
    log.info(sm.getString("standardContext.duplicateListener",listener));
    return;
  }
  ...


In Tomcat 7.0.42 the type of instance variable applicationListeners was changed from String[] to ApplicationListener[] and the method signature was changed to

public void addApplicationListener(ApplicationListener listener) 

But the check "listener.equals(applicationListeners[i])" in the fow loop wasn't adjusted --> now it doesn't compares the fq class names of the listeners but calls Object.equals() because class ApplicationListener doesn't overwrite equals() method.

The solution would be to overwrite equals() and hashCode() method in org.apache.catalina.deploy.ApplicationListener.

I have checked current Tomcat version 8.0.8 and the issue is still present there. I would help much to fix it in Tomcat 7 and 8 releases.


(In reply to Oleksii from comment #6)
> I have encountered the same problem when used a workoaround solution for a
> SEAM project (https://issues.jboss.org/browse/JBSEAM-4401). I need the
> ConfigureListener to be invoked before the SeamListener.
> 
> During debugging I found that the com.sun.faces.config.ConfigureListener is
> added twice in org.apache.catalina.core.StandardContext.
> 
> The first instance is added because it is described in the web.xml.
> 
> The second instance is added by a JarScanner because the listener is
> described in jsf-impl.jar/META-INF/jsf_core.tld. My jsf-impl has an
> Implementation-Version: 2.1.7-SNAPSHOT.
> 
> I have no idea how to avoid the situation yet.
Comment 9 Violeta Georgieva 2014-05-27 19:48:58 UTC
Thanks for the investigation. 
This has been fixed in trunk for 8.0.9 and in 7.0.x for 7.0.55 onwards.
Comment 10 Konstantin Kolinko 2014-06-05 12:51:30 UTC
(In reply to Volker from comment #8)

I also fixed the error message that was displayed (r1600616 7.0.55).

The addApplicationListener(ApplicationListener) API was reviewed and reverted in Tomcat 8 - issue 56588.