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.io.IOException;
22 import java.io.InputStream;
23 import java.io.OutputStream;
24 import java.util.Locale;
25 import java.util.Map;
26 import java.util.MissingResourceException;
27 import java.util.ResourceBundle;
28 import java.util.logging.Level;
29 import java.util.logging.Logger;
30 import java.util.zip.GZIPOutputStream;
31
32 import javax.faces.FacesException;
33 import javax.faces.application.ProjectStage;
34 import javax.faces.application.Resource;
35 import javax.faces.application.ResourceHandler;
36 import javax.faces.application.ResourceHandlerWrapper;
37 import javax.faces.application.ResourceWrapper;
38 import javax.faces.context.ExternalContext;
39 import javax.faces.context.FacesContext;
40 import javax.servlet.http.HttpServletResponse;
41
42 import org.apache.myfaces.commons.resourcehandler.config.element.Library;
43 import org.apache.myfaces.commons.resourcehandler.resource.ResourceHandlerCache;
44 import org.apache.myfaces.commons.resourcehandler.resource.ResourceHandlerCache.ResourceValue;
45 import org.apache.myfaces.commons.resourcehandler.resource.ResourceLoader;
46 import org.apache.myfaces.commons.resourcehandler.resource.ResourceMeta;
47 import org.apache.myfaces.commons.util.ClassUtils;
48 import org.apache.myfaces.commons.util.ExternalContextUtils;
49 import org.apache.myfaces.commons.util.RequestType;
50 import org.apache.myfaces.commons.util.StringUtils;
51
52
53
54
55
56
57 public class ExtendedResourceHandlerImpl extends ResourceHandlerWrapper
58 {
59 private static final String IS_RESOURCE_REQUEST = "org.apache.myfaces.commons.IS_RESOURCE_REQUEST";
60
61 private static final String RESOURCE_LOCALE = "org.apache.myfaces.commons.RESOURCE_LOCALE";
62
63 private ExtendedDefaultResourceHandlerSupport _resourceHandlerSupport;
64
65 private ResourceHandlerCache _resourceHandlerCache;
66
67
68 private static final Logger log = Logger.getLogger(ExtendedResourceHandlerImpl.class.getName());
69
70 private static final int _BUFFER_SIZE = 2048;
71
72 private ResourceHandler _delegate;
73
74
75
76 public ExtendedResourceHandlerImpl(ResourceHandler delegate)
77 {
78 this._delegate = delegate;
79
80 _resourceHandlerSupport = new ExtendedDefaultResourceHandlerSupport();
81 }
82
83
84
85
86
87
88
89
90 @Override
91 public Resource createResource(String resourceName, String libraryName)
92 {
93 if (getResourceHandlerSupport().getMyFacesResourcesConfig().getLibrary(libraryName) != null)
94 {
95 return createResource(resourceName, libraryName, null);
96 }
97 else
98 {
99 return super.createResource(resourceName, libraryName);
100 }
101 }
102
103 @Override
104 public Resource createResource(String resourceName, String libraryName,
105 String contentType)
106 {
107 if (getResourceHandlerSupport().getMyFacesResourcesConfig().getLibrary(libraryName) != null)
108 {
109 return defaultCreateResource(resourceName, libraryName, contentType);
110 }
111 else
112 {
113 return super.createResource(resourceName, libraryName, contentType);
114 }
115 }
116
117 private Resource defaultCreateResource(String resourceName, String expectedLibraryName,
118 String contentType)
119 {
120 Resource resource = null;
121
122 FacesContext facesContext = FacesContext.getCurrentInstance();
123
124 if (contentType == null)
125 {
126
127 contentType = facesContext.getExternalContext().getMimeType(resourceName);
128 }
129
130 String localePrefix = (String) facesContext.getAttributes().get(RESOURCE_LOCALE);
131
132 if (localePrefix == null)
133 {
134 localePrefix = getLocalePrefixForLocateResource();
135 }
136
137
138 String redirectedLibraryName = resolveLibraryName(expectedLibraryName);
139
140
141 if(getResourceLoaderCache().containsResource(resourceName, redirectedLibraryName, contentType, localePrefix))
142 {
143 ResourceValue resourceValue = getResourceLoaderCache().getResource(
144 resourceName, redirectedLibraryName, contentType, localePrefix);
145
146
147
148 resource = new ExtendedResourceImpl((ExtendedResourceMeta) resourceValue.getResourceMeta(), resourceValue.getResourceLoader(),
149 getResourceHandlerSupport(), contentType, localePrefix, redirectedLibraryName.equals(expectedLibraryName) ? null : expectedLibraryName);
150 }
151 else
152 {
153 for (ResourceLoader loader : getResourceHandlerSupport().getResourceLoaders())
154 {
155 ResourceMeta resourceMeta = deriveResourceMeta(loader, resourceName, redirectedLibraryName, localePrefix);
156
157 if (resourceMeta != null)
158 {
159
160 resource = new ExtendedResourceImpl((ExtendedResourceMeta) resourceMeta, loader, getResourceHandlerSupport(), contentType, localePrefix,
161 redirectedLibraryName.equals(expectedLibraryName) ? null : expectedLibraryName);
162
163
164 getResourceLoaderCache().putResource(resourceName, redirectedLibraryName, contentType,
165 localePrefix, resourceMeta, loader);
166 break;
167 }
168 }
169 }
170
171 return resource;
172 }
173
174 public String resolveLibraryName(String libraryName)
175 {
176 String finalLibraryName = libraryName;
177 Library library = null;
178 boolean resolved = false;
179 do
180 {
181 library = getResourceHandlerSupport().getMyFacesResourcesConfig().getLibrary(finalLibraryName);
182 if (library != null)
183 {
184 if (library.getRedirectName() != null && library.getRedirectName().length() > 0)
185 {
186 finalLibraryName = library.getRedirectName();
187 }
188 else
189 {
190
191 resolved = true;
192 }
193 }
194 } while (library != null && !resolved);
195
196 return finalLibraryName;
197 }
198
199
200
201
202
203
204
205 protected ExtendedResourceMeta deriveResourceMeta(ResourceLoader resourceLoader,
206 String resourceName, String libraryName, String localePrefix)
207 {
208 String resourceVersion = null;
209 String libraryVersion = null;
210 ExtendedResourceMeta resourceId = null;
211
212
213 if (localePrefix != null)
214 {
215 if (null != libraryName)
216 {
217 String pathToLib = localePrefix + '/' + libraryName;
218 libraryVersion = resourceLoader.getLibraryVersion(pathToLib);
219
220 if (null != libraryVersion)
221 {
222 String pathToResource = localePrefix + '/'
223 + libraryName + '/' + libraryVersion + '/'
224 + resourceName;
225 resourceVersion = resourceLoader
226 .getResourceVersion(pathToResource);
227 }
228 else
229 {
230 String pathToResource = localePrefix + '/'
231 + libraryName + '/' + resourceName;
232 resourceVersion = resourceLoader
233 .getResourceVersion(pathToResource);
234 }
235
236 if (!(resourceVersion != null && ResourceLoader.VERSION_INVALID.equals(resourceVersion)))
237 {
238 resourceId = (ExtendedResourceMeta) resourceLoader.createResourceMeta(localePrefix, libraryName,
239 libraryVersion, resourceName, resourceVersion);
240 }
241 }
242 else
243 {
244 resourceVersion = resourceLoader
245 .getResourceVersion(localePrefix + '/'+ resourceName);
246 if (!(resourceVersion != null && ResourceLoader.VERSION_INVALID.equals(resourceVersion)))
247 {
248 resourceId = (ExtendedResourceMeta) resourceLoader.createResourceMeta(localePrefix, null, null,
249 resourceName, resourceVersion);
250 }
251 }
252
253 if (resourceId != null)
254 {
255 if (!resourceLoader.resourceExists(resourceId))
256 {
257 resourceId = null;
258 }
259 }
260 }
261
262
263 if (resourceId == null)
264 {
265 if (null != libraryName)
266 {
267 libraryVersion = resourceLoader.getLibraryVersion(libraryName);
268
269 if (null != libraryVersion)
270 {
271 String pathToResource = (libraryName + '/' + libraryVersion
272 + '/' + resourceName);
273 resourceVersion = resourceLoader
274 .getResourceVersion(pathToResource);
275 }
276 else
277 {
278 String pathToResource = (libraryName + '/'
279 + resourceName);
280 resourceVersion = resourceLoader
281 .getResourceVersion(pathToResource);
282 }
283
284 if (!(resourceVersion != null && ResourceLoader.VERSION_INVALID.equals(resourceVersion)))
285 {
286 resourceId = (ExtendedResourceMeta) resourceLoader.createResourceMeta(null, libraryName,
287 libraryVersion, resourceName, resourceVersion);
288 }
289 }
290 else
291 {
292 resourceVersion = resourceLoader
293 .getResourceVersion(resourceName);
294
295 if (!(resourceVersion != null && ResourceLoader.VERSION_INVALID.equals(resourceVersion)))
296 {
297 resourceId = (ExtendedResourceMeta) resourceLoader.createResourceMeta(null, null, null,
298 resourceName, resourceVersion);
299 }
300 }
301
302 if (resourceId != null)
303 {
304 if (!resourceLoader.resourceExists(resourceId))
305 {
306 resourceId = null;
307 }
308 }
309 }
310
311 return resourceId;
312 }
313
314
315
316
317
318
319
320 @Override
321 public void handleResourceRequest(FacesContext facesContext) throws IOException
322 {
323
324
325
326
327
328
329
330
331
332
333
334
335 try
336 {
337 String resourceBasePath = getResourceHandlerSupport()
338 .calculateResourceBasePath(facesContext);
339
340 if (resourceBasePath == null)
341 {
342
343
344
345
346 super.handleResourceRequest(facesContext);
347 return;
348 }
349
350
351
352
353
354
355 if (!RequestType.SERVLET.equals(ExternalContextUtils.getRequestType(facesContext.getExternalContext())))
356 {
357 throw new IllegalStateException("Could not obtain an instance of HttpServletResponse.");
358 }
359 Object response = facesContext.getExternalContext().getResponse();
360 HttpServletResponse httpServletResponse = (HttpServletResponse) response;
361 if (httpServletResponse == null)
362 {
363 throw new IllegalStateException("Could not obtain an instance of HttpServletResponse.");
364 }
365
366 if (isResourceIdentifierExcluded(facesContext, resourceBasePath))
367 {
368 httpServletResponse.setStatus(HttpServletResponse.SC_NOT_FOUND);
369 return;
370 }
371
372 String resourceName = null;
373 String libraryName = null;
374 String requestedLocalePrefix = null;
375 if (resourceBasePath.startsWith(getResourceHandlerSupport().getResourceIdentifier()))
376 {
377
378
379 resourceName = resourceBasePath
380 .substring(getResourceHandlerSupport().getResourceIdentifier().length());
381
382 if (resourceName.startsWith("/$"))
383 {
384
385 int from = 3;
386 int to = resourceName.indexOf('/',3);
387 requestedLocalePrefix = resourceName.substring(from,to);
388 from = to+1;
389 to = resourceName.indexOf('/', from);
390 libraryName = resourceName.substring(from, to);
391 resourceName = resourceName.substring(to+1);
392 }
393 else
394 {
395
396 resourceName = null;
397
398
399
400 }
401 }
402 else
403 {
404
405
406 super.handleResourceRequest(facesContext);
407 return;
408 }
409
410
411 if (resourceName == null)
412 {
413 super.handleResourceRequest(facesContext);
414 return;
415 }
416 else if (libraryName == null)
417 {
418 super.handleResourceRequest(facesContext);
419 return;
420 }
421 else if (libraryName != null && getResourceHandlerSupport().getMyFacesResourcesConfig().getLibrary(libraryName) == null)
422 {
423 super.handleResourceRequest(facesContext);
424 return;
425 }
426
427 if (requestedLocalePrefix != null)
428 {
429 facesContext.getAttributes().put(RESOURCE_LOCALE, requestedLocalePrefix);
430 }
431
432 Resource resource = null;
433
434
435
436 resource = facesContext.getApplication().getResourceHandler().createResource(resourceName, libraryName);
437
438
439
440
441
442
443 if (resource == null)
444 {
445 httpServletResponse.setStatus(HttpServletResponse.SC_NOT_FOUND);
446 return;
447 }
448
449 if (!resource.userAgentNeedsUpdate(facesContext))
450 {
451 httpServletResponse.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
452 return;
453 }
454
455 httpServletResponse.setContentType(_getContentType(resource, facesContext.getExternalContext()));
456
457 Map<String, String> headers = resource.getResponseHeaders();
458
459 for (Map.Entry<String, String> entry : headers.entrySet())
460 {
461 httpServletResponse.setHeader(entry.getKey(), entry.getValue());
462 }
463
464
465 try
466 {
467
468
469
470
471
472 if (!facesContext.isProjectStage(ProjectStage.Development) &&
473 getResourceHandlerSupport().isGzipResourcesEnabled() &&
474 !getResourceHandlerSupport().isCacheDiskGzipResources() &&
475 getResourceHandlerSupport().userAgentSupportsCompression(facesContext) &&
476 getResourceHandlerSupport().isCompressable(resource))
477 {
478 InputStream in = resource.getInputStream();
479 OutputStream out = new GZIPOutputStream(httpServletResponse.getOutputStream(), _BUFFER_SIZE);
480 byte[] buffer = new byte[_BUFFER_SIZE];
481
482 try
483 {
484 int count = pipeBytes(in, out, buffer);
485
486 httpServletResponse.setContentLength(count);
487 }
488 finally
489 {
490 try
491 {
492 in.close();
493 }
494 finally
495 {
496 out.close();
497 }
498 }
499 }
500 else
501 {
502 InputStream in = resource.getInputStream();
503 OutputStream out = httpServletResponse.getOutputStream();
504 byte[] buffer = new byte[_BUFFER_SIZE];
505
506 try
507 {
508 int count = pipeBytes(in, out, buffer);
509
510 httpServletResponse.setContentLength(count);
511 }
512 finally
513 {
514 try
515 {
516 in.close();
517 }
518 finally
519 {
520 out.close();
521 }
522 }
523 }
524 }
525 catch (IOException e)
526 {
527
528 if (log.isLoggable(Level.SEVERE))
529 log.severe("Error trying to load resource " + resourceName
530 + " with library " + libraryName + " :"
531 + e.getMessage());
532 httpServletResponse.setStatus(HttpServletResponse.SC_NOT_FOUND);
533 }
534 }
535 catch (Throwable ex)
536 {
537
538
539
540 throw new FacesException(ex);
541
542 }
543 }
544
545
546
547
548
549 private static int pipeBytes(InputStream in, OutputStream out, byte[] buffer)
550 throws IOException
551 {
552 int count = 0;
553 int length;
554
555 while ((length = (in.read(buffer))) >= 0)
556 {
557 out.write(buffer, 0, length);
558 count += length;
559 }
560 return count;
561 }
562
563 @Override
564 public boolean isResourceRequest(FacesContext facesContext)
565 {
566
567
568
569 Boolean value = (Boolean) facesContext.getAttributes().get(IS_RESOURCE_REQUEST);
570
571 if (value != null && value)
572 {
573
574 return value;
575 }
576 else
577 {
578 String resourceBasePath = getResourceHandlerSupport()
579 .calculateResourceBasePath(facesContext);
580
581 if (resourceBasePath != null
582 && resourceBasePath.startsWith(getResourceHandlerSupport().getResourceIdentifier()))
583 {
584 facesContext.getAttributes().put(IS_RESOURCE_REQUEST, Boolean.TRUE);
585 return true;
586 }
587 else
588 {
589 value = super.isResourceRequest(facesContext);
590 facesContext.getAttributes().put(IS_RESOURCE_REQUEST, value);
591 return value;
592 }
593 }
594 }
595
596 protected String getLocalePrefixForLocateResource()
597 {
598 String localePrefix = null;
599 FacesContext context = FacesContext.getCurrentInstance();
600
601 String bundleName = context.getApplication().getMessageBundle();
602
603 if (null != bundleName)
604 {
605 Locale locale = context.getApplication().getViewHandler()
606 .calculateLocale(context);
607
608 ResourceBundle bundle = ResourceBundle
609 .getBundle(bundleName, locale, ClassUtils.getContextClassLoader());
610
611 if (bundle != null)
612 {
613 try
614 {
615 localePrefix = bundle.getString(ResourceHandler.LOCALE_PREFIX);
616 }
617 catch (MissingResourceException e)
618 {
619
620 }
621 }
622 }
623 return localePrefix;
624 }
625
626 protected boolean isResourceIdentifierExcluded(FacesContext context,
627 String resourceIdentifier)
628 {
629 String value = context.getExternalContext().getInitParameter(
630 RESOURCE_EXCLUDES_PARAM_NAME);
631 if (value == null)
632 {
633 value = RESOURCE_EXCLUDES_DEFAULT_VALUE;
634 }
635
636 String[] extensions = StringUtils.splitShortString(value, ' ');
637 for (int i = 0; i < extensions.length; i++)
638 {
639 if (resourceIdentifier.endsWith(extensions[i]))
640 {
641 return true;
642 }
643 }
644 return false;
645 }
646
647
648
649
650
651
652
653 @Override
654 public boolean libraryExists(String libraryName)
655 {
656 if (getResourceHandlerSupport().getMyFacesResourcesConfig().getLibrary(libraryName) != null)
657 {
658 String localePrefix = getLocalePrefixForLocateResource();
659
660 String pathToLib = null;
661
662 if (localePrefix != null)
663 {
664
665 pathToLib = localePrefix + '/' + libraryName;
666
667 for (ResourceLoader loader : getResourceHandlerSupport()
668 .getResourceLoaders())
669 {
670 if (loader.libraryExists(pathToLib))
671 {
672 return true;
673 }
674 }
675 }
676
677
678 for (ResourceLoader loader : getResourceHandlerSupport()
679 .getResourceLoaders())
680 {
681 if (loader.libraryExists(libraryName))
682 {
683 return true;
684 }
685 }
686 }
687 else
688 {
689 super.libraryExists(libraryName);
690 }
691
692 return false;
693 }
694
695
696
697
698
699 public void setResourceHandlerSupport(
700 ExtendedDefaultResourceHandlerSupport resourceHandlerSupport)
701 {
702 _resourceHandlerSupport = resourceHandlerSupport;
703 }
704
705
706
707
708 protected ExtendedDefaultResourceHandlerSupport getResourceHandlerSupport()
709 {
710 return _resourceHandlerSupport;
711 }
712
713 private ResourceHandlerCache getResourceLoaderCache()
714 {
715 if (_resourceHandlerCache == null)
716 _resourceHandlerCache = new ResourceHandlerCache();
717 return _resourceHandlerCache;
718 }
719
720 private String _getContentType(Resource resource, ExternalContext externalContext)
721 {
722 String contentType = resource.getContentType();
723
724
725 if (contentType == null || contentType.length() == 0)
726 {
727 String resourceName = getWrappedResourceName(resource);
728
729 if (resourceName != null)
730 {
731 contentType = externalContext.getMimeType(resourceName);
732 }
733 }
734
735 return contentType;
736 }
737
738
739
740
741
742
743
744
745 private String getWrappedResourceName(Resource resource)
746 {
747 String resourceName = resource.getResourceName();
748 if (resourceName != null)
749 {
750 return resourceName;
751 }
752
753 if (resource instanceof ResourceWrapper)
754 {
755 return getWrappedResourceName(((ResourceWrapper) resource).getWrapped());
756 }
757
758 return null;
759 }
760
761 @Override
762 public ResourceHandler getWrapped()
763 {
764 return _delegate;
765 }
766 }