1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.myfaces.commons.resourcehandler;
20
21 import java.util.Map;
22
23 import javax.faces.application.ProjectStage;
24 import javax.faces.application.Resource;
25 import javax.faces.application.ResourceHandler;
26 import javax.faces.context.ExternalContext;
27 import javax.faces.context.FacesContext;
28 import javax.faces.webapp.FacesServlet;
29
30 import org.apache.commons.logging.Log;
31 import org.apache.commons.logging.LogFactory;
32 import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFWebConfigParam;
33 import org.apache.myfaces.commons.resourcehandler.application.FacesServletMapping;
34 import org.apache.myfaces.commons.resourcehandler.config.MyFacesResourceHandlerConfigParser;
35 import org.apache.myfaces.commons.resourcehandler.config.element.MyFacesResourcesConfig;
36 import org.apache.myfaces.commons.resourcehandler.resource.BaseResourceHandlerSupport;
37 import org.apache.myfaces.commons.resourcehandler.resource.ClassLoaderResourceLoader;
38 import org.apache.myfaces.commons.resourcehandler.resource.ExternalContextResourceLoader;
39 import org.apache.myfaces.commons.resourcehandler.resource.ResourceLoader;
40 import org.apache.myfaces.commons.resourcehandler.resource.ResourceMeta;
41 import org.apache.myfaces.commons.resourcehandler.webapp.config.WebConfigProvider;
42 import org.apache.myfaces.commons.resourcehandler.webapp.config.WebConfigProviderFactory;
43 import org.apache.myfaces.commons.resourcehandler.webapp.config.WebRegistration;
44 import org.apache.myfaces.commons.resourcehandler.webapp.config.element.ServletRegistration;
45 import org.apache.myfaces.commons.util.ClassUtils;
46 import org.apache.myfaces.commons.util.StringUtils;
47 import org.apache.myfaces.commons.util.WebConfigParamUtils;
48
49 public class ExtendedDefaultResourceHandlerSupport extends BaseResourceHandlerSupport
50 {
51 protected static final String CACHED_SERVLET_MAPPING =
52 ExtendedDefaultResourceHandlerSupport.class.getName() + ".CACHED_SERVLET_MAPPING";
53
54
55
56
57 @JSFWebConfigParam(defaultValue="false")
58 public static final String INIT_PARAM_GZIP_RESOURCES_ENABLED = "org.apache.myfaces.commons.GZIP_RESOURCES_ENABLED";
59
60
61
62
63 @JSFWebConfigParam(defaultValue=".css, .js")
64 public static final String INIT_PARAM_GZIP_RESOURCES_SUFFIX = "org.apache.myfaces.commons.GZIP_RESOURCES_SUFFIX";
65 public static final String INIT_PARAM_GZIP_RESOURCES_EXTENSIONS_DEFAULT = ".css .js";
66
67
68
69
70
71 @JSFWebConfigParam(defaultValue="true")
72 public static final String INIT_PARAM_CACHE_DISK_GZIP_RESOURCES = "org.apache.myfaces.commons.CACHE_DISK_GZIP_RESOURCES";
73
74
75
76
77
78
79 @JSFWebConfigParam(defaultValue="/javax.faces.resource")
80 public static final String INIT_PARAM_EXTENDED_RESOURCE_IDENTIFIER = "org.apache.myfaces.commons.EXTENDED_RESOURCE_IDENTIFIER";
81
82 private static final String INIT_PARAM_DELEGATE_FACES_SERVLET = "org.apache.myfaces.DELEGATE_FACES_SERVLET";
83
84 private static Class DELEGATE_FACES_SERVLET_INTERFACE_CLASS = null;
85
86 static
87 {
88 try
89 {
90 DELEGATE_FACES_SERVLET_INTERFACE_CLASS = ClassUtils.classForName("org.apache.myfaces.shared_impl.webapp.webxml.DelegatedFacesServlet");
91 }
92 catch (ClassNotFoundException e)
93 {
94 }
95 }
96
97
98
99
100 private static final String ACCEPT_ENCODING_HEADER = "Accept-Encoding";
101
102 private ResourceLoader[] _resourceLoaders;
103
104 private final boolean _gzipResourcesEnabled;
105
106 private final String[] _gzipResourcesSuffix;
107
108 private final boolean _cacheDiskGzipResources;
109
110 private final boolean _developmentStage;
111
112 private MyFacesResourcesConfig _config;
113
114 private WebConfigProvider _webConfigProvider;
115
116 private String _resourceIdentifier;
117
118 public ExtendedDefaultResourceHandlerSupport()
119 {
120 super();
121 FacesContext context = FacesContext.getCurrentInstance();
122
123 _gzipResourcesEnabled = WebConfigParamUtils.getBooleanInitParameter(context.getExternalContext(),
124 INIT_PARAM_GZIP_RESOURCES_ENABLED, false);
125 _gzipResourcesSuffix = StringUtils.splitShortString(
126 WebConfigParamUtils.getStringInitParameter(context.getExternalContext(),
127 INIT_PARAM_GZIP_RESOURCES_SUFFIX, INIT_PARAM_GZIP_RESOURCES_EXTENSIONS_DEFAULT), ' ');
128 _cacheDiskGzipResources = WebConfigParamUtils.getBooleanInitParameter(context.getExternalContext(),
129 INIT_PARAM_CACHE_DISK_GZIP_RESOURCES, true);
130 _developmentStage = context.isProjectStage(ProjectStage.Development);
131
132 _resourceIdentifier = WebConfigParamUtils.getStringInitParameter(context.getExternalContext(),
133 INIT_PARAM_EXTENDED_RESOURCE_IDENTIFIER, ResourceHandler.RESOURCE_IDENTIFIER);
134
135
136 MyFacesResourceHandlerConfigParser configParser = new MyFacesResourceHandlerConfigParser();
137 _config = configParser.parse(FacesContext.getCurrentInstance());
138
139 _webConfigProvider = WebConfigProviderFactory.getFacesConfigResourceProviderFactory(context).
140 createWebConfigProvider(context);
141
142 _webConfigProvider.init(context);
143
144
145
146 getResourceLoaders();
147 }
148
149 public MyFacesResourcesConfig getMyFacesResourcesConfig()
150 {
151 return _config;
152 }
153
154 public String[] getGzipResourcesSuffixes()
155 {
156 return _gzipResourcesSuffix;
157 }
158
159 public boolean isGzipResourcesEnabled()
160 {
161 return _gzipResourcesEnabled;
162 }
163
164 public boolean isCacheDiskGzipResources()
165 {
166 return _cacheDiskGzipResources;
167 }
168
169 public boolean isCompressable(ResourceMeta resourceMeta)
170 {
171 if (getGzipResourcesSuffixes() != null)
172 {
173 boolean compressable = false;
174 for (int i = 0; i < getGzipResourcesSuffixes().length; i++)
175 {
176 if (getGzipResourcesSuffixes()[i] != null &&
177 getGzipResourcesSuffixes()[i].length() > 0 &&
178 resourceMeta.getResourceName().endsWith(getGzipResourcesSuffixes()[i]))
179 {
180 compressable = true;
181 break;
182 }
183 }
184 return compressable;
185 }
186 else
187 {
188 return true;
189 }
190 }
191
192 public boolean isCompressable(Resource resource)
193 {
194 if (getGzipResourcesSuffixes() != null)
195 {
196 boolean compressable = false;
197 for (int i = 0; i < getGzipResourcesSuffixes().length; i++)
198 {
199 if (getGzipResourcesSuffixes()[i] != null &&
200 getGzipResourcesSuffixes()[i].length() > 0 &&
201 resource.getResourceName().endsWith(getGzipResourcesSuffixes()[i]))
202 {
203 compressable = true;
204 break;
205 }
206 }
207 return compressable;
208 }
209 else
210 {
211 return true;
212 }
213 }
214
215 public boolean userAgentSupportsCompression(FacesContext facesContext)
216 {
217 String acceptEncodingHeader = facesContext.getExternalContext()
218 .getRequestHeaderMap().get(ACCEPT_ENCODING_HEADER);
219
220 return ResourceUtils.isGZIPEncodingAccepted(acceptEncodingHeader);
221 }
222
223 public String calculateResourceBasePath(FacesContext facesContext)
224 {
225 ExternalContext externalContext = facesContext.getExternalContext();
226 String resourceBasePath = null;
227
228
229 FacesServletMapping mapping = calculateFacesServletMapping(
230 externalContext.getRequestServletPath(),
231 externalContext.getRequestPathInfo());
232
233
234 if (mapping != null)
235 {
236 if (mapping.isExtensionMapping())
237 {
238
239
240
241
242
243
244
245
246 resourceBasePath = externalContext.getRequestServletPath();
247 int stripPoint = resourceBasePath.lastIndexOf('.');
248 if (stripPoint > 0)
249 {
250 resourceBasePath = resourceBasePath.substring(0, stripPoint);
251 }
252 }
253 else
254 {
255
256
257
258
259
260
261
262
263
264 resourceBasePath = externalContext.getRequestPathInfo();
265 }
266 return resourceBasePath;
267 }
268 else
269 {
270
271
272
273 return externalContext.getRequestPathInfo();
274 }
275 }
276
277 protected FacesServletMapping getFacesServletMapping(FacesContext context)
278 {
279 Map<Object, Object> attributes = context.getAttributes();
280
281
282 FacesServletMapping mapping = (FacesServletMapping) attributes.get(CACHED_SERVLET_MAPPING);
283 if (mapping == null)
284 {
285 ExternalContext externalContext = context.getExternalContext();
286
287 FacesServletMapping calculatedMapping = calculateFacesServletMapping(
288 externalContext.getRequestServletPath(),
289 externalContext.getRequestPathInfo());
290
291 if (!calculatedMapping.isPrefixMapping())
292 {
293
294
295 getWebConfigProvider().update(context);
296
297 WebRegistration webRegistration = getWebConfigProvider().getWebRegistration(context);
298
299 String prefix = getFacesServletPrefixMapping(context, webRegistration);
300
301 if (prefix != null)
302 {
303 mapping = FacesServletMapping.createPrefixMapping(prefix);
304 }
305 else
306 {
307 mapping = calculatedMapping;
308 }
309 }
310 else
311 {
312 mapping = calculatedMapping;
313 }
314
315 attributes.put(CACHED_SERVLET_MAPPING, mapping);
316 }
317 return mapping;
318 }
319
320 private String getFacesServletPrefixMapping(FacesContext context, WebRegistration webRegistration)
321 {
322 String prefix = null;
323
324 String delegateFacesServlet = WebConfigParamUtils.getStringInitParameter(context.getExternalContext(),
325 INIT_PARAM_DELEGATE_FACES_SERVLET);
326
327 for (Map.Entry<String, ? extends ServletRegistration> entry : webRegistration.getServletRegistrations().entrySet())
328 {
329 ServletRegistration registration = entry.getValue();
330 boolean facesServlet = false;
331 if (FacesServlet.class.getName().equals(registration.getClassName()))
332 {
333 facesServlet = true;
334 }
335 else if (delegateFacesServlet != null && delegateFacesServlet.equals(registration.getClassName()))
336 {
337 facesServlet = true;
338 }
339 else
340 {
341 if (DELEGATE_FACES_SERVLET_INTERFACE_CLASS != null)
342 {
343 try
344 {
345 Class servletClass = ClassUtils.classForName(registration.getClassName());
346 if (DELEGATE_FACES_SERVLET_INTERFACE_CLASS.isAssignableFrom(servletClass));
347 {
348 facesServlet = true;
349 }
350 }
351 catch (ClassNotFoundException e)
352 {
353 Log log = LogFactory.getLog(ExtendedDefaultResourceHandlerSupport.class);
354 if (log.isTraceEnabled())
355 {
356 log.trace("cannot load servlet class to detect if is a FacesServlet or DelegateFacesServlet", e);
357 }
358 }
359 }
360 }
361 if (facesServlet)
362 {
363 for (String urlPattern : registration.getMappings())
364 {
365 String extension = urlPattern != null && urlPattern.startsWith("*.") ? urlPattern.substring(urlPattern
366 .indexOf('.')) : null;
367 if (extension == null)
368 {
369 int index = urlPattern.indexOf("/*");
370 if (index != -1)
371 {
372 prefix = urlPattern.substring(0, urlPattern.indexOf("/*"));
373 }
374 else
375 {
376 prefix = urlPattern;
377 }
378 }
379 else
380 {
381 prefix = null;
382 }
383
384 if (prefix != null)
385 {
386 return prefix;
387 }
388 }
389 }
390 }
391 return prefix;
392 }
393
394
395
396
397 public ResourceLoader[] getResourceLoaders()
398 {
399 if (_resourceLoaders == null)
400 {
401
402
403
404
405 if (
406 {
407 _resourceLoaders = new ResourceLoader[] {
408 new GZIPResourceLoader(new ExtendedResourceLoaderWrapper(new ExternalContextResourceLoader("/resources")), this),
409 new GZIPResourceLoader(new ExtendedResourceLoaderWrapper(new ClassLoaderResourceLoader("META-INF/resources")), this)
410 };
411 }
412 else
413 {
414 _resourceLoaders = new ResourceLoader[] {
415 new ExtendedResourceLoaderWrapper(new ExternalContextResourceLoader("/resources")),
416 new ExtendedResourceLoaderWrapper(new ClassLoaderResourceLoader("META-INF/resources"))
417 };
418 }
419 }
420 return _resourceLoaders;
421 }
422
423 public WebConfigProvider getWebConfigProvider()
424 {
425 return _webConfigProvider;
426 }
427
428 @Override
429 public String getResourceIdentifier()
430 {
431 return _resourceIdentifier;
432 }
433
434 }