You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by ta...@apache.org on 2018/11/29 13:19:25 UTC

[myfaces] branch 2.3.x updated: MYFACES-4270, MYFACES-4269

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

tandraschko pushed a commit to branch 2.3.x
in repository https://gitbox.apache.org/repos/asf/myfaces.git


The following commit(s) were added to refs/heads/2.3.x by this push:
     new cb75b5a  MYFACES-4270, MYFACES-4269
cb75b5a is described below

commit cb75b5a6486c61c6bd3e3befc62cce58576f6be0
Author: Thomas Andraschko <ta...@apache.org>
AuthorDate: Thu Nov 29 14:19:30 2018 +0100

    MYFACES-4270, MYFACES-4269
---
 .../application/DefaultViewHandlerSupport.java     |  24 +-
 .../shared/application/FacesServletMapping.java    |  16 +
 .../application/FacesServletMappingUtils.java      | 344 ++++++++++-----------
 .../resource/BaseResourceHandlerSupport.java       |   5 +-
 4 files changed, 206 insertions(+), 183 deletions(-)

diff --git a/shared/src/main/java/org/apache/myfaces/shared/application/DefaultViewHandlerSupport.java b/shared/src/main/java/org/apache/myfaces/shared/application/DefaultViewHandlerSupport.java
index ba8edab..1aa5427 100644
--- a/shared/src/main/java/org/apache/myfaces/shared/application/DefaultViewHandlerSupport.java
+++ b/shared/src/main/java/org/apache/myfaces/shared/application/DefaultViewHandlerSupport.java
@@ -226,11 +226,11 @@ public class DefaultViewHandlerSupport implements ViewHandlerSupport
         boolean prefixedExactMappingFound = false;
         if (prefixedExactMappingViewId != null && prefixedExactMappingViewId.length() > 0)
         {
-            FacesServletMapping alternateMapping = FacesServletMappingUtils.
-                    calculateFacesServletMappingFromPrefixedExactMappingViewId(context, prefixedExactMappingViewId);
-            if (alternateMapping != null)
+            FacesServletMapping exactMapping = FacesServletMappingUtils.getExactMapping(
+                    context, prefixedExactMappingViewId);
+            if (exactMapping != null)
             {
-                mapping = alternateMapping;
+                mapping = exactMapping;
                 prefixedExactMappingFound = true;
             }
         }
