You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by pa...@apache.org on 2022/08/30 13:23:44 UTC

[myfaces] branch main updated: MYFACES-4442: avoid UnsupportedOperationException

This is an automated email from the ASF dual-hosted git repository.

paulnicolucci pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/myfaces.git


The following commit(s) were added to refs/heads/main by this push:
     new e0a2812bd MYFACES-4442: avoid UnsupportedOperationException
     new fcaf6d46a Merge pull request #292 from pnicolucci/MYFACES-4442
e0a2812bd is described below

commit e0a2812bde32c8994b136f067236cb6d0c9ae608
Author: Paul Nicolucci <pn...@gmail.com>
AuthorDate: Mon Aug 29 10:47:47 2022 -0400

    MYFACES-4442: avoid UnsupportedOperationException
---
 .../myfaces/webapp/FacesInitializerImpl.java       | 77 ++++++++----------
 .../webapp/MyFacesContainerInitializer.java        | 92 ++++++++++++++--------
 2 files changed, 91 insertions(+), 78 deletions(-)

diff --git a/impl/src/main/java/org/apache/myfaces/webapp/FacesInitializerImpl.java b/impl/src/main/java/org/apache/myfaces/webapp/FacesInitializerImpl.java
index 3752d2b34..db5a91f94 100644
--- a/impl/src/main/java/org/apache/myfaces/webapp/FacesInitializerImpl.java
+++ b/impl/src/main/java/org/apache/myfaces/webapp/FacesInitializerImpl.java
@@ -85,19 +85,19 @@ public class FacesInitializerImpl implements FacesInitializer
     private static final Logger log = Logger.getLogger(FacesInitializerImpl.class.getName());
 
     public static final String CDI_BEAN_MANAGER_INSTANCE = "oam.cdi.BEAN_MANAGER_INSTANCE";
-    
+
     private static final String CDI_SERVLET_CONTEXT_BEAN_MANAGER_ATTRIBUTE = 
         "jakarta.enterprise.inject.spi.BeanManager";
 
     public static final String INJECTED_BEAN_STORAGE_KEY = "org.apache.myfaces.spi.BEAN_ENTRY_STORAGE";
 
     public static final String INITIALIZED = "org.apache.myfaces.INITIALIZED";
-    
+
     private static final byte FACES_INIT_PHASE_PREINIT = 0;
     private static final byte FACES_INIT_PHASE_POSTINIT = 1;
     private static final byte FACES_INIT_PHASE_PREDESTROY = 2;
     private static final byte FACES_INIT_PHASE_POSTDESTROY = 3;
