dev@javaserverfaces.java.net

[REVIEW] Disable web.xml scanning in ConfigureListener when running in GlassFish

From: Ryan Lubke <Ryan.Lubke_at_Sun.COM>
Date: Fri, 10 Feb 2006 13:57:08 -0800


GlassFish has an optimization in place to only call
ConfiguerListener.contextInitialized() if the
FacesServlet is present in the web.xml. The Configure
Listener has similar logic, and in the case of
GlassFish, the ConfigureListener's version doens't
need to be invoked.


SECTION: Modified Files
----------------------------
M src/com/sun/faces/LogStrings.properties
M src/com/sun/faces/application/ViewHandlerImpl.java
  - Ignore these - this is for issue 236 which I
    haven't checked in.

M src/com/sun/faces/config/ConfigureListener.java
  - add boolean field with protected setter
    that, if true, will disable the web.xml
    scanning optimization.
M build.xml
 - If we're building for glassfish, update jsf_core.tld
   to use the GlassFishConfigureListener otherwise
   use the default ConfigureListener and use
   the web.xml scanning logic by default (useful when
   Sun's impl is installed in the application classloader
   of Tomcat)
M conf/share/jsf_core.tld
 - replaced the default value of the listener with a
   String that ANT can replace


A src/com/sun/faces/config/GlassFishConfigureListener.java
  - disable web.xml scanning and call super.contextInitialized()


SECTION: Diffs
----------------------------
Index: build.xml
===================================================================
RCS file: /cvs/javaserverfaces-sources/jsf-ri/build.xml,v
retrieving revision 1.204
diff -u -r1.204 build.xml
--- build.xml 7 Feb 2006 20:40:21 -0000 1.204
+++ build.xml 10 Feb 2006 21:51:28 -0000
@@ -242,6 +242,21 @@
               toDir="${build.classes.dir}/META-INF"/>
         <copy file="${conf.share.dir}/jsf_core.tld"
               toDir="${build.classes.dir}/META-INF"/>
+ <if>
+ <equals arg1="${container.name}" arg2="glassfish"/>
+ <then>
+ <property name="listener.class" value="com.sun.faces.config.GlassFishConfigureListener"/>
+ </then>
+ <else>
+ <property name="listener.class" value="com.sun.faces.config.ConfigureListener"/>
+ </else>
+ </if>
+
+ <echo message="INFO: Updating jsf_core.tld to use ServletContextListener ${listener.class}"/>
+
+ <replace file="${build.classes.dir}/META-INF/jsf_core.tld"
+ token="|CONFIG_LISTEN_CLASS|"
+ value="${listener.class}"/>
 
     </target>
 
Index: conf/share/jsf_core.tld
===================================================================
RCS file: /cvs/javaserverfaces-sources/jsf-ri/conf/share/jsf_core.tld,v
retrieving revision 1.57
diff -u -r1.57 jsf_core.tld
--- conf/share/jsf_core.tld 22 Aug 2005 22:10:03 -0000 1.57
+++ conf/share/jsf_core.tld 10 Feb 2006 21:51:28 -0000
@@ -71,7 +71,7 @@
           application including it is initialized by the container.
     -->
  <listener>
- <listener-class>com.sun.faces.config.ConfigureListener</listener-class>
+ <listener-class>|CONFIG_LISTEN_CLASS|</listener-class>
  </listener>
 
 
Index: src/com/sun/faces/LogStrings.properties
===================================================================
RCS file: /cvs/javaserverfaces-sources/jsf-ri/src/com/sun/faces/LogStrings.properties,v
retrieving revision 1.6
diff -u -r1.6 LogStrings.properties
--- src/com/sun/faces/LogStrings.properties 7 Feb 2006 20:40:22 -0000 1.6
+++ src/com/sun/faces/LogStrings.properties 10 Feb 2006 21:51:28 -0000
@@ -37,5 +37,6 @@
 jsf.navigation.no_matching_outcome_action="JSF1013: Unable to find matching navigation case from view ID ''{0}'' for outcome ''{1}'' and action ''{2}''
 jsf.util_no_annotation_processed=JSF1014: Unable to load annotation class ''{0}''. As a result, this annotation will not be processed.
 jsf.config.listener.version=Initializing Sun''s JavaServer Faces implementation (|version.string|) for context ''{0}''
+jsf.viewhandler.requestpath.recursion="JSF1015: Request path ''{0}'' begins with one or more occurrences of the FacesServlet prefix path mapping ''{1}''.
 # core tags
 jsf.core.tags.eval_result_not_expected_type=JSF1011: Evaluation of expression for attribute ''{0}'' resulted in unexpected type. Expected {1}, but received {2}.
Index: src/com/sun/faces/application/ViewHandlerImpl.java
===================================================================
RCS file: /cvs/javaserverfaces-sources/jsf-ri/src/com/sun/faces/application/ViewHandlerImpl.java,v
retrieving revision 1.64
diff -u -r1.64 ViewHandlerImpl.java
--- src/com/sun/faces/application/ViewHandlerImpl.java 23 Jan 2006 21:01:43 -0000 1.64
+++ src/com/sun/faces/application/ViewHandlerImpl.java 10 Feb 2006 21:51:28 -0000
@@ -374,12 +374,24 @@
             throw new NullPointerException(message);
         }
 