@@ -242,6 +242,19 @@ public class DefaultViewHandlerSupport implements ViewHandlerSupport
         {
             if (mapping != null)
             {
+                if (mapping.isExact())
+                {
+                    // it means that the currentView is a exact mapping
+                    // but the view to resolve is not exact - we must fallback to a prefix or suffix mapping
+                    mapping = FacesServletMappingUtils.getPrefixOrSuffixMapping(context, viewId);
+                    if (mapping == null)
+                    {
+                        throw new IllegalStateException(
+                                "No generic (either prefix or suffix) servlet-mapping found for FacesServlet."
+                                + "This is required serve views, that are not exact mapped.");
+                    }
+                }
+
                 if (mapping.isExtensionMapping())
                 {
                     //See JSF 2.0 section 7.5.2 
@@ -355,7 +368,8 @@ public class DefaultViewHandlerSupport implements ViewHandlerSupport
             ExternalContext externalContext = context.getExternalContext();
             mapping = FacesServletMappingUtils.calculateFacesServletMapping(
                     context, externalContext.getRequestServletPath(),
-                    externalContext.getRequestPathInfo());
+                    externalContext.getRequestPathInfo(),
+                    true);
 
             attributes.put(CACHED_SERVLET_MAPPING, mapping);
         }
diff --git a/shared/src/main/java/org/apache/myfaces/shared/application/FacesServletMapping.java b/shared/src/main/java/org/apache/myfaces/shared/application/FacesServletMapping.java
index bc357b4..a27c9bd 100644
--- a/shared/src/main/java/org/apache/myfaces/shared/application/FacesServletMapping.java
+++ b/shared/src/main/java/org/apache/myfaces/shared/application/FacesServletMapping.java
@@ -36,6 +36,8 @@ public class FacesServletMapping
      * url-pattern of the FacesServlet mapping.
      */
     private String extension;
+    
+    private boolean exact;
 
     /**
      * Creates a new FacesServletMapping object using prefix mapping.
@@ -155,4 +157,18 @@ public class FacesServletMapping
         }
     }
 
+    public boolean isExact()
+    {
+        return exact;
+    }
+
+    public void setExact(boolean exact)
+    {
+        this.exact = exact;
+    }
+
+    public boolean isExactMapping()
+    {
+        return exact;
+    }
 }
\ No newline at end of file
diff --git a/shared/src/main/java/org/apache/myfaces/shared/application/FacesServletMappingUtils.java b/shared/src/main/java/org/apache/myfaces/shared/application/FacesServletMappingUtils.java
index 1572e37..74fa269 100644
--- a/shared/src/main/java/org/apache/myfaces/shared/application/FacesServletMappingUtils.java
+++ b/shared/src/main/java/org/apache/myfaces/shared/application/FacesServletMappingUtils.java
@@ -21,82 +21,94 @@ package org.apache.myfaces.shared.application;
 
 import java.util.Collection;
 import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
 
 import javax.faces.context.ExternalContext;
 import javax.faces.context.FacesContext;
 import javax.faces.webapp.FacesServlet;
 import javax.servlet.ServletContext;
 import javax.servlet.ServletRegistration;
+import org.apache.myfaces.shared.util.ClassUtils;
 import org.apache.myfaces.shared.util.ExternalContextUtils;
 import org.apache.myfaces.shared.webapp.webxml.DelegatedFacesServlet;
 import org.apache.myfaces.shared.webapp.webxml.WebXml;
 
-/**
- *
- */
 public class FacesServletMappingUtils
 {
-    // Key used to store a map of servlet class names with boolean values that indicate whether the
-    // the servlet is a FacesServlet.
-    private static final String IS_FACES_SERVLET_CLASS_NAME_MAP = "org.apache.myfaces.IS_FACES_SERVLET_CLASS_NAME_MAP";
-
-    public static FacesServletMapping calculateGenericFacesServletMapping(
-        FacesContext facesContext, String servletPath, String pathInfo)
+    private static final String FACES_SERVLET_REGISTRATION = "org.apache.myfaces.FACES_SERVLET_REGISTRATION";
+    private static final String FACES_SERVLET_MAPPINGS = "org.apache.myfaces.FACES_SERVLET_MAPPINGS";
+    
+    public static ServletRegistration getFacesServletRegistration(FacesContext facesContext,
+            ServletContext servletContext)
     {
-        if (ExternalContextUtils.isPortlet(facesContext.getExternalContext()))
-        {
-            return calculateFacesServletMapping(servletPath, pathInfo);
-        }
-        else
+        Map<String, Object> applicationMap = facesContext.getExternalContext().getApplicationMap();
+        
+        ServletRegistration servletRegistration = (ServletRegistration) applicationMap.get(FACES_SERVLET_REGISTRATION);
+        if (servletRegistration == null)
         {
-            Object context = facesContext.getExternalContext().getContext();
-            if (context instanceof ServletContext)
+            Map<String, ? extends ServletRegistration> registrations = servletContext.getServletRegistrations();
+            if (registrations != null)
             {
-                if (pathInfo != null)
+                for (Map.Entry<String, ? extends ServletRegistration> entry : registrations.entrySet())
                 {
-                    // If there is a "extra path", it's definitely no extension mapping.
-                    // Now we just have to determine the path which has been specified
-                    // in the url-pattern, but that's easy as it's the same as the
-                    // current servletPath. It doesn't even matter if "/*" has been used
-                    // as in this case the servletPath is just an empty string according
-                    // to the Servlet Specification (SRV 4.4).
-                    return createMappingFromServletRegistration(facesContext, 
-                            (ServletContext)context, servletPath, pathInfo, false);
-                }
-                else
-                {
-                    // In the case of extension mapping, no "extra path" is available.
-                    // Still it's possible that prefix-based mapping has been used.
-                    // Actually, if there was an exact match no "extra path"
-                    // is available (e.g. if the url-pattern is "/faces/*"
-                    // and the request-uri is "/context/faces").
-                    int slashPos = servletPath.lastIndexOf('/');
-                    int extensionPos = servletPath.lastIndexOf('.');
-                    if (extensionPos > -1 && extensionPos > slashPos)
-                    {
-                        String extension = servletPath.substring(extensionPos);
-                        return FacesServletMapping.createExtensionMapping(extension);
-                    }
-                    else
+                    if (isFacesServlet(facesContext, entry.getValue().getClassName()))
                     {
-                        // There is no extension in the given servletPath and therefore
-                        // we assume that it's an exact match using prefix-based mapping.
-                        return createMappingFromServletRegistration(facesContext, 
-                                (ServletContext)context, servletPath, pathInfo, false);
+                        servletRegistration = entry.getValue();
+                        break;
                     }
                 }
             }
-            else
+            
+            applicationMap.put(FACES_SERVLET_REGISTRATION, servletRegistration);
+        }
+
+        return servletRegistration;
+    }
+    
+    public static String[] getFacesServletMappings(FacesContext facesContext,ServletContext servletContext)
+    {
+        Map<String, Object> applicationMap = facesContext.getExternalContext().getApplicationMap();
+        
+        String[] mappings = (String[]) applicationMap.get(FACES_SERVLET_MAPPINGS);
+        if (mappings == null)
+        {
+            ServletRegistration servletRegistration = getFacesServletRegistration(facesContext, servletContext);
+            if (servletRegistration != null)
             {
-                return calculateFacesServletMapping(servletPath, pathInfo);
+                Collection<String> mappingsCollection = servletRegistration.getMappings();
+                mappings = mappingsCollection.toArray(new String[mappingsCollection.size()]);
+            }
+            
+            if (mappings == null)
+            {
+                mappings = new String[]{ };
             }
+
+            applicationMap.put(FACES_SERVLET_MAPPINGS, mappings);
         }
-        //return null;
+        
+        return mappings;
     }
     
+    public static boolean isFacesServlet(FacesContext facesContext, String servletClassName)
+    {
+        Class servletClass = ClassUtils.simpleClassForName(servletClassName, false);
+        if (servletClass != null)
+        {
+            ExternalContext externalContext = facesContext.getExternalContext();
+            
+            return FacesServlet.class.isAssignableFrom(servletClass)
+                    || DelegatedFacesServlet.class.isAssignableFrom(servletClass)
+                    || servletClass.getName().equals(WebXml.getWebXml(externalContext).getDelegateFacesServlet());
+        }
+        return false;
+    }
+    
+    
+    
+    
+
     public static FacesServletMapping calculateFacesServletMapping(
-        FacesContext facesContext, String servletPath, String pathInfo)
+        FacesContext facesContext, String servletPath, String pathInfo, boolean allowExactMapping)
     {
         if (ExternalContextUtils.isPortlet(facesContext.getExternalContext()))
         {
@@ -116,7 +128,7 @@ public class FacesServletMappingUtils
                     // as in this case the servletPath is just an empty string according
                     // to the Servlet Specification (SRV 4.4).
                     return createMappingFromServletRegistration(facesContext, 
-                            (ServletContext)context, servletPath, pathInfo, true);
+                            (ServletContext)context, servletPath, pathInfo, allowExactMapping);
                 }
                 else
                 {
@@ -125,11 +137,9 @@ public class FacesServletMappingUtils
                     // Actually, if there was an exact match no "extra path"
                     // is available (e.g. if the url-pattern is "/faces/*"
                     // and the request-uri is "/context/faces").
-                    int slashPos = servletPath.lastIndexOf('/');
-                    int extensionPos = servletPath.lastIndexOf('.');
-                    if (extensionPos > -1 && extensionPos > slashPos)
+                    String extension = extractExtensionFromUrl(servletPath);
+                    if (extension != null)
                     {
-                        String extension = servletPath.substring(extensionPos);
                         return FacesServletMapping.createExtensionMapping(extension);
                     }
                     else
@@ -137,7 +147,7 @@ public class FacesServletMappingUtils
                         // There is no extension in the given servletPath and therefore
                         // we assume that it's an exact match using prefix-based mapping.
                         return createMappingFromServletRegistration(facesContext, 
-                                (ServletContext)context, servletPath, pathInfo, true);
+                                (ServletContext)context, servletPath, pathInfo, allowExactMapping);
                     }
                 }
             }
