View Javadoc

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.commons.resourcehandler.resource;
20  
21  import java.util.Map;
22  
23  import javax.faces.context.ExternalContext;
24  import javax.faces.context.FacesContext;
25  
26  import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFWebConfigParam;
27  import org.apache.myfaces.commons.resourcehandler.application.FacesServletMapping;
28  import org.apache.myfaces.commons.util.WebConfigParamUtils;
29  
30  /**
31   * A ResourceHandlerSupport implementation for use with standard Java Servlet engines,
32   * ie an engine that supports javax.servlet, and uses a standard web.xml file.
33   * 
34   * @author Leonardo Uribe (latest modification by $Author: lu4242 $)
35   * @version $Revision: 946779 $ $Date: 2010-05-20 15:31:42 -0500 (Jue, 20 May 2010) $
36   */
37  public class BaseResourceHandlerSupport extends ResourceHandlerSupport
38  {
39  
40      /**
41       * Set the max time in miliseconds set on the "Expires" header for a resource.
42       * (default to one week in miliseconds or 604800000) 
43       */
44      @JSFWebConfigParam(since="2.0", defaultValue="604800000")
45      public static final String RESOURCE_MAX_TIME_EXPIRES = "org.apache.myfaces.RESOURCE_MAX_TIME_EXPIRES";
46  
47      /**
48       * Identifies the FacesServlet mapping in the current request map.
49       */
50      private static final String CACHED_SERVLET_MAPPING =
51          BaseResourceHandlerSupport.class.getName() + ".CACHED_SERVLET_MAPPING";
52      
53      private Long _startupTime;
54      
55      private Long _maxTimeExpires;
56          
57      public BaseResourceHandlerSupport()
58      {
59          _startupTime = System.currentTimeMillis();
60      }
61      
62      public ResourceLoader[] getResourceLoaders()
63      {
64          return null;
65      }
66  
67      public String calculateResourceBasePath(FacesContext facesContext)
68      {        
69          FacesServletMapping mapping = getFacesServletMapping(facesContext);
70          ExternalContext externalContext = facesContext.getExternalContext();      
71          
72          if (mapping != null)
73          {
74              String resourceBasePath = null;
75              if (mapping.isExtensionMapping())
76              {
77                  // Mapping using a suffix. In this case we have to strip 
78                  // the suffix. If we have a url like:
79                  // http://localhost:8080/testjsf20/javax.faces.resource/imagen.jpg.jsf?ln=dojo
80                  // 
81                  // The servlet path is /javax.faces.resource/imagen.jpg.jsf
82                  //
83                  // For obtain the resource name we have to remove the .jsf suffix and 
84                  // the prefix ResourceHandler.RESOURCE_IDENTIFIER
85                  resourceBasePath = externalContext.getRequestServletPath();
86                  int stripPoint = resourceBasePath.lastIndexOf('.');
87                  if (stripPoint > 0)
88                  {
89                      resourceBasePath = resourceBasePath.substring(0, stripPoint);
90                  }
91              }
92              else
93              {
94                  // Mapping using prefix. In this case we have to strip 
95                  // the prefix used for mapping. If we have a url like:
96                  // http://localhost:8080/testjsf20/faces/javax.faces.resource/imagen.jpg?ln=dojo
97                  //
98                  // The servlet path is /faces
99                  // and the path info is /javax.faces.resource/imagen.jpg
100                 //
101                 // For obtain the resource name we have to remove the /faces prefix and 
102                 // then the prefix ResourceHandler.RESOURCE_IDENTIFIER
103                 resourceBasePath = externalContext.getRequestPathInfo();
104             }
105             return resourceBasePath;            
106         }
107         else
108         {
109             //If no mapping is detected, just return the
110             //information follows the servlet path but before
111             //the query string
112             return externalContext.getRequestPathInfo();
113         }
114     }
115 
116     public boolean isExtensionMapping()
117     {
118         FacesServletMapping mapping = getFacesServletMapping(
119                 FacesContext.getCurrentInstance());
120         if (mapping != null)
121         {
122             if (mapping.isExtensionMapping())
123             {
124                 return true;
125             }
126         }
127         return false;
128     }
129     
130     public String getMapping()
131     {
132         FacesServletMapping mapping = getFacesServletMapping(
133                 FacesContext.getCurrentInstance());
134         if (mapping != null)
135         {
136             if (mapping.isExtensionMapping())
137             {
138                 return mapping.getExtension();
139             }
140             else
141             {
142                 return mapping.getPrefix();
143             }
144         }
145         return "";
146     }
147 
148     /**
149      * Read the web.xml file that is in the classpath and parse its internals to
150      * figure out how the FacesServlet is mapped for the current webapp.
151      */
152     protected FacesServletMapping getFacesServletMapping(FacesContext context)
153     {
154         Map<Object, Object> attributes = context.getAttributes();
155 
156         // Has the mapping already been determined during this request?
157         FacesServletMapping mapping = (FacesServletMapping) attributes.get(CACHED_SERVLET_MAPPING);
158         if (mapping == null)
159         {
160             ExternalContext externalContext = context.getExternalContext();
161             mapping = calculateFacesServletMapping(externalContext.getRequestServletPath(),
162                     externalContext.getRequestPathInfo());
163 
164             attributes.put(CACHED_SERVLET_MAPPING, mapping);
165         }
166         return mapping;
167     }
168 
169     /**
170      * Determines the mapping of the FacesServlet in the web.xml configuration
171      * file. However, there is no need to actually parse this configuration file
172      * as runtime information is sufficient.
173      *
174      * @param servletPath The servletPath of the current request
175      * @param pathInfo    The pathInfo of the current request
176      * @return the mapping of the FacesServlet in the web.xml configuration file
177      */
178     protected static FacesServletMapping calculateFacesServletMapping(
179         String servletPath, String pathInfo)
180     {
181         if (pathInfo != null)
182         {
183             // If there is a "extra path", it's definitely no extension mapping.
184             // Now we just have to determine the path which has been specified
185             // in the url-pattern, but that's easy as it's the same as the
186             // current servletPath. It doesn't even matter if "/*" has been used
187             // as in this case the servletPath is just an empty string according
188             // to the Servlet Specification (SRV 4.4).
189             return FacesServletMapping.createPrefixMapping(servletPath);
190         }
191         else
192         {
193             // In the case of extension mapping, no "extra path" is available.
194             // Still it's possible that prefix-based mapping has been used.
195             // Actually, if there was an exact match no "extra path"
196             // is available (e.g. if the url-pattern is "/faces/*"
197             // and the request-uri is "/context/faces").
198             int slashPos = servletPath.lastIndexOf('/');
199             int extensionPos = servletPath.lastIndexOf('.');
200             if (extensionPos > -1 && extensionPos > slashPos)
201             {
202                 String extension = servletPath.substring(extensionPos);
203                 return FacesServletMapping.createExtensionMapping(extension);
204             }
205             else
206             {
207                 // There is no extension in the given servletPath and therefore
208                 // we assume that it's an exact match using prefix-based mapping.
209                 return FacesServletMapping.createPrefixMapping(servletPath);
210             }
211         }
212     }
213 
214     public long getStartupTime()
215     {
216         return _startupTime;
217     }
218     
219     public long getMaxTimeExpires()
220     {
221         if (_maxTimeExpires == null)
222         {
223             _maxTimeExpires = WebConfigParamUtils.getLongInitParameter(
224                     FacesContext.getCurrentInstance().getExternalContext(), 
225                     RESOURCE_MAX_TIME_EXPIRES, 604800000L);
226         }
227         return _maxTimeExpires;
228     }
229 }