-    
+
     /**
      * Performs all necessary initialization tasks like configuring this Faces
      * application.
@@ -115,14 +115,14 @@ public class FacesInitializerImpl implements FacesInitializer
             }
             return;
         }
-        
+
         try
         {
             if (log.isLoggable(Level.FINEST))
             {
                 log.finest("Initializing MyFaces");
             }
-            
+
             long start = System.currentTimeMillis();
 
             // Some parts of the following configuration tasks have been implemented 
@@ -144,43 +144,34 @@ public class FacesInitializerImpl implements FacesInitializer
             {
                 spf.initKnownServiceProviderMapInfo(externalContext, spfConfig);
             }
-            
-            // Parse and validate the web.xml configuration file
-            
+
             if (!WebConfigParamUtils.getBooleanInitParameter(externalContext,
                     MyfacesConfig.INITIALIZE_ALWAYS_STANDALONE, false))
             {
-                FacesServletMappingUtils.ServletRegistrationInfo facesServletRegistration =
-                        FacesServletMappingUtils.getFacesServletRegistration(facesContext, servletContext);
-                if (facesServletRegistration == null
-                        || facesServletRegistration.getMappings() == null
-                        || facesServletRegistration.getMappings().length == 0)
+                // check to see if the FacesServlet was found by MyFacesContainerInitializer
+                Boolean mappingAdded = (Boolean) servletContext.getAttribute(
+                    MyFacesContainerInitializer.FACES_SERVLET_FOUND);
+
+                if (mappingAdded == null || !mappingAdded)
                 {
-                    // check to see if the FacesServlet was found by MyFacesContainerInitializer
-                    Boolean mappingAdded = (Boolean) servletContext.getAttribute(
-                        MyFacesContainerInitializer.FACES_SERVLET_FOUND);
+                    // check if the FacesServlet has been added dynamically
+                    // in a Servlet 3.0 environment by MyFacesContainerInitializer
+                    mappingAdded = (Boolean) servletContext.getAttribute(
+                        MyFacesContainerInitializer.FACES_SERVLET_ADDED_ATTRIBUTE);
 
                     if (mappingAdded == null || !mappingAdded)
                     {
-                        // check if the FacesServlet has been added dynamically
-                        // in a Servlet 3.0 environment by MyFacesContainerInitializer
-                        mappingAdded = (Boolean) servletContext.getAttribute(
-                            MyFacesContainerInitializer.FACES_SERVLET_ADDED_ATTRIBUTE);
-
-                        if (mappingAdded == null || !mappingAdded)
+                        if (log.isLoggable(Level.WARNING))
                         {
-                            if (log.isLoggable(Level.WARNING))
-                            {
-                                log.warning("No mappings of FacesServlet found. Abort initializing MyFaces.");
-                            }
-                            return;
+                            log.warning("No mappings of FacesServlet found. Abort initializing MyFaces.");
                         }
+                        return;
                     }
                 }
             }
-            
+
             initCDIIntegration(servletContext, externalContext);
-            
+
             initContainerIntegration(servletContext, externalContext);
 
             // log environment integrations
@@ -205,10 +196,10 @@ public class FacesInitializerImpl implements FacesInitializer
             initWebsocketIntegration(servletContext, externalContext);
 
             WebConfigParamsLogger.logWebContextParams(facesContext);
-            
+
             //Start ViewPoolProcessor if necessary
             ViewPoolProcessor.initialize(facesContext);
-            
+
             MyfacesConfig config = MyfacesConfig.getCurrentInstance(facesContext.getExternalContext());
             if (config.isAutomaticExtensionlessMapping())
             {
@@ -222,7 +213,7 @@ public class FacesInitializerImpl implements FacesInitializer
                 facesContext.getExternalContext().getApplicationMap().put(
                         MyfacesConfig.RESOURCE_BUNDLE_CONTROL, resourceBundleControl);
             }
- 
+
             // print out a very prominent log message if the project stage is != Production
             if (!facesContext.isProjectStage(ProjectStage.Production)
                     && !facesContext.isProjectStage(ProjectStage.UnitTest))
@@ -476,33 +467,33 @@ public class FacesInitializerImpl implements FacesInitializer
         // before Application and RenderKit factories, so we should use different object. 
         return _createFacesContext(servletContext, true);
     }
-        
+
     @Override
     public void destroyStartupFacesContext(FacesContext facesContext)
     {
         _releaseFacesContext(facesContext);
     }
-    
+
     @Override
     public FacesContext initShutdownFacesContext(ServletContext servletContext)
     {
         return _createFacesContext(servletContext, false);
     }
-    
-    @Override    
+
+    @Override
     public void destroyShutdownFacesContext(FacesContext facesContext)
     {
         _releaseFacesContext(facesContext);
     }
-    
+
     private FacesContext _createFacesContext(ServletContext servletContext, boolean startup)
     {
         ExternalContext externalContext = new StartupServletExternalContextImpl(servletContext, startup);
         ExceptionHandler exceptionHandler = new ExceptionHandlerImpl();
-        FacesContext facesContext = new StartupFacesContextImpl(externalContext, 
+        FacesContext facesContext = new StartupFacesContextImpl(externalContext,
                 externalContext, exceptionHandler, startup);
-        
-        // If getViewRoot() is called during application startup or shutdown, 
+
+        // If getViewRoot() is called during application startup or shutdown,
         // it should return a new UIViewRoot with its locale set to Locale.getDefault().
         UIViewRoot startupViewRoot = new UIViewRoot();
         startupViewRoot.setLocale(Locale.getDefault());
@@ -510,7 +501,7 @@ public class FacesInitializerImpl implements FacesInitializer
         
         return facesContext;
     }
-    
+
     private void _releaseFacesContext(FacesContext facesContext)
     {        
         // make sure that the facesContext gets released.
@@ -518,7 +509,7 @@ public class FacesInitializerImpl implements FacesInitializer
         if (facesContext != null)
         {
             facesContext.release();
-        }        
+        }
     }
 
     /**
@@ -819,7 +810,7 @@ public class FacesInitializerImpl implements FacesInitializer
      * @return false if there are not plugins defined via ServiceLoader.
      */
     private boolean loadFacesInitPluginsViaServiceLoader(ServletContext servletContext)
