Coverage Report - org.apache.myfaces.application.DefaultViewHandlerSupport
 
Classes in this File Line Coverage Branch Coverage Complexity
DefaultViewHandlerSupport
0%
0/63
0%
0/42
0
DefaultViewHandlerSupport$FacesServletMapping
0%
0/17
0%
0/4
0
 
 1  
 /*
 2  
  * Licensed to the Apache Software Foundation (ASF) under one
 3  
  * or more contributor license agreements.  See the NOTICE file
 4  
  * distributed with this work for additional information
 5  
  * regarding copyright ownership.  The ASF licenses this file
 6  
  * to you under the Apache License, Version 2.0 (the
 7  
  * "License"); you may not use this file except in compliance
 8  
  * with the License.  You may obtain a copy of the License at
 9  
  *
 10  
  *   http://www.apache.org/licenses/LICENSE-2.0
 11  
  *
 12  
  * Unless required by applicable law or agreed to in writing,
 13  
  * software distributed under the License is distributed on an
 14  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 15  
  * KIND, either express or implied.  See the License for the
 16  
  * specific language governing permissions and limitations
 17  
  * under the License.
 18  
  */
 19  
 package org.apache.myfaces.application;
 20  
 
 21  
 import org.apache.commons.logging.Log;
 22  
 import org.apache.commons.logging.LogFactory;
 23  
 
 24  
 import javax.faces.application.ViewHandler;
 25  
 import javax.faces.context.ExternalContext;
 26  
 import javax.faces.context.FacesContext;
 27  
 import java.util.Map;
 28  
 
 29  
 /**
 30  
  * A ViewHandlerSupport implementation for use with standard Java Servlet engines,
 31  
  * ie an engine that supports javax.servlet, and uses a standard web.xml file.
 32  
  *
 33  
  * @author Mathias Broekelmann (latest modification by $Author: skitching $)
 34  
  * @version $Revision: 673811 $ $Date: 2008-07-03 16:18:36 -0500 (Thu, 03 Jul 2008) $
 35  
  */
 36  0
 public class DefaultViewHandlerSupport implements ViewHandlerSupport
 37  
 {
 38  
     /**
 39  
      * Identifies the FacesServlet mapping in the current request map.
 40  
      */
 41  0
     private static final String CACHED_SERVLET_MAPPING =
 42  
         DefaultViewHandlerSupport.class.getName() + ".CACHED_SERVLET_MAPPING";
 43  
 
 44  0
     private static final Log log = LogFactory.getLog(DefaultViewHandlerSupport.class);
 45  
 
 46  
     public String calculateViewId(FacesContext context, String viewId)
 47  
     {
 48  0
         FacesServletMapping mapping = getFacesServletMapping(context);
 49  0
         if (mapping == null || mapping.isExtensionMapping())
 50  
         {
 51  0
             viewId = applyDefaultSuffix(context, viewId);
 52  
         }
 53  0
         else if (mapping != null && viewId != null && mapping.getUrlPattern().startsWith(viewId))
 54  
         {
 55  0
             throw new InvalidViewIdException(viewId);
 56  
         }
 57  0
         return viewId;
 58  
     }
 59  
 
 60  
     public String calculateActionURL(FacesContext context, String viewId)
 61  
     {
 62  0
         if (viewId == null || !viewId.startsWith("/"))
 63  
         {
 64  0
             throw new IllegalArgumentException("ViewId must start with a '/': " + viewId);
 65  
         }
 66  
 
 67  0
         FacesServletMapping mapping = getFacesServletMapping(context);
 68  0
         ExternalContext externalContext = context.getExternalContext();
 69  0
         String contextPath = externalContext.getRequestContextPath();
 70  0
         StringBuilder builder = new StringBuilder(contextPath);
 71  0
         if (mapping != null)
 72  
         {
 73  0
             if (mapping.isExtensionMapping())
 74  
             {
 75  0
                 String contextSuffix = getContextSuffix(context);
 76  0
                 if (viewId.endsWith(contextSuffix))
 77  
                 {
 78  0
                     builder.append(viewId.substring(0, viewId.indexOf(contextSuffix)));
 79  0
                     builder.append(mapping.getExtension());
 80  
                 }
 81  
                 else
 82  
                 {
 83  0
                     builder.append(viewId);
 84  
                 }
 85  0
             }
 86  
             else
 87  
             {
 88  0
                 builder.append(mapping.getPrefix());
 89  0
                 builder.append(viewId);
 90  
             }
 91  
         }
 92  
         else
 93  
         {
 94  0
             builder.append(viewId);
 95  
         }
 96  0
         String calculatedActionURL = builder.toString();
 97  0
         if (log.isTraceEnabled())
 98  
         {
 99  0
             log.trace("Calculated actionURL: '" + calculatedActionURL + "' for viewId: '" + viewId + "'");
 100  
         }
 101  0
         return calculatedActionURL;
 102  
     }
 103  
 
 104  
     /**
 105  
      * Read the web.xml file that is in the classpath and parse its internals to
 106  
      * figure out how the FacesServlet is mapped for the current webapp.
 107  
      */
 108  
     protected FacesServletMapping getFacesServletMapping(FacesContext context)
 109  
     {
 110  0
         Map<String, Object> requestMap = context.getExternalContext().getRequestMap();
 111  
 
 112  
         // Has the mapping already been determined during this request?
 113  0
         if (!requestMap.containsKey(CACHED_SERVLET_MAPPING))
 114  
         {
 115  0
             ExternalContext externalContext = context.getExternalContext();
 116  0
             FacesServletMapping mapping =
 117  
                 calculateFacesServletMapping(
 118  
                     externalContext.getRequestServletPath(),
 119  
                     externalContext.getRequestPathInfo());
 120  
 
 121  0
             requestMap.put(CACHED_SERVLET_MAPPING, mapping);
 122  
         }
 123  
 
 124  0
         return (FacesServletMapping) requestMap.get(CACHED_SERVLET_MAPPING);
 125  
     }
 126  
 
 127  
     /**
 128  
      * Determines the mapping of the FacesServlet in the web.xml configuration
 129  
      * file. However, there is no need to actually parse this configuration file
 130  
      * as runtime information is sufficient.
 131  
      *
 132  
      * @param servletPath The servletPath of the current request
 133  
      * @param pathInfo    The pathInfo of the current request
 134  
      * @return the mapping of the FacesServlet in the web.xml configuration file
 135  
      */
 136  
     protected static FacesServletMapping calculateFacesServletMapping(
 137  
         String servletPath, String pathInfo)
 138  
     {
 139  0
         if (pathInfo != null)
 140  
         {
 141  
             // If there is a "extra path", it's definitely no extension mapping.
 142  
             // Now we just have to determine the path which has been specified
 143  
             // in the url-pattern, but that's easy as it's the same as the
 144  
             // current servletPath. It doesn't even matter if "/*" has been used
 145  
             // as in this case the servletPath is just an empty string according
 146  
             // to the Servlet Specification (SRV 4.4).
 147  0
             return FacesServletMapping.createPrefixMapping(servletPath);
 148  
         }
 149  
         else
 150  
         {
 151  
             // In the case of extension mapping, no "extra path" is available.
 152  
             // Still it's possible that prefix-based mapping has been used.
 153  
             // Actually, if there was an exact match no "extra path"
 154  
             // is available (e.g. if the url-pattern is "/faces/*"
 155  
             // and the request-uri is "/context/faces").
 156  0
             int slashPos = servletPath.lastIndexOf('/');
 157  0
             int extensionPos = servletPath.lastIndexOf('.');
 158  0
             if (extensionPos > -1 && extensionPos > slashPos)
 159  
             {
 160  0
                 String extension = servletPath.substring(extensionPos);
 161  0
                 return FacesServletMapping.createExtensionMapping(extension);
 162  
             }
 163  
             else
 164  
             {
 165  
                 // There is no extension in the given servletPath and therefore
 166  
                 // we assume that it's an exact match using prefix-based mapping.
 167  0
                 return FacesServletMapping.createPrefixMapping(servletPath);
 168  
             }
 169  
         }
 170  
     }
 171  
 
 172  
     protected String getContextSuffix(FacesContext context)
 173  
     {
 174  0
         String defaultSuffix = context.getExternalContext().getInitParameter(ViewHandler.DEFAULT_SUFFIX_PARAM_NAME);
 175  0
         if (defaultSuffix == null)
 176  
         {
 177  0
             defaultSuffix = ViewHandler.DEFAULT_SUFFIX;
 178  
         }
 179  0
         return defaultSuffix;
 180  
     }
 181  
 
 182  
     /**
 183  
      * Return the viewId with any non-standard suffix stripped off and replaced with
 184  
      * the default suffix configured for the specified context.
 185  
      * <p/>
 186  
      * For example, an input parameter of "/foo.jsf" may return "/foo.jsp".
 187  
      */
 188  
     protected String applyDefaultSuffix(FacesContext context, String viewId)
 189  
     {
 190  0
         String defaultSuffix = getContextSuffix(context);
 191  
 
 192  0
         if (viewId == null)
 193  
         {
 194  0
             return null;
 195  
         }
 196  
 
 197  0
         if (!viewId.endsWith(defaultSuffix))
 198  
         {
 199  0
             StringBuilder builder = new StringBuilder(viewId);
 200  0
             int slashPos = viewId.lastIndexOf('/');
 201  0
             int extensionPos = viewId.lastIndexOf('.');
 202  0
             if (extensionPos > -1 && extensionPos > slashPos)
 203  
             {
 204  0
                 builder.replace(extensionPos, viewId.length(), defaultSuffix);
 205  
             }
 206  
             else
 207  
             {
 208  0
                 builder.append(defaultSuffix);
 209  
             }
 210  0
             viewId = builder.toString();
 211  0
             if (log.isTraceEnabled())
 212  
             {
 213  0
                 log.trace("view id after applying the context suffix: " + viewId);
 214  
             }
 215  
         }
 216  0
         return viewId;
 217  
     }
 218  
 
 219  
     /**
 220  
      * Represents a mapping entry of the FacesServlet in the web.xml
 221  
      * configuration file.
 222  
      */
 223  0
     protected static class FacesServletMapping
 224  
     {
 225  
 
 226  
         /**
 227  
          * The path ("/faces", for example) which has been specified in the
 228  
          * url-pattern of the FacesServlet mapping.
 229  
          */
 230  
         private String prefix;
 231  
 
 232  
         /**
 233  
          * The extension (".jsf", for example) which has been specified in the
 234  
          * url-pattern of the FacesServlet mapping.
 235  
          */
 236  
         private String extension;
 237  
 
 238  
         /**
 239  
          * Creates a new FacesServletMapping object using prefix mapping.
 240  
          *
 241  
          * @param path The path ("/faces", for example) which has been specified
 242  
          *             in the url-pattern of the FacesServlet mapping.
 243  
          * @return a newly created FacesServletMapping
 244  
          */
 245  
         public static FacesServletMapping createPrefixMapping(String path)
 246  
         {
 247  0
             FacesServletMapping mapping = new FacesServletMapping();
 248  0
             mapping.setPrefix(path);
 249  0
             return mapping;
 250  
         }
 251  
 
 252  
         /**
 253  
          * Creates a new FacesServletMapping object using extension mapping.
 254  
          *
 255  
          * @param path The extension (".jsf", for example) which has been
 256  
          *             specified in the url-pattern of the FacesServlet mapping.
 257  
          * @return a newly created FacesServletMapping
 258  
          */
 259  
         public static FacesServletMapping createExtensionMapping(
 260  
             String extension)
 261  
         {
 262  0
             FacesServletMapping mapping = new FacesServletMapping();
 263  0
             mapping.setExtension(extension);
 264  0
             return mapping;
 265  
         }
 266  
 
 267  
         /**
 268  
          * Returns the path ("/faces", for example) which has been specified in
 269  
          * the url-pattern of the FacesServlet mapping. If this mapping is based
 270  
          * on an extension, <code>null</code> will be returned. Note that this
 271  
          * path is not the same as the specified url-pattern as the trailing
 272  
          * "/*" is omitted.
 273  
          *
 274  
          * @return the path which has been specified in the url-pattern
 275  
          */
 276  
         public String getPrefix()
 277  
         {
 278  0
             return prefix;
 279  
         }
 280  
 
 281  
         /**
 282  
          * Sets the path ("/faces/", for example) which has been specified in
 283  
          * the url-pattern.
 284  
          *
 285  
          * @param path The path which has been specified in the url-pattern
 286  
          */
 287  
         public void setPrefix(String path)
 288  
         {
 289  0
             this.prefix = path;
 290  0
         }
 291  
 
 292  
         /**
 293  
          * Returns the extension (".jsf", for example) which has been specified
 294  
          * in the url-pattern of the FacesServlet mapping. If this mapping is
 295  
          * not based on an extension, <code>null</code> will be returned.
 296  
          *
 297  
          * @return the extension which has been specified in the url-pattern
 298  
          */
 299  
         public String getExtension()
 300  
         {
 301  0
             return extension;
 302  
         }
 303  
 
 304  
         /**
 305  
          * Sets the extension (".jsf", for example) which has been specified in
 306  
          * the url-pattern of the FacesServlet mapping.
 307  
          *
 308  
          * @param extension The extension which has been specified in the url-pattern
 309  
          */
 310  
         public void setExtension(String extension)
 311  
         {
 312  0
             this.extension = extension;
 313  0
         }
 314  
 
 315  
         /**
 316  
          * Indicates whether this mapping is based on an extension (e.g.
 317  
          * ".jsp").
 318  
          *
 319  
          * @return <code>true</code>, if this mapping is based is on an
 320  
          *         extension, <code>false</code> otherwise
 321  
          */
 322  
         public boolean isExtensionMapping()
 323  
         {
 324  0
             return extension != null;
 325  
         }
 326  
 
 327  
         /**
 328  
          * Returns the url-pattern entry for this servlet mapping.
 329  
          *
 330  
          * @return the url-pattern entry for this servlet mapping
 331  
          */
 332  
         public String getUrlPattern()
 333  
         {
 334  0
             if (isExtensionMapping())
 335  
             {
 336  0
                 return "*" + extension;
 337  
             }
 338  
             else
 339  
             {
 340  0
                 return prefix + "/*";
 341  
             }
 342  
         }
 343  
 
 344  
     }
 345  
 }