@@ -154,64 +164,40 @@ public class FacesServletMappingUtils
     {
         try
         {
-            Map<String, ? extends ServletRegistration> map = servletContext.getServletRegistrations();
-            if (map != null)
+            ServletRegistration facesServletRegistration = getFacesServletRegistration(
+                    facesContext, servletContext);
+            if (facesServletRegistration != null)
             {
                 FacesServletMapping facesExtensionMapping = null;
                 FacesServletMapping facesPrefixMapping = null;
                 FacesServletMapping facesExactMapping = null;
-                
-                for (Map.Entry<String, ? extends ServletRegistration> entry : map.entrySet())
+
+                try
                 {
-                    try
+                    String[] mappings = getFacesServletMappings(facesContext, servletContext);
+                    for (String mapping : mappings)
                     {
-                        Collection<String> mappings = entry.getValue().getMappings();
-                        
-                        if (isFacesServlet(facesContext, (String)entry.getValue().getClassName()))
+                        if (isExtensionMapping(mapping))
                         {
-                            for (String mapping : mappings)
-                            {
-                                if (mapping.startsWith("*."))
-                                {
-                                    // extension mapping, use it.
-                                    facesExtensionMapping = FacesServletMapping.createExtensionMapping(
-                                            mapping.substring(1));
-                                }
-                                else if (mapping.startsWith("/") && mapping.endsWith("/*"))
-                                {
-                                    // prefix mapping, use it.
-                                    facesPrefixMapping = FacesServletMapping.createPrefixMapping(
-                                            mapping.substring(0, mapping.length()-2));
-                                }
-                                else if (allowExactMatch && mapping.startsWith("/") && mapping.equals(servletPath))
-                                {
-                                    facesExactMapping = FacesServletMapping.createPrefixMapping(servletPath);
-                                }
-                            }                            
+                            facesExtensionMapping = FacesServletMapping.createExtensionMapping(
+                                    extractExtension(mapping));
                         }
-                        else
+                        else if (isPrefixMapping(mapping))
                         {
-                            //This is not a FacesServlet mapping.  It could be a non-faces request
-                            //Need to look for exact mapping to servletPath
-                            String servletPrefixMapping = null;
-                            for (String mapping : mappings)
-                            {                                
-                                if (mapping.startsWith("/") && mapping.endsWith("/*"))
-                                {
-                                    mapping = mapping.substring(0, mapping.length()-2);
-                                }                                
-                                if (mapping.equals(servletPath))
-                                {
-                                    return FacesServletMapping.createPrefixMapping(mapping);
-                                }
-                            }
-                       }
-                    }
-                    catch (Exception ex)
-                    {
-                        //No op
+                            facesPrefixMapping = FacesServletMapping.createPrefixMapping(
+                                    extractPrefix(mapping));
+                        }
+                        else if (allowExactMatch && mapping.startsWith("/") && mapping.equals(servletPath))
+                        {
+                            facesExactMapping = FacesServletMapping.createPrefixMapping(servletPath);
+                            facesExactMapping.setExact(true);
+                        }
                     }
                 }
+                catch (Exception ex)
+                {
+                    //No op
+                }
 
                 // Choose exact mapping if preferred.
                 if (allowExactMatch && facesExactMapping != null)
@@ -241,49 +227,7 @@ public class FacesServletMappingUtils
             return FacesServletMapping.createPrefixMapping(servletPath);
         }
     }