-    {   
+    {
         ServiceLoader<StartupListener> loader = ServiceLoader.load(StartupListener.class,
                 ClassUtils.getContextClassLoader());
 
diff --git a/impl/src/main/java/org/apache/myfaces/webapp/MyFacesContainerInitializer.java b/impl/src/main/java/org/apache/myfaces/webapp/MyFacesContainerInitializer.java
index 5bbc8978a..6c919d215 100644
--- a/impl/src/main/java/org/apache/myfaces/webapp/MyFacesContainerInitializer.java
+++ b/impl/src/main/java/org/apache/myfaces/webapp/MyFacesContainerInitializer.java
@@ -60,7 +60,7 @@ import org.apache.myfaces.util.lang.ClassUtils;
 
 /**
  * This class is called by any Java EE 6 complaint container at startup.
- * It checks if the current webapp is a Faces-webapp by checking if some of 
+ * It checks if the current webapp is a Faces-webapp by checking if some of
  * the Faces related annotations are specified in the webapp classpath or if
  * the faces-config.xml file is present. If so, the listener checks if 
  * the FacesServlet has already been defined in web.xml and if not, it adds
@@ -132,6 +132,9 @@ public class MyFacesContainerInitializer implements ServletContainerInitializer
             return;
         }
 
+        // Check for a FacesServlet and store the result so it can be used by the FacesInitializer.
+        boolean isFacesServletPresent = checkForFacesServlet(servletContext);
+
         // Check for one or more of this conditions:
         // 1. A faces-config.xml file is found in WEB-INF
         // 2. A faces-config.xml file is found in the META-INF directory of a jar in the application's classpath.
@@ -142,45 +145,42 @@ public class MyFacesContainerInitializer implements ServletContainerInitializer
         //    implementation is not empty.
         if ((clazzes != null && !clazzes.isEmpty()) || isFacesConfigPresent(servletContext))
         {
-            // look for the FacesServlet
-            Map<String, ? extends ServletRegistration> servlets = servletContext.getServletRegistrations();
-            for (Map.Entry<String, ? extends ServletRegistration> servletEntry : servlets.entrySet())
+            /*
+             * If we get into this code block the application contains some Faces artifacts, either a faces-config.xml
+             * or one ore more classes from @HandlesTypes. However if classes from @HandlesTypes or a faces-config.xml
+             * is available a FacesServlet definition might not be defined.
+             *
+             * If a FacesServet definition was not found then add it dynamically.
+             */
+            if(!isFacesServletPresent)
             {
-                String className = servletEntry.getValue().getClassName();
-                if (FACES_SERVLET_CLASS.getName().equals(className) || isDelegatedFacesServlet(className))
+                // the FacesServlet is not installed yet - install it
+                ServletRegistration.Dynamic servlet =
+                        servletContext.addServlet(FACES_SERVLET_NAME, FACES_SERVLET_CLASS);
+
+                //try to add typical Faces mappings
+                String[] mappings = isAutomaticXhtmlMappingDisabled(servletContext) ?
+                            FACES_SERVLET_MAPPINGS : FACES_SERVLET_FULL_MAPPINGS;
+                Set<String> conflictMappings = servlet.addMapping(mappings);
+                if (conflictMappings != null && !conflictMappings.isEmpty())
                 {
-                    // we found a FacesServlet; set an attribute for use during initialization
-                    servletContext.setAttribute(FACES_SERVLET_FOUND, Boolean.TRUE);                    
-                    return;
+                    //at least one of the attempted mappings is in use, remove and try again
+                    Set<String> newMappings = new HashSet<>(Arrays.asList(mappings));
+                    newMappings.removeAll(conflictMappings);
+                    mappings = newMappings.toArray(new String[newMappings.size()]);
+                    servlet.addMapping(mappings);
                 }
-            }
-
-            // the FacesServlet is not installed yet - install it
-            ServletRegistration.Dynamic servlet = servletContext.addServlet(FACES_SERVLET_NAME, FACES_SERVLET_CLASS);
-
-            //try to add typical Faces mappings
-            String[] mappings = isAutomaticXhtmlMappingDisabled(servletContext) ? 
-                        FACES_SERVLET_MAPPINGS : FACES_SERVLET_FULL_MAPPINGS;
-            Set<String> conflictMappings = servlet.addMapping(mappings);
-            if (conflictMappings != null && !conflictMappings.isEmpty())
-            {
-                //at least one of the attempted mappings is in use, remove and try again
-                Set<String> newMappings = new HashSet<>(Arrays.asList(mappings));
-                newMappings.removeAll(conflictMappings);
-                mappings = newMappings.toArray(new String[newMappings.size()]);
-                servlet.addMapping(mappings);
-            }
 
-            if (mappings != null && mappings.length > 0)
-            {
-                // at least one mapping was added 
-                // now we have to set a field in the ServletContext to indicate that we have
-                // added the mapping dynamically, because MyFaces just parsed the web.xml to
-                // find mappings and thus it would abort initializing
-                servletContext.setAttribute(FACES_SERVLET_ADDED_ATTRIBUTE, Boolean.TRUE);
+                if (mappings != null && mappings.length > 0)
+                {
+                    // at least one mapping was added 
+                    // now we have to set a field in the ServletContext to indicate that we have
+                    // added the mapping dynamically.
+                    servletContext.setAttribute(FACES_SERVLET_ADDED_ATTRIBUTE, Boolean.TRUE);
 
-                // add a log message
-                log.log(Level.INFO, "Added FacesServlet with mappings=" + Arrays.toString(mappings));
+                    // add a log message
+                    log.log(Level.INFO, "Added FacesServlet with mappings=" + Arrays.toString(mappings));
+                }
             }
         }
     }
@@ -304,6 +304,28 @@ public class MyFacesContainerInitializer implements ServletContainerInitializer
         }
     }
 
+    /*
+     * Checks if a FacesServlet has been mapped.
+     */
+    private boolean checkForFacesServlet(ServletContext servletContext)
+    {
+        // look for the FacesServlet
+        Map<String, ? extends ServletRegistration> servlets = servletContext.getServletRegistrations();
+        boolean isFacesServletPresent = false;
+
+        for (Map.Entry<String, ? extends ServletRegistration> servletEntry : servlets.entrySet())
+        {
+            String className = servletEntry.getValue().getClassName();
+            if (FACES_SERVLET_CLASS.getName().equals(className) || isDelegatedFacesServlet(className))
+            {
+                // we found a FacesServlet; set an attribute for use during initialization
+                servletContext.setAttribute(FACES_SERVLET_FOUND, Boolean.TRUE);
+                isFacesServletPresent = true;
+            }
+        }
+        return isFacesServletPresent;
+    }
+
     /**
      * Checks if the class represented by className implements DelegatedFacesServlet.
      * @param className