Note: This bug is displayed in read-only format because the product is no longer active in Red Hat Bugzilla.

Bug 900561 (JBPAPP6-896)

Summary: FacesContext.getCurrentInstance returns external context from a different deployment during application startup
Product: [JBoss] JBoss Enterprise Application Platform 6 Reporter: Marek Schmidt <maschmid>
Component: WebAssignee: Stan Silvert <ssilvert>
Status: CLOSED CURRENTRELEASE QA Contact:
Severity: high Docs Contact:
Priority: high    
Version: 6.0.0CC: abn, maschmid, mnovotny, sgilda, ssilvert, twells
Target Milestone: ---   
Target Release: EAP 6.0.1   
Hardware: Unspecified   
OS: Unspecified   
URL: http://jira.jboss.org/jira/browse/JBPAPP6-896
Whiteboard: eap601candidate
Fixed In Version: Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of: Environment:
EAP 6.0.0.CR1, JDK 1.6.0_30
Last Closed: 2013-02-21 11:18:06 UTC Type: Bug
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:
Attachments:
Description Flags
server.log
none
jboss-as-helloworld-1.war
none
jboss-as-helloworld-2.war none

Description Marek Schmidt 2012-05-31 09:12:54 UTC
Affects: Release Notes
Steps to Reproduce: 1. Start the AS7/EAP6 with  ./standalone.sh -Dorg.jboss.server.bootstrap.maxThreads=1   (which makes it easier to reproduce, as the issue occurs only when both the deployments are handled by the same MSC service thread)
2. deploy seam-blog.ear
3. deploy seam-booking.ear
4. notice the seam-booking doesn't work

the ears can be found in http://file.brq.redhat.com/~maschmid/JBPAPP-9197/
Workaround Description: Make sure that you do not try to call FacesContext.getCurrentInstance() from a ServletContextListener.  If you are using FacesContext at application initialization it should only be done in response to a JSF PostConstructApplicationEvent.  And then, you should always call FacesContext.release() in a finally block when you are done.

Presumably, once http://java.net/jira/browse/JAVASERVERFACES-2436 is fixed, the call to FacesContext.release() will be done for you just as it is during a request to the FacesServlet.
project_key: JBPAPP6

Deplying two Seam2 applications sometimes fails with the second one not working, as it loads configuration files belonging to the other application. The problem seems to be that during application initialization, the FacesContext.getCurrentInstance sometimes returns a non-null instance belonging to a previous deployment.

The code in Seam2 to load resources looks like this (called during SeamListener contextInitialized, which is a ServletListener)