-    
-    public static boolean isFacesServlet(FacesContext facesContext, String servletClassName)
-    {
-        ExternalContext eContext = facesContext.getExternalContext();
-
-        // Map used for caching purposes
-        Map<String, Boolean> servletClassNameMap = (Map<String, Boolean>) 
-                                eContext.getApplicationMap().get(IS_FACES_SERVLET_CLASS_NAME_MAP);
-
-        if (servletClassNameMap == null)
-        {
-            // Create the map if it has not been created yet
-            servletClassNameMap = new ConcurrentHashMap<String, Boolean>();
-            eContext.getApplicationMap().put(IS_FACES_SERVLET_CLASS_NAME_MAP, servletClassNameMap);
-        }
-
-        Boolean isFacesServlet = servletClassNameMap.get(servletClassName);
-
-        // if isFacesServlet is null, that means that we haven't cached the servletClassName boolean value
-        if (isFacesServlet == null)
-        {
-            Class servletClass = org.apache.myfaces.shared.util.ClassUtils.simpleClassForName(
-                    servletClassName, false);
 
-            if (servletClass != null)
-            {
-                isFacesServlet = (FacesServlet.class.isAssignableFrom(servletClass) ||
-                                DelegatedFacesServlet.class.isAssignableFrom(servletClass) ||
-                                servletClass.getName().equals(
-                                WebXml.getWebXml(eContext).getDelegateFacesServlet())) ? Boolean.TRUE : Boolean.FALSE;
-
-                servletClassNameMap.put(servletClassName, isFacesServlet);
-            }
-            else
-            {
-                isFacesServlet = Boolean.FALSE;
-                servletClassNameMap.put(servletClassName, isFacesServlet);
-            }
-        }
-
-        return isFacesServlet;
-    }
-    
     /**
      * Determines the mapping of the FacesServlet in the web.xml configuration
      * file. However, there is no need to actually parse this configuration file
@@ -293,8 +237,7 @@ public class FacesServletMappingUtils
      * @param pathInfo    The pathInfo of the current request
      * @return the mapping of the FacesServlet in the web.xml configuration file
      */
