dev@javaserverfaces.java.net

Code Review : issue 11984

From: Sheetal Vartak <sheetal.vartak_at_oracle.com>
Date: Tue, 7 Dec 2010 16:20:01 -0800

Hi All,
Glassfish allows creation of virtual servers. Virtual hosting refers to the ability to run several web sites (domains) from a single physical server machine with a single IP address. To explain a little about how one sets up a virtual host, here are a few steps :

1> start the Glassfish domain (domain1 by default).
2> create a virtual server :
./asadmin create-virtual-server --hosts localhost -u admin myHost
One can specify http-listeners for this host.

3> deploy the application :
./asadmin deploy --virtualservers myHost <war>
OR
./asadmin deploy <war> (this makes sure that the war is enabled on all virtual servers. in our case, "server" which is the default virtual server and "myHost")

Now deploying to a specific virtual server worked just fine. But the second case of deployment was bombing with an NPE.

ExternalContext's implementation (InitFacesContext$ServletContextWrapper) has an ApplicationMap instance that gets populated with a bunch of attributes including Application and ApplicationAssociate. Application is a singleton which gets added to the ApplicationMap only when it gets created. Similarly, ApplicationAssociate gets added to the map only during its creation which happens only once too on a per-web app basis.

During the deployment process (where the virtual server is not specified), the JSF env gets created correctly and the app gets deployed to the first virtual server in the list in GF. As part of this process, a new ExternalContext instance gets created and its applicationMap gets populated. This is the time when the Application and ApplicationAssociate instances get created and added to the map.
When the JSF env is being created a second time around for the next virtual server, a new ExternalContext instance is created, its applicationMap is also populated. But its applicationMap does not contain the "Application" and "ApplicationAssociate" entries since that only happens during the creation of those entries. Hence the proposed fix.

I tried to find a more suitable place to introduce the fix. But ResourceHandlerImpl's constructor seems like the best place. Please let me know if you feel otherwise.

Thanks
Sheetal


http://java.net/jira/browse/GLASSFISH-11984

SECTION: Modified Files
----------------------------
M jsf-ri/src/main/java/com/sun/faces/application/ApplicationAssociate.java
M jsf-ri/src/main/java/com/sun/faces/application/resource/ResourceHandlerImpl.java


SECTION: Diffs
----------------------------
Index: jsf-ri/src/main/java/com/sun/faces/application/ApplicationAssociate.java
===================================================================
--- jsf-ri/src/main/java/com/sun/faces/application/ApplicationAssociate.java (revision 8748)
+++ jsf-ri/src/main/java/com/sun/faces/application/ApplicationAssociate.java (working copy)
@@ -240,6 +240,10 @@
         applicationStateInfo = new ApplicationStateInfo();
     }
 
+ public static void addToExternalContextMap(ExternalContext ec) {
+ ec.getApplicationMap().put(ASSOCIATE_KEY, getCurrentInstance());
+ }
+
     public static ApplicationAssociate getInstance(ExternalContext
          externalContext) {
         if (externalContext == null) {
Index: jsf-ri/src/main/java/com/sun/faces/application/resource/ResourceHandlerImpl.java
===================================================================
--- jsf-ri/src/main/java/com/sun/faces/application/resource/ResourceHandlerImpl.java (revision 8748)
+++ jsf-ri/src/main/java/com/sun/faces/application/resource/ResourceHandlerImpl.java (working copy)
@@ -40,6 +40,7 @@
 
 package com.sun.faces.application.resource;
 
+import javax.faces.application.Application;
 import com.sun.faces.application.ApplicationAssociate;
 import com.sun.faces.config.WebConfiguration;
 import static com.sun.faces.config.WebConfiguration.WebContextInitParameter.*;
@@ -91,6 +92,22 @@
         creationTime = System.currentTimeMillis();
         webconfig = WebConfiguration.getInstance();
         ExternalContext extContext = FacesContext.getCurrentInstance().getExternalContext();
+
+ //it can be the case where a JSF app is getting deployed to multiple virtual servers
+ //in that case, check if there is an existing ApplicationImpl instance around.
+ //if so, then add the ApplicationImpl and its corresponding ApplicationAssociate instances
+ //to the ApplicationMap
+
+
+ if (ApplicationAssociate.getInstance(extContext) == null) {
+ Application app =
+ FacesContext.getCurrentInstance().getApplication();
+ if (app != null) {
+ extContext.getApplicationMap().put(app.getClass().getName(), app);
+ ApplicationAssociate.addToExternalContextMap(extContext);
+ }
+ }
+
         manager = ApplicationAssociate.getInstance(extContext).getResourceManager();
         initExclusions();
         initMaxAge();