- String requestURI = viewToExecute.getViewId();
- if (logger.isLoggable(Level.FINE)) {
+ String mapping = getFacesMapping(context);
+ String requestURI =
+ updateRequestURI(viewToExecute.getViewId(), mapping);
+
+ if (mapping.equals(requestURI)) {
+ // The request was to the FacesServlet only - no path info
+ // on some containers this causes a recursion in the
+ // RequestDispatcher and the request appears to hang.
+ // If this is detected, return status 404
+ HttpServletResponse response = (HttpServletResponse)
+ context.getExternalContext().getResponse();
+ response.sendError(HttpServletResponse.SC_NOT_FOUND);
+ return;
+ }
+ if (logger.isLoggable(Level.FINE)) {
             logger.fine("About to execute view " + requestURI);
         }
-
- String mapping = getFacesMapping(context);
+
         String newViewId = requestURI;
         // If we have a valid mapping (meaning we were invoked via the
         // FacesServlet) and we're extension mapped, do the replacement.
@@ -746,6 +758,39 @@
         } else {
            // Servlet invoked using extension mapping
             return servletPath.substring(servletPath.lastIndexOf('.'));
+ }
+ }
+
+ /**
+ * <p>if the specified mapping is a prefix mapping, and the provided
+ * request URI (usually the value from <code>ExternalContext.getRequestServletPath()</code>)
+ * starts with <code>mapping + '/'</code>, prune the mapping from the
+ * URI and return it, otherwise, return the original URI.
+ * @param uri the servlet request path
+ * @param mapping the FacesServlet mapping used for this request
+ * @return the URI without additional FacesServlet mappings
+ * @since 1.2
+ */
+ private String updateRequestURI(String uri, String mapping) {
+
+ if (!isPrefixMapped(mapping)) {
+ return uri;
+ } else {
+ int length = mapping.length() + 1;
+ StringBuilder builder = new StringBuilder(length);
+ builder.append(mapping).append('/');
+ String mappingMod = builder.toString();
+ boolean logged = false;
+ while (uri.startsWith(mappingMod)) {
+ if (!logged && logger.isLoggable(Level.WARNING)) {
+ logged = true;
+ logger.log(Level.WARNING,
+ "jsf.viewhandler.requestpath.recursion",
+ new Object[] {uri, mapping});
+ }
+ uri = uri.substring(length - 1);
+ }
+ return uri;
         }
     }
 
Index: src/com/sun/faces/config/ConfigureListener.java
===================================================================
RCS file: /cvs/javaserverfaces-sources/jsf-ri/src/com/sun/faces/config/ConfigureListener.java,v
retrieving revision 1.60
diff -u -r1.60 ConfigureListener.java
--- src/com/sun/faces/config/ConfigureListener.java 9 Feb 2006 20:18:38 -0000 1.60
+++ src/com/sun/faces/config/ConfigureListener.java 10 Feb 2006 21:51:28 -0000
@@ -273,6 +273,10 @@
     private PropertyResolver legacyPRChainHead = null;
     private ArrayList<ELResolver> elResolversFromFacesConfig = null;
     
+ // flag to disable web.xml scanning completely - to be used
+ // by subclasses of ConfigureListener.
+ private boolean shouldScanWebXml = true;
+
     // ------------------------------------------ ServletContextListener Methods
 
     /**
@@ -365,7 +369,8 @@
             // Check to see if the FacesServlet is present in the
             // web.xml. If it is, perform faces configuration as normal,
             // otherwise, simply return.
- if (!isFeatureEnabled(context, FORCE_LOAD_CONFIG)) {
+ if (shouldScanWebXml &&
+ !isFeatureEnabled(context, FORCE_LOAD_CONFIG)) {
                 WebXmlProcessor processor = new WebXmlProcessor(context);
                 if (!processor.isFacesServletPresent()) {
                     if (LOGGER.isLoggable(Level.FINE)) {
@@ -691,6 +696,11 @@
         return afactory.getApplication();
 
     }
+
+
+ protected void scanWebXml(boolean shouldScan) {
+ this.shouldScanWebXml = shouldScan;
+ }
 
 
     /**
@@ -811,7 +821,9 @@
                 prevInChain = instance;
             }
             legacyPRChainHead = (PropertyResolver) instance;
- associate.setLegacyPRChainHead(legacyPRChainHead);
+ if (associate != null) {
+ associate.setLegacyPRChainHead(legacyPRChainHead);
+ }
         }
         
         // process custom el-resolver elements if any
@@ -864,7 +876,9 @@
                 prevInChain = instance;
             }
             legacyVRChainHead = (VariableResolver) instance;
- associate.setLegacyVRChainHead(legacyVRChainHead);
+ if (associate != null) {
+ associate.setLegacyVRChainHead(legacyVRChainHead);
+ }
         }
 
         values = config.getViewHandlers();
@@ -1741,15 +1755,19 @@
             // register an empty resolver for now. It will be populated after the
             // first request is serviced.
             CompositeELResolver compositeELResolverForJsp =
- new FacesCompositeELResolver();
- appAssociate.setFacesELResolverForJsp(compositeELResolverForJsp);
+ new FacesCompositeELResolver();
+ if (appAssociate != null) {
+ appAssociate.setFacesELResolverForJsp(compositeELResolverForJsp);
+ }
                     
             // get JspApplicationContext.
             JspApplicationContext jspAppContext = JspFactory.getDefaultFactory()
                     .getJspApplicationContext(context);
     
             // cache the ExpressionFactory instance in ApplicationAssociate
- appAssociate.setExpressionFactory(jspAppContext.getExpressionFactory());
+ if (appAssociate != null) {
+ appAssociate.setExpressionFactory(jspAppContext.getExpressionFactory());
+ }
     
             // register compositeELResolver with JSP
             try {


SECTION: New Files
----------------------------
SEE ATTACHMENTS