-    private static FacesServletMapping calculateFacesServletMapping(
-        String servletPath, String pathInfo)
+    private static FacesServletMapping calculateFacesServletMapping(String servletPath, String pathInfo)
     {
         if (pathInfo != null)
         {
@@ -313,59 +256,108 @@ public class FacesServletMappingUtils
             // Actually, if there was an exact match no "extra path"
             // is available (e.g. if the url-pattern is "/faces/*"
             // and the request-uri is "/context/faces").
-            int slashPos = servletPath.lastIndexOf('/');
-            int extensionPos = servletPath.lastIndexOf('.');
-            if (extensionPos > -1 && extensionPos > slashPos)
+            String extension = extractExtensionFromUrl(servletPath);
+            if (extension != null)
             {
-                String extension = servletPath.substring(extensionPos);
                 return FacesServletMapping.createExtensionMapping(extension);
             }
             else
             {
                 // There is no extension in the given servletPath and therefore
                 // we assume that it's an exact match using prefix-based mapping.
-                return FacesServletMapping.createPrefixMapping(servletPath);
+                FacesServletMapping mapping = FacesServletMapping.createPrefixMapping(servletPath);
+                mapping.setExact(true);
+                return mapping;
             }
         }
     }
     
-    public static FacesServletMapping calculateFacesServletMappingFromPrefixedExactMappingViewId(
-        FacesContext facesContext, String prefixedExactMappingViewId)
+    public static FacesServletMapping getExactMapping(FacesContext facesContext, String prefixedExactMappingViewId)
     {
-        FacesServletMapping mapping = null;
         if (!ExternalContextUtils.isPortlet(facesContext.getExternalContext()))
         {
             Object context = facesContext.getExternalContext().getContext();
             if (context instanceof ServletContext)
             {
-                Map<String, ? extends ServletRegistration> map = ((ServletContext)context).getServletRegistrations();
-                if (map != null)
+                String[] mappings = getFacesServletMappings(facesContext, (ServletContext) context);
+                for (String mapping : mappings)
                 {
-                    for (Map.Entry<String, ? extends ServletRegistration> entry : map.entrySet())
+                    if (!mapping.contains("*") && prefixedExactMappingViewId.equals(mapping))
                     {
-                        try
-                        {
-                            if (isFacesServlet(facesContext, (String)entry.getValue().getClassName()))
-                            {
-                                Collection<String> mappings = entry.getValue().getMappings();
-                                for (String m : mappings)
-                                {
-                                    if ((!m.contains("*")) && prefixedExactMappingViewId.equals(m))
-                                    {
-                                        mapping = FacesServletMapping.createPrefixMapping(prefixedExactMappingViewId);
-                                        break;
-                                    }
-                                }
-                            }
-                        }
-                        catch (Exception ex)
+                        FacesServletMapping facesServletMapping =
+                                FacesServletMapping.createPrefixMapping(prefixedExactMappingViewId);
+                        facesServletMapping.setExact(true);
+                        return facesServletMapping;
+                    }
+                }
+            }
+        }
+
+        return null;
+    }
+    
+    
+    public static FacesServletMapping getPrefixOrSuffixMapping(FacesContext facesContext, String viewId)
+    {
+        if (!ExternalContextUtils.isPortlet(facesContext.getExternalContext()))
+        {
+            Object context = facesContext.getExternalContext().getContext();
+            if (context instanceof ServletContext)
+            {
+                String[] mappings = getFacesServletMappings(facesContext, (ServletContext) context);
+                for (String mapping : mappings)
+                {
+                    if (isExtensionMapping(mapping))
+                    {
+                        String extension = extractExtension(mapping);
+                        if (viewId.endsWith(extension))
                         {
-                            //No op
+                            return FacesServletMapping.createExtensionMapping(extension);
                         }
                     }
+                    else if (isPrefixMapping(mapping))
+                    {
+                        String prefix = extractPrefix(mapping);
+                        return FacesServletMapping.createPrefixMapping(prefix);
+                    }
                 }
             }
         }
-        return mapping;
+        
+        return null;
+    }
+    
+    
+    
+    private static String extractExtensionFromUrl(String url)
+    {
+        int slashPos = url.lastIndexOf('/');
+        int extensionPos = url.lastIndexOf('.');
+        if (extensionPos > -1 && extensionPos > slashPos)
+        {
+            return url.substring(extensionPos);
+        }
+        
+        return null;
+    }
+    
+    private static boolean isExtensionMapping(String mapping)
+    {
+        return mapping.startsWith("*.");
+    }
+    
+    private static String extractExtension(String mapping)
+    {
+        return mapping.substring(1);
+    }
+    
+    private static boolean isPrefixMapping(String mapping)
+    {
+        return mapping.startsWith("/") && mapping.endsWith("/*");
+    }
+    
+    private static String extractPrefix(String mapping)
+    {
+        return mapping.substring(0, mapping.length() - 2);
     }
 }
diff --git a/shared/src/main/java/org/apache/myfaces/shared/resource/BaseResourceHandlerSupport.java b/shared/src/main/java/org/apache/myfaces/shared/resource/BaseResourceHandlerSupport.java
index 4e6b395..24121d0 100644
--- a/shared/src/main/java/org/apache/myfaces/shared/resource/BaseResourceHandlerSupport.java
+++ b/shared/src/main/java/org/apache/myfaces/shared/resource/BaseResourceHandlerSupport.java
@@ -171,9 +171,10 @@ public class BaseResourceHandlerSupport extends ResourceHandlerSupport
         if (mapping == null)
         {
             ExternalContext externalContext = context.getExternalContext();
-            mapping = FacesServletMappingUtils.calculateGenericFacesServletMapping(
+            mapping = FacesServletMappingUtils.calculateFacesServletMapping(
                     context, externalContext.getRequestServletPath(),
-                    externalContext.getRequestPathInfo());
+                    externalContext.getRequestPathInfo(),
+                    false);
 
             attributes.put(CACHED_SERVLET_MAPPING, mapping);
         }