{code}
public InputStream getResourceAsStream(String resource) {
      javax.faces.context.FacesContext context = javax.faces.context.FacesContext.getCurrentInstance(); 
      
      if (context!=null)
      {
         log.debug("XXX: facesContext " + context.getExternalContext().getContextName());
         stream = FacesResources.getResourceAsStream( resource, context.getExternalContext() );
      }
      
      if (stream == null)
      {
         // ... load stream from the ServletContext
      }
{code}

The FacesServlet is initialized later,

from the web.xml:
{code}
<listener>
  <listener-class>org.jboss.seam.servlet.SeamListener</listener-class>      
</listener>

<servlet>
   <servlet-name>Faces Servlet</servlet-name>
   <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
   <load-on-startup>1</load-on-startup>                        
</servlet>
{code}

Comment 1 Marek Schmidt 2012-05-31 09:15:50 UTC
Attachment: Added: server.log


Comment 2 Marek Schmidt 2012-05-31 09:21:30 UTC
Interesting log excerpts from the second deployment (Seam Booking) (notice the "XXX: facesContext Seam Blog Example"  lines)
{noformat}
...
10:24:25,749 INFO  [org.jboss.as.repository] (management-handler-thread - 2) JBAS014900: Content added at location /home/maschmid/testing/eap6/jboss-eap-6.0.0.CR1/jboss-eap-6.0/standalone/data/content/50/f1033a06466949685e1c3351994ffa193b2e84/content
10:24:25,754 INFO  [org.jboss.as.server.deployment] (MSC service thread 1-1) JBAS015876: Starting deployment of "seam-booking.ear"
10:24:26,037 INFO  [org.jboss.as.server.deployment] (MSC service thread 1-1) JBAS015876: Starting deployment of "booking-ejb.jar"
10:24:26,037 INFO  [org.jboss.as.server.deployment] (MSC service thread 1-1) JBAS015876: Starting deployment of "jboss-seam.jar"
10:24:26,038 INFO  [org.jboss.as.server.deployment] (MSC service thread 1-1) JBAS015876: Starting deployment of "booking-web.war"
...
10:24:28,415 DEBUG [org.jboss.seam.init.Initialization] (MSC service thread 1-1) initializing Seam
10:24:28,415 DEBUG [org.jboss.seam.contexts.ServletLifecycle] (MSC service thread 1-1) >>> Begin initialization
10:24:28,431 INFO  [org.jboss.seam.Component] (MSC service thread 1-1) Component: org.jboss.seam.core.init, scope: APPLICATION, type: JAVA_BEAN, class: org.jboss.seam.core.Init
10:24:28,434 DEBUG [org.jboss.seam.Component] (MSC service thread 1-1) org.jboss.seam.core.init.distributable=false
10:24:28,439 DEBUG [org.jboss.seam.Component] (MSC service thread 1-1) org.jboss.seam.core.init.jndiPattern=java:app/booking-ejb/#{ejbName}
10:24:28,439 DEBUG [org.jboss.seam.Component] (MSC service thread 1-1) org.jboss.seam.core.init.debug=true
...
10:24:28,737 DEBUG [org.jboss.seam.contexts.Contexts] (MSC service thread 1-1) starting up: org.jboss.seam.navigation.pages
10:24:28,738 DEBUG [org.jboss.seam.faces.ResourceLoader] (MSC service thread 1-1) XXX: facesContext Seam Blog Example
10:24:28,739 DEBUG [org.jboss.seam.navigation.Pages] (MSC service thread 1-1) reading pages.xml file: /WEB-INF/pages.xml
10:24:28,743 DEBUG [org.jboss.seam.faces.ResourceLoader] (MSC service thread 1-1) XXX: facesContext Seam Blog Example
10:24:28,744 DEBUG [org.jboss.seam.util.Resources] (MSC service thread 1-1) Loaded resource from Seam classloader: blacklist.properties
10:24:28,748 DEBUG [org.jboss.seam.contexts.Contexts] (MSC service thread 1-1) starting up: org.jboss.seam.el.referenceCache
10:24:28,764 DEBUG [org.jboss.seam.contexts.Contexts] (MSC service thread 1-1) starting up: org.jboss.seam.security.entityPermissionChecker
10:24:28,764 DEBUG [org.jboss.seam.contexts.Contexts] (MSC service thread 1-1) starting up: org.jboss.seam.transaction.facesTransactionEvents
10:24:28,764 DEBUG [org.jboss.seam.contexts.Contexts] (MSC service thread 1-1) starting up: org.jboss.seam.security.facesSecurityEvents
10:24:28,765 DEBUG [org.jboss.seam.contexts.Contexts] (MSC service thread 1-1) destroying: warRootDeploymentStrategy
10:24:28,765 DEBUG [org.jboss.seam.contexts.Contexts] (MSC service thread 1-1) destroying: deploymentStrategy
10:24:28,765 DEBUG [org.jboss.seam.contexts.Contexts] (MSC service thread 1-1) destroying: hotDeploymentStrategy
10:24:28,765 DEBUG [org.jboss.seam.contexts.Contexts] (MSC service thread 1-1) destroying: org.jboss.seam.core.events
10:24:28,765 DEBUG [org.jboss.seam.contexts.ServletLifecycle] (MSC service thread 1-1) <<< End initialization
10:24:28,765 DEBUG [org.jboss.seam.init.Initialization] (MSC service thread 1-1) done initializing Seam
10:24:28,768 INFO  [javax.enterprise.resource.webcontainer.jsf.config] (MSC service thread 1-1) Initializing Mojarra 2.1.7-jbossorg-2 (20120412-0335) for context '/seam-booking'
10:24:29,761 INFO  [org.richfaces.log.Cache] (MSC service thread 1-1) Selected fallback cache factory
10:24:29,763 INFO  [org.richfaces.log.Cache] (MSC service thread 1-1) Creating LRUMap cache instance using parameters: {org.richfaces.enableControlSkinning=false, javax.faces.DEFAULT_SUFFIX=.xhtml}
10:24:29,769 INFO  [org.richfaces.log.Cache] (MSC service thread 1-1) Creating LRUMap cache instance of 512 items capacity
10:24:29,776 INFO  [org.richfaces.log.Application] (MSC service thread 1-1) RichFaces Core Implementation by JBoss by Red Hat, version v.4.2.2.Final
10:24:29,778 WARNING [org.richfaces.log.Application] (MSC service thread 1-1) JMS API was found on the classpath; if you want to enable RichFaces Push JMS integration, set context-param 'org.richfaces.push.jms.enabled' in web.xml
10:24:29,780 INFO  [org.jboss.seam.servlet.SeamFilter] (MSC service thread 1-1) Initializing filter: org.jboss.seam.web.hotDeployFilter
10:24:29,780 INFO  [org.jboss.seam.servlet.SeamFilter] (MSC service thread 1-1) Initializing filter: org.jboss.seam.web.redirectFilter
10:24:29,780 INFO  [org.jboss.seam.servlet.SeamFilter] (MSC service thread 1-1) Initializing filter: org.jboss.seam.web.exceptionFilter
10:24:29,780 INFO  [org.jboss.seam.servlet.SeamFilter] (MSC service thread 1-1) Initializing filter: org.jboss.seam.web.multipartFilter
10:24:29,781 INFO  [org.jboss.seam.servlet.SeamFilter] (MSC service thread 1-1) Initializing filter: org.jboss.seam.web.identityFilter
10:24:29,781 INFO  [org.jboss.seam.servlet.SeamFilter] (MSC service thread 1-1) Initializing filter: org.jboss.seam.web.loggingFilter
10:24:29,782 INFO  [org.jboss.web] (MSC service thread 1-1) JBAS018210: Registering web context: /seam-booking
10:24:29,980 INFO  [org.jboss.as.server] (management-handler-thread - 2) JBAS018559: Deployed "seam-booking.ear"
{noformat}

Comment 3 Marek Schmidt 2012-05-31 09:41:51 UTC
Steps to Reproduce: Removed: 1. Start the AS7/EAP6 with  ./standalone.sh -Dorg.jboss.server.bootstrap.maxThreads=1   (which makes it easier to reproduce, as the issue occurs only when both the deployments are handled by the same MSC service thread)
2. deploy seam-blog.ear
3. deploy seam-booking.ear
4. notice the seam-blog doesn't work Added: 1. Start the AS7/EAP6 with  ./standalone.sh -Dorg.jboss.server.bootstrap.maxThreads=1   (which makes it easier to reproduce, as the issue occurs only when both the deployments are handled by the same MSC service thread)
2. deploy seam-blog.ear
3. deploy seam-booking.ear
4. notice the seam-blog doesn't work

the ears can be found in http://file.brq.redhat.com/~maschmid/JBPAPP-9197/


Comment 4 Marek Schmidt 2012-05-31 09:42:46 UTC
Steps to Reproduce: Removed: 1. Start the AS7/EAP6 with  ./standalone.sh -Dorg.jboss.server.bootstrap.maxThreads=1   (which makes it easier to reproduce, as the issue occurs only when both the deployments are handled by the same MSC service thread)
2. deploy seam-blog.ear
3. deploy seam-booking.ear
4. notice the seam-blog doesn't work

the ears can be found in http://file.brq.redhat.com/~maschmid/JBPAPP-9197/ Added: 1. Start the AS7/EAP6 with  ./standalone.sh -Dorg.jboss.server.bootstrap.maxThreads=1   (which makes it easier to reproduce, as the issue occurs only when both the deployments are handled by the same MSC service thread)
2. deploy seam-blog.ear
3. deploy seam-booking.ear
4. notice the seam-booking doesn't work

the ears can be found in http://file.brq.redhat.com/~maschmid/JBPAPP-9197/


Comment 5 Stan Silvert 2012-05-31 13:23:44 UTC
Marek N,

Can someone on the Seam team take a look at this?  I think it's far more likely to be a Seam issue than a JSF issue.  If it were a JSF issue you would see lots and lots of non-Seam users complaining.

BTW, the apps referenced here are using Seam 2.3.0.CR1-SNAPSHOT.

Stan

Comment 6 Marek Novotny 2012-05-31 14:10:29 UTC
Stan, 
 Marek Schmidt is from Seam QE so he is aware of the context.

I think what is weird is 
{noformat}
javax.faces.context.FacesContext.getCurrentInstance();
{noformat}
which gives the totally wrong context from previous application deployment initialization. That is not isolated from parallel applicaiton deployment?

Comment 7 Marek Schmidt 2012-05-31 14:33:35 UTC
The same problem reproducible with no Seam at all:

1. start jboss with ./standalone.sh -Dorg.jboss.server.bootstrap.maxThreads=1

(to make it more likely the two deployments are handled by the same thread)

2. deploy jboss-as-helloworld-1.war
3. deploy jboss-as-helloworld-2.war immediately after

4. notice the log

{noformat}
16:27:27,153 INFO  [org.jboss.as] (Controller Boot Thread) JBAS015874: JBoss EAP 6.0.0.GA (AS 7.1.2.Final-redhat-1) started in 3546ms - Started 135 of 215 services (79 services are passive or on-demand)
16:27:31,404 INFO  [org.jboss.as.repository] (management-handler-thread - 2) JBAS014900: Content added at location /home/maschmid/testing/eap6/jboss-eap-6.0.0.CR1/jboss-eap-6.0/standalone/data/content/f7/0c332126d93e65fcd2def44f171cb249e3d54f/content
16:27:31,426 INFO  [org.jboss.as.server.deployment] (MSC service thread 1-1) JBAS015876: Starting deployment of "jboss-as-helloworld-1.war"
16:27:31,754 INFO  [org.jboss.weld.deployer] (MSC service thread 1-1) JBAS016002: Processing weld deployment jboss-as-helloworld-1.war
16:27:31,840 INFO  [org.jboss.weld.deployer] (MSC service thread 1-1) JBAS016005: Starting Services for CDI deployment: jboss-as-helloworld-1.war
16:27:31,945 INFO  [org.jboss.weld.Version] (MSC service thread 1-1) WELD-000900 1.1.8 (redhat)
16:27:32,028 INFO  [org.jboss.as.osgi] (MSC service thread 1-1) JBAS011907: Register module: Module "deployment.jboss-as-helloworld-1.war:main" from Service Module Loader
16:27:32,088 INFO  [org.jboss.weld.deployer] (MSC service thread 1-1) JBAS016008: Starting weld service for deployment jboss-as-helloworld-1.war
16:27:32,453 INFO  [stdout] (MSC service thread 1-1) 
16:27:32,499 INFO  [javax.enterprise.resource.webcontainer.jsf.config] (MSC service thread 1-1) Initializing Mojarra 2.1.7-jbossorg-2 (20120412-0335) for context '/jboss-as-helloworld-1'
16:27:33,512 INFO  [org.hibernate.validator.util.Version] (MSC service thread 1-1) Hibernate Validator 4.2.0.Final-redhat-1
16:27:33,795 INFO  [org.jboss.web] (MSC service thread 1-1) JBAS018210: Registering web context: /jboss-as-helloworld-1
16:27:33,989 INFO  [org.jboss.as.server] (management-handler-thread - 2) JBAS018559: Deployed "jboss-as-helloworld-1.war"
16:27:35,714 INFO  [org.jboss.as.repository] (management-handler-thread - 4) JBAS014900: Content added at location /home/maschmid/testing/eap6/jboss-eap-6.0.0.CR1/jboss-eap-6.0/standalone/data/content/9b/873b9889dfa9fdbd7131114a0c3b34f5ffb2a3/content
16:27:35,719 INFO  [org.jboss.as.server.deployment] (MSC service thread 1-1) JBAS015876: Starting deployment of "jboss-as-helloworld-2.war"
16:27:35,753 INFO  [org.jboss.weld.deployer] (MSC service thread 1-1) JBAS016002: Processing weld deployment jboss-as-helloworld-2.war
16:27:35,768 INFO  [org.jboss.weld.deployer] (MSC service thread 1-1) JBAS016005: Starting Services for CDI deployment: jboss-as-helloworld-2.war
16:27:35,775 INFO  [org.jboss.as.osgi] (MSC service thread 1-1) JBAS011907: Register module: Module "deployment.jboss-as-helloworld-2.war:main" from Service Module Loader
16:27:35,779 INFO  [org.jboss.weld.deployer] (MSC service thread 1-1) JBAS016008: Starting weld service for deployment jboss-as-helloworld-2.war
16:27:35,854 INFO  [stdout] (MSC service thread 1-1) Context Name: Hello World Example 1
16:27:35,857 INFO  [javax.enterprise.resource.webcontainer.jsf.config] (MSC service thread 1-1) Initializing Mojarra 2.1.7-jbossorg-2 (20120412-0335) for context '/jboss-as-helloworld-2'
16:27:35,904 INFO  [org.jboss.web] (MSC service thread 1-1) JBAS018210: Registering web context: /jboss-as-helloworld-2
16:27:36,068 INFO  [org.jboss.as.server] (management-handler-thread - 4) JBAS018559: Deployed "jboss-as-helloworld-2.war"
{noformat}


{code}
public class HelloListener implements ServletContextListener
{

   @Override
   public void contextDestroyed(ServletContextEvent arg0)
   {
   }

   @Override
   public void contextInitialized(ServletContextEvent arg0)
   {
      FacesContext facesContext = FacesContext.getCurrentInstance();
      if (facesContext != null) {
         System.out.println("Context Name: " + facesContext.getExternalContext().getContextName());
      }
      else {
         System.out.println("");
      }
   }
}
{code}

{code}
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0"
    xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">

    <display-name>Hello World Example 1</display-name>

    <listener>
        <listener-class>org.jboss.as.quickstarts.helloworld.HelloListener</listener-class>
    </listener>

    <servlet>
        <servlet-name>Faces Servlet</servlet-name>
        <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

</web-app>
{code}

(the other has display-name "Hello World Example 2")

Comment 8 Marek Schmidt 2012-05-31 14:33:35 UTC
Attachment: Added: jboss-as-helloworld-1.war
Attachment: Added: jboss-as-helloworld-2.war


Comment 9 Marek Schmidt 2012-05-31 14:39:47 UTC
Also note that redeploying jboss-as-helloworld-2.war fails with

{noformat}
{16:37:43,018 ERROR [org.apache.catalina.core.ContainerBase.[jboss.web].[default-host].[/jboss-as-helloworld-2]] (MSC service thread 1-1) Exception sending context initialized event to listener instance of class org.jboss.as.quickstarts.helloworld.HelloListener: java.lang.NullPointerException
        at com.sun.faces.config.InitFacesContext$ServletContextAdapter.getContextName(InitFacesContext.java:317) [jsf-impl-2.1.7-redhat-1.jar:2.1.7-redhat-1]
        at org.jboss.as.quickstarts.helloworld.HelloListener.contextInitialized(HelloListener.java:22) [classes:]
        at org.apache.catalina.core.StandardContext.contextListenerStart(StandardContext.java:3392) [jbossweb-7.0.16.Final-redhat-1.jar:]
        at org.apache.catalina.core.StandardContext.start(StandardContext.java:3850) [jbossweb-7.0.16.Final-redhat-1.jar:]
        at org.jboss.as.web.deployment.WebDeploymentService.start(WebDeploymentService.java:90) [jboss-as-web-7.1.2.Final-redhat-1.jar:7.1.2.Final-redhat-1]
        at org.jboss.msc.service.ServiceControllerImpl$StartTask.startService(ServiceControllerImpl.java:1811)
        at org.jboss.msc.service.ServiceControllerImpl$StartTask.run(ServiceControllerImpl.java:1746)
        at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) [rt.jar:1.6.0_30]
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908) [rt.jar:1.6.0_30]
        at java.lang.Thread.run(Thread.java:662) [rt.jar:1.6.0_30
{noformat}

which is also very odd.

Comment 10 Stan Silvert 2012-05-31 14:54:17 UTC
I'm not sure how much everyone knows about this, so I'll summarize.

FacesContext.getCurrentInstance() gets the FacesContext from a ThreadLocal variable.  The FacesServlet is responsible for calling the FacesContextFactory to create the instance.  The constructor for FacesContextImpl calls FacesContext.setCurrentInstance(this).  This sets the ThreadLocal.  The FacesServlet is also responsible for calling FacesContext.release() in a finally block.  release() will remove the ThreadLocal.  Thus, the FacesContext and its assignment to a ThreadLocal should only survive a single request.

The error described in this jira is one where the ThreadLocal is not cleaned up at the end of the request.  So the next request gets a "dirty" FacesContext from the thread used to service an earlier request.

The kind of error we are seeing typically occurs when a framework does something to change or intercept the above logic.  Some possibilities are a custom FacesServlet, FacesContextFactory, or FacesContext implementation.  If Seam is using any of those then that's where you would start looking for the bug.

So given all that, I'll state again that it's unlikely to be a bug in the JSF implementation.  The JSF version we are using has been released for awhile now and I haven't been able to find complaints about FacesContext "leakage" problems.  This would be a fairly obvious bug.

Comment 11 Marek Schmidt 2012-05-31 14:58:49 UTC
Stan,

in my second example, there is no Seam and there is no request. The problem occurs in a servlet listener contextInitialized method, which is called before the FacesServlet is started. So the problem seems to be that the FacesContext.release didn't work properly in the first deployment, as the second deployment gets this dirty FacesContext instance.

Comment 12 Marek Schmidt 2012-05-31 15:06:27 UTC
Let me emphasise once more, the problem is with the FacesContext instance in the "MSC service thread 1-1", not the request threads.

Comment 13 Stan Silvert 2012-05-31 17:24:40 UTC
I guess I was busy writing my incorrect analysis while you were trying to tell me that you reproduced without Seam.  I'll take a closer look.

Comment 14 Stan Silvert 2012-05-31 19:05:34 UTC
I believe I've found the problem.  Notice in the log how you get 
16:27:32,453 INFO  [stdout] (MSC service thread 1-1)
For your code, this means that FacesContext is null because you do System.out.println("");

The problem is that your HelloListener is being called before the JSF listener.  As a workaround for now you can add this to the top of your web.xml
{noformat}
<listener>
       <listener-class>com.sun.faces.config.ConfigureListener</listener-class>
</listener>
{noformat}

As long as that listener comes before your declared listener then JSF will be initialized before you try to call FacesContext.getCurrentInstance().  

I'll see if there is something we can do to make sure that the JSF listener comes first.

Comment 15 Stan Silvert 2012-05-31 20:39:55 UTC
Marek S,

Can you re-attach the Seam apps you originally used to create this problem?  We will eventually need those for testing.

Stan

Comment 16 Marek Novotny 2012-05-31 20:45:26 UTC
Stan, you can find ears in the Steps to reproduce at http://file.brq.redhat.com/~maschmid/JBPAPP-9197/

Comment 17 Stan Silvert 2012-05-31 20:54:48 UTC
BTW, in JSF 2.x, the proper way to do what you are trying to do is to register for the PostConstructApplicationEvent.  This was created in JSF2 to specifically address this situation.

http://docs.oracle.com/cd/E17802_01/j2ee/javaee/javaserverfaces/2.0/docs/api/javax/faces/event/PostConstructApplicationEvent.html

If you know that you are using JSF 2.x then you should not rely on a ServletContextListener.



Comment 18 Stan Silvert 2012-05-31 21:02:21 UTC
I just realized something else.  If you are using JSF 1.x then calling FacesContext.getCurrentInstance() is not allowed outside of a servlet request.

So it looks like we probably have a bug in Seam after all.  You are required to use PostConstructApplicationEvent.

Comment 19 Marek Novotny 2012-06-01 06:54:24 UTC
Link: Added: This issue relates to JBSEAM-4980


Comment 20 Marek Novotny 2012-06-01 06:56:36 UTC
OK, I created issue (JBSEAM-4980) for that as we are using JSF2 solely in Seam 2.3.0.

Anyway that is a side effect for this issue, right? Do you have a fix for the original cause?

Comment 21 Marek Schmidt 2012-06-01 07:34:54 UTC
{quote}
I'll see if there is something we can do to make sure that the JSF listener comes first.
{quote}

Would that really be the proper fix? If I understand this correctly, that would overwrite the facesContext ThreadLocal instance by a correct one, which is mostly fine from the app point of view, but it doesn't change the fact that there is a facesContext instance left over from the previous deployment.

IMHO it is perfectly fine to have FacesContext.getCurrentInstance return null in a ServletContextListener if I configure the FacesServlet to be started later. This also seems to be the behaviour which Seam is used to. So I think the only fix that is necessary is to release the FacesContext in the MSC service thread after application initialization.  

To summarize, there are two issues:
1. FacesContext is not released in the MSC service thread after application initialization.
2. FacesContext is not initialized first.

I believe only 1. is the real issue, 2. is not an issue, makes sense only as workaround for 1.

Comment 22 Marek Schmidt 2012-06-01 07:50:11 UTC
Updating to critical, as this issue gives applications access to files belonging to a different deployment that has been handled by the same MSC service thread through the FacesContext.getCurrentInstance().getResourceAsStream().

Comment 23 Marek Schmidt 2012-06-01 10:00:48 UTC
Labels: Added: eap6_need_triage


Comment 24 Stan Silvert 2012-06-01 12:58:27 UTC
{quote}Anyway that is a side effect for this issue, right? Do you have a fix for the original cause?{quote}
Using a ServletContextListener to access FacesContext is the original cause.  You shouldn't do that.

The issue here is that ordering of ServletContextListener is undefined.  So you can not rely on FacesContext.getCurrentInstance() inside a ServletContextListener.  Even if we set the order in AS it wouldn't be guaranteed to work on other containers.
{quote}
    I'll see if there is something we can do to make sure that the JSF listener comes first.

Would that really be the proper fix?{quote}
No, that wouldn't be the proper fix.  I never should have suggested it.

{quote}If I understand this correctly, that would overwrite the facesContext ThreadLocal instance by a correct one, which is mostly fine from the app point of view, but it doesn't change the fact that there is a facesContext instance left over from the previous deployment.{quote}
I think you have a good point here.  It's fine as long as the app does things the right way.  But Mojarra should not leave things in the ThreadLocal if it can help it.  I'll open a Jira against Mojarra.

{quote}IMHO it is perfectly fine to have FacesContext.getCurrentInstance return null in a ServletContextListener if I configure the FacesServlet to be started later. This also seems to be the behaviour which Seam is used to. So I think the only fix that is necessary is to release the FacesContext in the MSC service thread after application initialization. {quote}
The problem is it's not fine to call FacesContext.getCurrentInstance() in a ServletContextListener.  The spec should make this explicit, but it doesn't.

The ServletContextListener.contextInitialized() method will always be called before the FacesServlet is started, so I'm not sure what you mean by "if I configure the FacesServlet to be started later".  If you can do what you need to do later, why would you code something to try at two different times?

{quote}
To summarize, there are two issues:
1. FacesContext is not released in the MSC service thread after application initialization.
2. FacesContext is not initialized first.

I believe only 1. is the real issue, 2. is not an issue, makes sense only as workaround for 1.
{quote}
Neither of those is an issue as far as Seam is concerned.  If Seam does things according to the JSF spec then it will be OK.

{quote}
Updating to critical,{quote} 
Unless I find out I'm wrong, I'll be closing this as "Wont Fix".  See below.  The JSF impl doesn't actually do anything wrong, though perhaps it could clean up a little better.

{quote}as this issue gives applications access to files belonging to a different deployment that has been handled by the same MSC service thread through the FacesContext.getCurrentInstance().getResourceAsStream().{quote}
I assume you mean FacesContext.getCurrentInstance().getExternalContext().getResourceAsStream()?  It is a violation of the JSF spec to call that during application initialization.  (Well, technically, the call is undefined).

See http://docs.oracle.com/cd/E17802_01/j2ee/javaee/javaserverfaces/2.0/docs/api/javax/faces/context/ExternalContext.html

getResourceAsStream() does not have the "valid to call during startup" designation.



Comment 25 Marek Schmidt 2012-06-01 13:13:17 UTC
Yes, I meant FacesContext.getCurrentInstance().getExternalContext().getResourceAsStream(), sorry

{quote}
getResourceAsStream() does not have the "valid to call during startup" designation.
{quote}

Yes it does. Unless I am reading it wrong, the docs you linked to says:

{quote}
It is valid to call this method during application startup or shutdown. If called during application startup or shutdown, this method calls through to the getResourceAsStream() method on the same container context instance (ServletContext or PortletContext) as the one used when calling getResourceAsStream() on the ExternalContext returned by the FacesContext during an actual request.
{quote}

And even if it would be undefined, I'd consider a behaviour which would allow you to retrieve resources from another deployment as a serious issue. 

Comment 26 Stan Silvert 2012-06-01 13:42:27 UTC
You're right.  I didn't click through to the detail that says it is "valid to call".  So it does indeed have that designation.

However, that doesn't change the fact that you need to call it after notification from the PostConstructApplicationEvent.  You can't rely on it from a ServletContextListener.

I think you are also right that it's a serious issue for Mojarra because it could be a security concern and I'll note that in the jira for Mojarra.

But as far as Seam is concerned, it still has to fix its code to stop using ServletContextListener to get FacesContext.

Comment 27 Stan Silvert 2012-06-01 15:36:36 UTC
I've opened this against Mojarra:
http://java.net/jira/browse/JAVASERVERFACES-2436

Perhaps we should keep this open until the Mojarra team decides what they want to do.

Comment 28 Stan Silvert 2012-06-01 20:17:32 UTC
{quote}Perhaps we should keep this open until the Mojarra team decides what they want to do.{quote}

Looks like we got our answer.  See Roger's comment on http://java.net/jira/browse/JAVASERVERFACES-2436.

Marek, you've uncovered a fine nest of bugs.  So far we have:

2 JSF spec issues
1 Mojarra implementation issue
1 Seam implementation issue

Nice work.

Comment 30 Stan Silvert 2012-06-04 18:16:31 UTC
Workaround Description: Added: Make sure that you do not try to call FacesContext.getCurrentInstance() from a ServletContextListener.  If you are using FacesContext at application initialization it should only be done in response to a JSF PostConstructApplicationEvent.  And then, you should always call FacesContext.release() in a finally block when you are done.

Presumably, once http://java.net/jira/browse/JAVASERVERFACES-2436 is fixed, the call to FacesContext.release() will be done for you just as it is during a request to the FacesServlet.


Comment 31 David Jorm 2012-06-05 00:32:41 UTC
Lowering priority to major as this is not an EAP 6 GA blocker.

Comment 33 Rajesh Rajasekaran 2012-07-11 19:53:08 UTC
Labels: Removed: eap6_need_triage Added: eap601candidate


Comment 34 Stan Silvert 2012-07-21 19:59:49 UTC
Mojarra has fixed this in 2.1.11.  I've done a pull request to get our fork of that into EAP.

Comment 35 Stan Silvert 2012-07-21 19:59:49 UTC
Git Pull Request: Added: https://github.com/jbossas/jboss-as/pull/2731


Comment 36 Stan Silvert 2012-07-28 23:28:48 UTC
This is now fixed in the latest EAP branch.

Comment 37 Paul Gier 2012-09-18 19:46:12 UTC
Git Pull Request: Removed: https://github.com/jbossas/jboss-as/pull/2731 Added: https://github.com/jbossas/jboss-as/pull/2731


Comment 38 Shelly McGowan 2012-09-18 19:46:15 UTC
Git Pull Request: Removed: https://github.com/jbossas/jboss-as/pull/2731 Added: https://github.com/jbossas/jboss-as/pull/2731


Comment 39 Marek Schmidt 2012-09-21 14:32:14 UTC
Verified on EAP 6.0.1.ER2

Comment 40 Tom WELLS 2012-10-04 12:01:24 UTC
Release Notes Docs Status: Added: Not Yet Documented
Git Pull Request: Removed: https://github.com/jbossas/jboss-as/pull/2731 Added: https://github.com/jbossas/jboss-as/pull/2731
Affects: Added: Release Notes


Comment 41 Tom WELLS 2012-10-04 12:01:37 UTC
Updated release note fields.

Comment 42 Dana Mison 2012-10-17 22:31:57 UTC
reopening for release notes updates

Comment 43 Dana Mison 2012-10-17 22:34:03 UTC
Writer: Added: elogue


Comment 44 Dana Mison 2012-10-17 23:13:31 UTC
Writer: Removed: elogue Added: tomwells


Comment 45 Tom WELLS 2012-10-22 07:43:40 UTC
Could someone please summarize the fix and result of this JIRA for the release notes, and check the Cause/Consequence below:

Cause: FacesContext.getCurrentInstance sometimes returns a non-null instance belonging to a previous deployment.
Consequence: When deploying two Seam2 applications, the second would occasionally not work, as configuration files were loaded from the first application.

Thanks.

Comment 46 Tom WELLS 2012-10-22 07:44:07 UTC
Release Notes Docs Status: Removed: Not Yet Documented Added: Needs More Info


Comment 47 Marek Schmidt 2012-10-29 17:19:41 UTC
It is a Mojarra issue, see the upstream summary of the changes http://java.net/jira/secure/attachment/50553/changebundle-2436.txt (from the upstream Mojarra issue http://java.net/jira/browse/JAVASERVERFACES-2436 )

To summarise the summary:

The FacesContext that is made available during application startup (InitFacesContext) is held in a ThreadLocal. The reference was not properly cleaned up. The fix adds additional tracking and cleaning of the InitFacesContext references so that another deployment reusing the same thread won't get the InitFacesContext reference belonging to the previous deployment.

The Cause and Consequence are mostly fine by me. The issue is not strictly Seam-specific, though. Any application that call FacesContext.getCurrentInstance() from a ServletContextListener would be affected and the resulting FacesContext instance might belong to a previous deployment (so the consequence depend on what exactly the application does with the FacesContext during startup, Seam uses it for reading configuration files, hence the Seam-specific consequence)

Comment 48 sgilda 2012-10-29 18:06:25 UTC
Thanks Marek!

Comment 49 sgilda 2012-10-29 18:34:11 UTC
Release Notes Docs Status: Removed: Needs More Info Added: Documented as Resolved Issue
Release Notes Text: Added: In some situations, the <code>FaceContext.getCurrentInstance()</code> method call from a <classname>ServletContextListener</classname> during application startup returned the external context from a different deployment. This was caused by a failure to properly clean up the <classname>FacesContext</classname> that was held in a ThreadLocal, allowing a JSF WAR to gain access to another WAR's resources. The fix adds additional tracking and cleaning of the <classname>InitFacesContext<classname> references so that another deployment reusing the same thread won't get references belonging to the previous deployment.
Git Pull Request: Removed: https://github.com/jbossas/jboss-as/pull/2731 Added: https://github.com/jbossas/jboss-as/pull/2731


Comment 50 sgilda 2012-10-29 18:34:44 UTC
Tom, I made a first pass at the release notes text. Feel free to edit as you see fit.

Comment 51 Tom WELLS 2012-10-29 23:23:53 UTC
Release Notes Text: Removed: In some situations, the <code>FaceContext.getCurrentInstance()</code> method call from a <classname>ServletContextListener</classname> during application startup returned the external context from a different deployment. This was caused by a failure to properly clean up the <classname>FacesContext</classname> that was held in a ThreadLocal, allowing a JSF WAR to gain access to another WAR's resources. The fix adds additional tracking and cleaning of the <classname>InitFacesContext<classname> references so that another deployment reusing the same thread won't get references belonging to the previous deployment. Added: In some situations, the <code>FaceContext.getCurrentInstance()</code> method call from a <classname>ServletContextListener</classname> during application startup returned the external context from a different deployment. This was caused by a failure to properly clean up the <classname>FacesContext</classname> that was held in a ThreadLocal, allowing a JSF WAR to gain access to another WAR's resources. Additional tracking and cleaning of the <classname>InitFacesContext<classname> references has been added, so that another deployment reusing the same thread won't get references belonging to the previous deployment.


Comment 52 sgilda 2012-10-30 00:07:22 UTC
Release Notes Text: Removed: In some situations, the <code>FaceContext.getCurrentInstance()</code> method call from a <classname>ServletContextListener</classname> during application startup returned the external context from a different deployment. This was caused by a failure to properly clean up the <classname>FacesContext</classname> that was held in a ThreadLocal, allowing a JSF WAR to gain access to another WAR's resources. Additional tracking and cleaning of the <classname>InitFacesContext<classname> references has been added, so that another deployment reusing the same thread won't get references belonging to the previous deployment. Added: In some situations, the `FaceContext.getCurrentInstance()` method call from a `ServletContextListener` during application startup returned the external context from a different deployment. This was caused by a failure to properly clean up the `FacesContext` that was held in a ThreadLocal, allowing a JSF WAR to gain access to another WAR's resources. Additional tracking and cleaning of the `InitFacesContext` references has been added, so that another deployment reusing the same thread won't get references belonging to the previous deployment.


Comment 53 Anne-Louise Tangring 2012-11-13 20:07:45 UTC
Release Notes Docs Status: Removed: Documented as Resolved Issue 
Writer: Removed: tomwells 
Release Notes Text: Removed: In some situations, the `FaceContext.getCurrentInstance()` method call from a `ServletContextListener` during application startup returned the external context from a different deployment. This was caused by a failure to properly clean up the `FacesContext` that was held in a ThreadLocal, allowing a JSF WAR to gain access to another WAR's resources. Additional tracking and cleaning of the `InitFacesContext` references has been added, so that another deployment reusing the same thread won't get references belonging to the previous deployment. 
Docs QE Status: Removed: NEW 


Comment 54 Marek Schmidt 2013-02-21 11:18:06 UTC
closing, this has been verified on EAP 6.0.1.ER2 already.