1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.myfaces.application;
20
21 import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFWebConfigParam;
22 import org.apache.myfaces.shared.resource.ResourceHandlerCache;
23 import org.apache.myfaces.shared.resource.ResourceHandlerCache.ResourceValue;
24 import org.apache.myfaces.shared.resource.ResourceHandlerSupport;
25 import org.apache.myfaces.shared.resource.ResourceImpl;
26 import org.apache.myfaces.shared.resource.ResourceLoader;
27 import org.apache.myfaces.shared.resource.ResourceMeta;
28 import org.apache.myfaces.shared.resource.ResourceValidationUtils;
29 import org.apache.myfaces.shared.util.ClassUtils;
30 import org.apache.myfaces.shared.util.ExternalContextUtils;
31 import org.apache.myfaces.shared.util.StringUtils;
32 import org.apache.myfaces.shared.util.WebConfigParamUtils;
33
34 import javax.faces.application.Resource;
35 import javax.faces.application.ResourceHandler;
36 import javax.faces.application.ResourceWrapper;
37 import javax.faces.context.ExternalContext;
38 import javax.faces.context.FacesContext;
39 import javax.servlet.http.HttpServletResponse;
40 import java.io.IOException;
41 import java.io.InputStream;
42 import java.io.OutputStream;
43 import java.util.HashMap;
44 import java.util.HashSet;
45 import java.util.Iterator;
46 import java.util.List;
47 import java.util.Locale;
48 import java.util.Map;
49 import java.util.MissingResourceException;
50 import java.util.ResourceBundle;
51 import java.util.Set;
52 import java.util.Spliterator;
53 import java.util.Spliterators;
54 import java.util.StringTokenizer;
55 import java.util.logging.Level;
56 import java.util.logging.Logger;
57 import java.util.regex.Pattern;
58 import java.util.stream.Stream;
59 import java.util.stream.StreamSupport;
60 import javax.faces.application.ResourceVisitOption;
61 import javax.faces.application.ViewHandler;
62 import javax.faces.view.ViewDeclarationLanguage;
63 import org.apache.myfaces.shared.renderkit.html.util.SharedStringBuilder;
64 import org.apache.myfaces.shared.resource.ContractResource;
65 import org.apache.myfaces.shared.resource.ContractResourceLoader;
66 import org.apache.myfaces.shared.resource.ResourceCachedInfo;
67 import org.apache.myfaces.util.SkipMatchIterator;
68
69
70
71
72
73
74
75
76 public class ResourceHandlerImpl extends ResourceHandler
77 {
78
79 private static final String IS_RESOURCE_REQUEST = "org.apache.myfaces.IS_RESOURCE_REQUEST";
80
81 private ResourceHandlerSupport _resourceHandlerSupport;
82
83 private ResourceHandlerCache _resourceHandlerCache;
84
85 private static final Logger log = Logger.getLogger(ResourceHandlerImpl.class.getName());
86
87
88
89
90 @JSFWebConfigParam(since="2.1.6, 2.0.12", defaultValue="false",
91 expectedValues="true, false", group="resources")
92 public static final String INIT_PARAM_STRICT_JSF_2_ALLOW_SLASH_LIBRARY_NAME =
93 "org.apache.myfaces.STRICT_JSF_2_ALLOW_SLASH_LIBRARY_NAME";
94 public static final boolean INIT_PARAM_STRICT_JSF_2_ALLOW_SLASH_LIBRARY_NAME_DEFAULT = false;
95
96
97
98
99
100
101 @JSFWebConfigParam(since="2.1.10, 2.0.16", defaultValue="2048", group="resources")
102 public static final String INIT_PARAM_RESOURCE_BUFFER_SIZE = "org.apache.myfaces.RESOURCE_BUFFER_SIZE";
103 public static final int INIT_PARAM_RESOURCE_BUFFER_SIZE_DEFAULT = 2048;
104
105 public static final Pattern LIBRARY_VERSION_CHECKER = Pattern.compile("\\p{Digit}+(_\\p{Digit}*)*");
106 public static final Pattern RESOURCE_VERSION_CHECKER = Pattern.compile("\\p{Digit}+(_\\p{Digit}*)*\\..*");
107
108 private Boolean _allowSlashLibraryName;
109 private int _resourceBufferSize = -1;
110
111 private String[] _excludedResourceExtensions;
112
113 private static final String[] FACELETS_VIEW_MAPPINGS_PARAM = {ViewHandler.FACELETS_VIEW_MAPPINGS_PARAM_NAME,
114 "facelets.VIEW_MAPPINGS"};
115 private Set<String> _viewSuffixes = null;
116
117 private final static String MYFACES_JS_RESOURCE_NAME = "oamSubmit.js";
118 public final static String RENDERED_RESOURCES_SET = "org.apache.myfaces.RENDERED_RESOURCES_SET";
119 private final static String MYFACES_LIBRARY_NAME = "org.apache.myfaces";
120
121 private static final String SHARED_STRING_BUILDER = ResourceHandlerImpl.class.getName() + ".SHARED_STRING_BUILDER";
122
123 @Override
124 public Resource createResource(String resourceName)
125 {
126 return createResource(resourceName, null);
127 }
128
129 @Override
130 public Resource createResource(String resourceName, String libraryName)
131 {
132 return createResource(resourceName, libraryName, null);
133 }
134
135 @Override
136 public Resource createResource(String resourceName, String libraryName,
137 String contentType)
138 {
139 Resource resource = null;
140
141 if (resourceName == null)
142 {
143 throw new NullPointerException();
144 }
145
146 if (resourceName.length() == 0)
147 {
148 return null;
149 }
150
151 if (resourceName.charAt(0) == '/')
152 {
153
154
155
156 resourceName = resourceName.substring(1);
157 }
158 if (!ResourceValidationUtils.isValidResourceName(resourceName))
159 {
160 return null;
161 }
162 if (libraryName != null && !ResourceValidationUtils.isValidLibraryName(
163 libraryName, isAllowSlashesLibraryName()))
164 {
165 return null;
166 }
167 FacesContext facesContext = FacesContext.getCurrentInstance();
168 if (contentType == null)
169 {
170
171 contentType = facesContext.getExternalContext().getMimeType(resourceName);
172 }
173
174 final String localePrefix = getLocalePrefixForLocateResource(facesContext);
175 final List<String> contracts = facesContext.getResourceLibraryContracts();
176 String contractPreferred = getContractNameForLocateResource(facesContext);
177 ResourceValue resourceValue = null;
178
179
180
181
182
183
184
185
186
187
188
189
190 if (contractPreferred != null)
191 {
192 resourceValue = getResourceLoaderCache().getResource(
193 resourceName, libraryName, contentType, localePrefix, contractPreferred);
194 }
195 if (resourceValue == null && !contracts.isEmpty())
196 {
197
198 for (String contract : contracts)
199 {
200 resourceValue = getResourceLoaderCache().getResource(
201 resourceName, libraryName, contentType, localePrefix, contract);
202 if (resourceValue != null)
203 {
204 break;
205 }
206 }
207 }
208
209 if (resourceValue == null)
210 {
211
212 resourceValue = getResourceLoaderCache().getResource(resourceName, libraryName, contentType, localePrefix);
213 }
214
215 if(resourceValue != null)
216 {
217 resource = new ResourceImpl(resourceValue.getResourceMeta(), resourceValue.getResourceLoader(),
218 getResourceHandlerSupport(), contentType,
219 resourceValue.getCachedInfo() != null ? resourceValue.getCachedInfo().getURL() : null,
220 resourceValue.getCachedInfo() != null ? resourceValue.getCachedInfo().getRequestPath() : null);
221 }
222 else
223 {
224 boolean resolved = false;
225
226 if (contractPreferred != null)
227 {
228 for (ContractResourceLoader loader : getResourceHandlerSupport().getContractResourceLoaders())
229 {
230 ResourceMeta resourceMeta = deriveResourceMeta(loader, resourceName, libraryName,
231 localePrefix, contractPreferred);
232 if (resourceMeta != null)
233 {
234 resource = new ResourceImpl(resourceMeta, loader,
235 getResourceHandlerSupport(), contentType);
236
237
238 getResourceLoaderCache().putResource(resourceName, libraryName, contentType,
239 localePrefix, contractPreferred, resourceMeta, loader,
240 new ResourceCachedInfo(resource.getURL(), resource.getRequestPath()));
241 resolved = true;
242 break;
243 }
244 }
245 }
246 if (!resolved && !contracts.isEmpty())
247 {
248 for (ContractResourceLoader loader :
249 getResourceHandlerSupport().getContractResourceLoaders())
250 {
251 for (String contract : contracts)
252 {
253 ResourceMeta resourceMeta = deriveResourceMeta(
254 loader, resourceName, libraryName,
255 localePrefix, contract);
256 if (resourceMeta != null)
257 {
258 resource = new ResourceImpl(resourceMeta, loader,
259 getResourceHandlerSupport(), contentType);
260
261
262 getResourceLoaderCache().putResource(
263 resourceName, libraryName, contentType,
264 localePrefix, contract, resourceMeta, loader,
265 new ResourceCachedInfo(resource.getURL(), resource.getRequestPath()));
266 resolved = true;
267 break;
268 }
269 }
270 }
271 }
272 if (!resolved)
273 {
274 for (ResourceLoader loader : getResourceHandlerSupport().getResourceLoaders())
275 {
276 ResourceMeta resourceMeta = deriveResourceMeta(
277 loader, resourceName, libraryName, localePrefix);
278
279 if (resourceMeta != null)
280 {
281 resource = new ResourceImpl(
282 resourceMeta, loader, getResourceHandlerSupport(), contentType);
283
284
285 getResourceLoaderCache().putResource(resourceName, libraryName, contentType,
286 localePrefix, null, resourceMeta, loader,
287 new ResourceCachedInfo(resource.getURL(), resource.getRequestPath()));
288 break;
289 }
290 }
291 }
292 }
293 return resource;
294 }
295
296 protected ResourceMeta deriveResourceMeta(ContractResourceLoader resourceLoader,
297 String resourceName, String libraryName, String localePrefix, String contractName)
298 {
299 String resourceVersion = null;
300 String libraryVersion = null;
301 ResourceMeta resourceId = null;
302
303
304 if (localePrefix != null)
305 {
306 if (null != libraryName)
307 {
308 String pathToLib = localePrefix + '/' + libraryName;
309 libraryVersion = resourceLoader.getLibraryVersion(pathToLib, contractName);
310
311 if (null != libraryVersion)
312 {
313 String pathToResource = localePrefix + '/'
314 + libraryName + '/' + libraryVersion + '/'
315 + resourceName;
316 resourceVersion = resourceLoader
317 .getResourceVersion(pathToResource, contractName);
318 }
319 else
320 {
321 String pathToResource = localePrefix + '/'
322 + libraryName + '/' + resourceName;
323 resourceVersion = resourceLoader
324 .getResourceVersion(pathToResource, contractName);
325 }
326
327 if (!(resourceVersion != null && ResourceLoader.VERSION_INVALID.equals(resourceVersion)))
328 {
329 resourceId = resourceLoader.createResourceMeta(localePrefix, libraryName,
330 libraryVersion, resourceName, resourceVersion, contractName);
331 }
332 }
333 else
334 {
335 resourceVersion = resourceLoader
336 .getResourceVersion(localePrefix + '/'+ resourceName, contractName);
337 if (!(resourceVersion != null && ResourceLoader.VERSION_INVALID.equals(resourceVersion)))
338 {
339 resourceId = resourceLoader.createResourceMeta(localePrefix, null, null,
340 resourceName, resourceVersion, contractName);
341 }
342 }
343
344 if (resourceId != null && !resourceLoader.resourceExists(resourceId))
345 {
346 resourceId = null;
347 }
348 }
349
350
351 if (resourceId == null)
352 {
353 if (null != libraryName)
354 {
355 libraryVersion = resourceLoader.getLibraryVersion(libraryName, contractName);
356
357 if (null != libraryVersion)
358 {
359 String pathToResource = (libraryName + '/' + libraryVersion
360 + '/' + resourceName);
361 resourceVersion = resourceLoader
362 .getResourceVersion(pathToResource, contractName);
363 }
364 else
365 {
366 String pathToResource = (libraryName + '/'
367 + resourceName);
368 resourceVersion = resourceLoader
369 .getResourceVersion(pathToResource, contractName);
370 }
371
372 if (!(resourceVersion != null && ResourceLoader.VERSION_INVALID.equals(resourceVersion)))
373 {
374 resourceId = resourceLoader.createResourceMeta(null, libraryName,
375 libraryVersion, resourceName, resourceVersion, contractName);
376 }
377 }
378 else
379 {
380 resourceVersion = resourceLoader
381 .getResourceVersion(resourceName, contractName);
382
383 if (!(resourceVersion != null && ResourceLoader.VERSION_INVALID.equals(resourceVersion)))
384 {
385 resourceId = resourceLoader.createResourceMeta(null, null, null,
386 resourceName, resourceVersion, contractName);
387 }
388 }
389
390 if (resourceId != null && !resourceLoader.resourceExists(resourceId))
391 {
392 resourceId = null;
393 }
394 }
395
396 return resourceId;
397 }
398
399
400
401
402
403
404
405 protected ResourceMeta deriveResourceMeta(ResourceLoader resourceLoader,
406 String resourceName, String libraryName, String localePrefix)
407 {
408 String resourceVersion = null;
409 String libraryVersion = null;
410 ResourceMeta resourceId = null;
411
412
413 if (localePrefix != null)
414 {
415 if (null != libraryName)
416 {
417 String pathToLib = localePrefix + '/' + libraryName;
418 libraryVersion = resourceLoader.getLibraryVersion(pathToLib);
419
420 if (null != libraryVersion)
421 {
422 String pathToResource = localePrefix + '/'
423 + libraryName + '/' + libraryVersion + '/'
424 + resourceName;
425 resourceVersion = resourceLoader
426 .getResourceVersion(pathToResource);
427 }
428 else
429 {
430 String pathToResource = localePrefix + '/'
431 + libraryName + '/' + resourceName;
432 resourceVersion = resourceLoader
433 .getResourceVersion(pathToResource);
434 }
435
436 if (!(resourceVersion != null && ResourceLoader.VERSION_INVALID.equals(resourceVersion)))
437 {
438 resourceId = resourceLoader.createResourceMeta(localePrefix, libraryName,
439 libraryVersion, resourceName, resourceVersion);
440 }
441 }
442 else
443 {
444 resourceVersion = resourceLoader
445 .getResourceVersion(localePrefix + '/'+ resourceName);
446 if (!(resourceVersion != null && ResourceLoader.VERSION_INVALID.equals(resourceVersion)))
447 {
448 resourceId = resourceLoader.createResourceMeta(localePrefix, null, null,
449 resourceName, resourceVersion);
450 }
451 }
452
453 if (resourceId != null && !resourceLoader.resourceExists(resourceId))
454 {
455 resourceId = null;
456 }
457 }
458
459
460 if (resourceId == null)
461 {
462 if (null != libraryName)
463 {
464 libraryVersion = resourceLoader.getLibraryVersion(libraryName);
465
466 if (null != libraryVersion)
467 {
468 String pathToResource = (libraryName + '/' + libraryVersion
469 + '/' + resourceName);
470 resourceVersion = resourceLoader
471 .getResourceVersion(pathToResource);
472 }
473 else
474 {
475 String pathToResource = (libraryName + '/'
476 + resourceName);
477 resourceVersion = resourceLoader
478 .getResourceVersion(pathToResource);
479 }
480
481 if (!(resourceVersion != null && ResourceLoader.VERSION_INVALID.equals(resourceVersion)))
482 {
483 resourceId = resourceLoader.createResourceMeta(null, libraryName,
484 libraryVersion, resourceName, resourceVersion);
485 }
486 }
487 else
488 {
489 resourceVersion = resourceLoader
490 .getResourceVersion(resourceName);
491
492 if (!(resourceVersion != null && ResourceLoader.VERSION_INVALID.equals(resourceVersion)))
493 {
494 resourceId = resourceLoader.createResourceMeta(null, null, null,
495 resourceName, resourceVersion);
496 }
497 }
498
499 if (resourceId != null && !resourceLoader.resourceExists(resourceId))
500 {
501 resourceId = null;
502 }
503 }
504
505 return resourceId;
506 }
507
508 @Override
509 public String getRendererTypeForResourceName(String resourceName)
510 {
511 if (resourceName.endsWith(".js"))
512 {
513 return "javax.faces.resource.Script";
514 }
515 else if (resourceName.endsWith(".css"))
516 {
517 return "javax.faces.resource.Stylesheet";
518 }
519 return null;
520 }
521
522
523
524
525
526
527
528 @Override
529 public void handleResourceRequest(FacesContext facesContext) throws IOException
530 {
531
532
533 String resourceBasePath = getResourceHandlerSupport()
534 .calculateResourceBasePath(facesContext);
535
536 if (resourceBasePath == null)
537 {
538
539
540
541
542 return;
543 }
544
545
546
547
548
549
550 ExternalContext extContext = facesContext.getExternalContext();
551 Object response = extContext.getResponse();
552 HttpServletResponse httpServletResponse = ExternalContextUtils.getHttpServletResponse(response);
553 if (httpServletResponse == null)
554 {
555 throw new IllegalStateException("Could not obtain an instance of HttpServletResponse.");
556 }
557
558 if (isResourceIdentifierExcluded(facesContext, resourceBasePath))
559 {
560 httpServletResponse.setStatus(HttpServletResponse.SC_NOT_FOUND);
561 return;
562 }
563
564 String resourceName = null;
565 if (resourceBasePath.startsWith(ResourceHandler.RESOURCE_IDENTIFIER))
566 {
567 resourceName = resourceBasePath
568 .substring(ResourceHandler.RESOURCE_IDENTIFIER.length() + 1);
569
570 if (resourceBasePath != null && !ResourceValidationUtils.isValidResourceName(resourceName))
571 {
572 httpServletResponse.setStatus(HttpServletResponse.SC_NOT_FOUND);
573 return;
574 }
575 }
576 else
577 {
578
579 httpServletResponse.setStatus(HttpServletResponse.SC_NOT_FOUND);
580 return;
581 }
582
583 String libraryName = facesContext.getExternalContext()
584 .getRequestParameterMap().get("ln");
585
586 if (libraryName != null && !ResourceValidationUtils.isValidLibraryName(
587 libraryName, isAllowSlashesLibraryName()))
588 {
589 httpServletResponse.setStatus(HttpServletResponse.SC_NOT_FOUND);
590 return;
591 }
592
593 Resource resource = null;
594 if (libraryName != null)
595 {
596
597 resource = facesContext.getApplication().getResourceHandler().createResource(resourceName, libraryName);
598 }
599 else
600 {
601 resource = facesContext.getApplication().getResourceHandler().createResource(resourceName);
602 }
603
604 if (resource == null)
605 {
606 httpServletResponse.setStatus(HttpServletResponse.SC_NOT_FOUND);
607 return;
608 }
609
610 if (!resource.userAgentNeedsUpdate(facesContext))
611 {
612 httpServletResponse.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
613 return;
614 }
615
616 httpServletResponse.setContentType(_getContentType(resource, facesContext.getExternalContext()));
617
618 Map<String, String> headers = resource.getResponseHeaders();
619
620 for (Map.Entry<String, String> entry : headers.entrySet())
621 {
622 httpServletResponse.setHeader(entry.getKey(), entry.getValue());
623 }
624
625
626 extContext.setResponseBufferSize(this.getResourceBufferSize());
627
628
629 try
630 {
631 InputStream in = resource.getInputStream();
632 OutputStream out = httpServletResponse.getOutputStream();
633
634 byte[] buffer = new byte[this.getResourceBufferSize()];
635
636 try
637 {
638 int count = pipeBytes(in, out, buffer);
639
640 if (!httpServletResponse.isCommitted())
641 {
642 httpServletResponse.setContentLength(count);
643 }
644 }
645 finally
646 {
647 try
648 {
649 in.close();
650 }
651 finally
652 {
653 out.close();
654 }
655 }
656 }
657 catch (IOException e)
658 {
659
660 if (isConnectionAbort(e))
661 {
662 log.log(Level.INFO,"Connection was aborted while loading resource " + resourceName
663 + " with library " + libraryName);
664 }
665 else
666 {
667 if (log.isLoggable(Level.WARNING))
668 {
669 log.log(Level.WARNING,"Error trying to load and send resource " + resourceName
670 + " with library " + libraryName + " :"
671 + e.getMessage(), e);
672 }
673 httpServletResponse.setStatus(HttpServletResponse.SC_NOT_FOUND);
674 }
675 }
676
677
678
679
680
681
682
683
684 }
685
686 private static boolean isConnectionAbort(IOException e)
687 {
688 return e.getClass().getCanonicalName().equals("org.apache.catalina.connector.ClientAbortException");
689 }
690
691
692
693
694
695 private static int pipeBytes(InputStream in, OutputStream out, byte[] buffer)
696 throws IOException
697 {
698 int count = 0;
699 int length;
700
701 while ((length = (in.read(buffer))) >= 0)
702 {
703 out.write(buffer, 0, length);
704 count += length;
705 }
706 return count;
707 }
708
709 @Override
710 public boolean isResourceRequest(FacesContext facesContext)
711 {
712
713
714
715 Boolean value = (Boolean) facesContext.getAttributes().get(IS_RESOURCE_REQUEST);
716
717 if (value == null)
718 {
719 String resourceBasePath = getResourceHandlerSupport()
720 .calculateResourceBasePath(facesContext);
721
722 value = resourceBasePath != null
723 && resourceBasePath.startsWith(ResourceHandler.RESOURCE_IDENTIFIER);
724 facesContext.getAttributes().put(IS_RESOURCE_REQUEST, value);
725 }
726 return value;
727 }
728
729 protected String getLocalePrefixForLocateResource()
730 {
731 return getLocalePrefixForLocateResource(FacesContext.getCurrentInstance());
732 }
733
734 protected String getLocalePrefixForLocateResource(FacesContext context)
735 {
736 String localePrefix = null;
737 boolean isResourceRequest = context.getApplication().getResourceHandler().isResourceRequest(context);
738
739 if (isResourceRequest)
740 {
741 localePrefix = context.getExternalContext().getRequestParameterMap().get("loc");
742
743 if (localePrefix != null)
744 {
745 if (!ResourceValidationUtils.isValidLocalePrefix(localePrefix))
746 {
747 return null;
748 }
749 return localePrefix;
750 }
751 }
752
753 String bundleName = context.getApplication().getMessageBundle();
754
755 if (null != bundleName)
756 {
757 Locale locale = null;
758
759 if (isResourceRequest || context.getViewRoot() == null)
760 {
761 locale = context.getApplication().getViewHandler()
762 .calculateLocale(context);
763 }
764 else
765 {
766 locale = context.getViewRoot().getLocale();
767 }
768
769 try
770 {
771 ResourceBundle bundle = ResourceBundle
772 .getBundle(bundleName, locale, ClassUtils.getContextClassLoader());
773
774 if (bundle != null)
775 {
776 if (bundle.containsKey(ResourceHandler.LOCALE_PREFIX))
777 {
778 localePrefix = bundle.getString(ResourceHandler.LOCALE_PREFIX);
779 }
780 }
781 }
782 catch (MissingResourceException e)
783 {
784
785 }
786 }
787 return localePrefix;
788 }
789
790 protected String getContractNameForLocateResource(FacesContext context)
791 {
792 String contractName = null;
793 boolean isResourceRequest = context.getApplication().getResourceHandler().isResourceRequest(context);
794
795 if (isResourceRequest)
796 {
797 contractName = context.getExternalContext().getRequestParameterMap().get("con");
798 }
799
800
801 if (contractName == null)
802 {
803 contractName = (String) context.getAttributes().get(ContractResource.CONTRACT_SELECTED);
804 }
805
806
807 if (contractName != null &&
808 !ResourceValidationUtils.isValidContractName(contractName))
809 {
810 return null;
811 }
812 return contractName;
813 }
814
815 protected boolean isResourceIdentifierExcluded(FacesContext context, String resourceIdentifier)
816 {
817 if (_excludedResourceExtensions == null)
818 {
819 String value = WebConfigParamUtils.getStringInitParameter(context.getExternalContext(),
820 RESOURCE_EXCLUDES_PARAM_NAME,
821 RESOURCE_EXCLUDES_DEFAULT_VALUE);
822
823 _excludedResourceExtensions = StringUtils.splitShortString(value, ' ');
824 }
825
826 for (int i = 0; i < _excludedResourceExtensions.length; i++)
827 {
828 if (resourceIdentifier.endsWith(_excludedResourceExtensions[i]))
829 {
830 return true;
831 }
832 }
833 return false;
834 }
835
836
837
838
839
840
841
842 @Override
843 public boolean libraryExists(String libraryName)
844 {
845 FacesContext facesContext = FacesContext.getCurrentInstance();
846 String localePrefix = getLocalePrefixForLocateResource(facesContext);
847 final List<String> contracts = facesContext.getResourceLibraryContracts();
848
849 String pathToLib = null;
850 Boolean libraryFound = null;
851 if (libraryName != null && !ResourceValidationUtils.isValidLibraryName(
852 libraryName, isAllowSlashesLibraryName()))
853 {
854 return false;
855 }
856
857 if (localePrefix != null)
858 {
859
860 pathToLib = localePrefix + '/' + libraryName;
861
862 libraryFound = getResourceLoaderCache().libraryExists(pathToLib);
863 if (libraryFound != null)
864 {
865 return libraryFound.booleanValue();
866 }
867 }
868 libraryFound = getResourceLoaderCache().libraryExists(libraryName);
869 if (libraryFound != null)
870 {
871 return libraryFound.booleanValue();
872 }
873
874 if (localePrefix != null)
875 {
876 if (!contracts.isEmpty())
877 {
878 for (String contract : contracts)
879 {
880 for (ContractResourceLoader loader : getResourceHandlerSupport()
881 .getContractResourceLoaders())
882 {
883 if (loader.libraryExists(pathToLib, contract))
884 {
885 getResourceLoaderCache().confirmLibraryExists(pathToLib);
886 return true;
887 }
888 }
889 }
890 }
891
892 for (ResourceLoader loader : getResourceHandlerSupport()
893 .getResourceLoaders())
894 {
895 if (loader.libraryExists(pathToLib))
896 {
897 getResourceLoaderCache().confirmLibraryExists(pathToLib);
898 return true;
899 }
900 }
901 }
902
903
904 if (!contracts.isEmpty())
905 {
906 for (String contract : contracts)
907 {
908 for (ContractResourceLoader loader : getResourceHandlerSupport()
909 .getContractResourceLoaders())
910 {
911 if (loader.libraryExists(libraryName, contract))
912 {
913 getResourceLoaderCache().confirmLibraryExists(libraryName);
914 return true;
915 }
916 }
917 }
918 }
919
920 for (ResourceLoader loader : getResourceHandlerSupport()
921 .getResourceLoaders())
922 {
923 if (loader.libraryExists(libraryName))
924 {
925 getResourceLoaderCache().confirmLibraryExists(libraryName);
926 return true;
927 }
928 }
929
930 if (localePrefix != null)
931 {
932
933 getResourceLoaderCache().confirmLibraryNotExists(pathToLib);
934 }
935 else
936 {
937 getResourceLoaderCache().confirmLibraryNotExists(libraryName);
938 }
939 return false;
940 }
941
942
943
944
945
946 public void setResourceHandlerSupport(
947 ResourceHandlerSupport resourceHandlerSupport)
948 {
949 _resourceHandlerSupport = resourceHandlerSupport;
950 }
951
952
953
954
955 protected ResourceHandlerSupport getResourceHandlerSupport()
956 {
957 if (_resourceHandlerSupport == null)
958 {
959 _resourceHandlerSupport = new DefaultResourceHandlerSupport();
960 }
961 return _resourceHandlerSupport;
962 }
963
964 private ResourceHandlerCache getResourceLoaderCache()
965 {
966 if (_resourceHandlerCache == null)
967 {
968 _resourceHandlerCache = new ResourceHandlerCache();
969 }
970 return _resourceHandlerCache;
971 }
972
973 private String _getContentType(Resource resource, ExternalContext externalContext)
974 {
975 String contentType = resource.getContentType();
976
977
978 if (contentType == null || contentType.length() == 0)
979 {
980 String resourceName = getWrappedResourceName(resource);
981
982 if (resourceName != null)
983 {
984 contentType = externalContext.getMimeType(resourceName);
985 }
986 }
987
988 return contentType;
989 }
990
991
992
993
994
995
996
997
998 private String getWrappedResourceName(Resource resource)
999 {
1000 String resourceName = resource.getResourceName();
1001 if (resourceName != null)
1002 {
1003 return resourceName;
1004 }
1005
1006 if (resource instanceof ResourceWrapper)
1007 {
1008 return getWrappedResourceName(((ResourceWrapper) resource).getWrapped());
1009 }
1010
1011 return null;
1012 }
1013
1014 protected boolean isAllowSlashesLibraryName()
1015 {
1016 if (_allowSlashLibraryName == null)
1017 {
1018 _allowSlashLibraryName = WebConfigParamUtils.getBooleanInitParameter(
1019 FacesContext.getCurrentInstance().getExternalContext(),
1020 INIT_PARAM_STRICT_JSF_2_ALLOW_SLASH_LIBRARY_NAME,
1021 INIT_PARAM_STRICT_JSF_2_ALLOW_SLASH_LIBRARY_NAME_DEFAULT);
1022 }
1023 return _allowSlashLibraryName;
1024 }
1025
1026 protected int getResourceBufferSize()
1027 {
1028 if (_resourceBufferSize == -1)
1029 {
1030 _resourceBufferSize = WebConfigParamUtils.getIntegerInitParameter(
1031 FacesContext.getCurrentInstance().getExternalContext(),
1032 INIT_PARAM_RESOURCE_BUFFER_SIZE,
1033 INIT_PARAM_RESOURCE_BUFFER_SIZE_DEFAULT);
1034 }
1035 return _resourceBufferSize;
1036 }
1037
1038 @Override
1039 public Resource createResourceFromId(String resourceId)
1040 {
1041 Resource resource = null;
1042
1043 if (resourceId == null)
1044 {
1045 throw new NullPointerException();
1046 }
1047
1048
1049
1050 if (!ResourceValidationUtils.isValidResourceId(resourceId))
1051 {
1052 return null;
1053 }
1054
1055 FacesContext facesContext = FacesContext.getCurrentInstance();
1056 final List<String> contracts = facesContext.getResourceLibraryContracts();
1057 String contractPreferred = getContractNameForLocateResource(facesContext);
1058 ResourceValue resourceValue = null;
1059
1060
1061
1062
1063
1064
1065
1066
1067 if (contractPreferred != null)
1068 {
1069 resourceValue = getResourceLoaderCache().getResource(
1070 resourceId, contractPreferred);
1071 }
1072 if (resourceValue == null && !contracts.isEmpty())
1073 {
1074
1075 for (String contract : contracts)
1076 {
1077 resourceValue = getResourceLoaderCache().getResource(resourceId, contract);
1078 if (resourceValue != null)
1079 {
1080 break;
1081 }
1082 }
1083 }
1084 if (resourceValue == null)
1085 {
1086
1087 resourceValue = getResourceLoaderCache().getResource(resourceId);
1088 }
1089
1090 if(resourceValue != null)
1091 {
1092
1093 String contentType = facesContext.getExternalContext().getMimeType(
1094 resourceValue.getResourceMeta().getResourceName());
1095
1096 resource = new ResourceImpl(resourceValue.getResourceMeta(), resourceValue.getResourceLoader(),
1097 getResourceHandlerSupport(), contentType,
1098 resourceValue.getCachedInfo() != null ? resourceValue.getCachedInfo().getURL() : null,
1099 resourceValue.getCachedInfo() != null ? resourceValue.getCachedInfo().getRequestPath() : null);
1100 }
1101 else
1102 {
1103 boolean resolved = false;
1104 if (contractPreferred != null)
1105 {
1106 for (ContractResourceLoader loader : getResourceHandlerSupport().getContractResourceLoaders())
1107 {
1108 ResourceMeta resourceMeta = deriveResourceMeta(
1109 facesContext, loader, resourceId, contractPreferred);
1110 if (resourceMeta != null)
1111 {
1112 String contentType = facesContext.getExternalContext().getMimeType(
1113 resourceMeta.getResourceName());
1114
1115 resource = new ResourceImpl(resourceMeta, loader,
1116 getResourceHandlerSupport(), contentType);
1117
1118
1119 getResourceLoaderCache().putResource(resourceId, resourceMeta, loader,
1120 new ResourceCachedInfo(resource.getURL(), resource.getRequestPath()));
1121
1122 resolved = true;
1123 break;
1124 }
1125 }
1126 }
1127 if (!resolved && !contracts.isEmpty())
1128 {
1129 for (ContractResourceLoader loader :
1130 getResourceHandlerSupport().getContractResourceLoaders())
1131 {
1132 for (String contract : contracts)
1133 {
1134 ResourceMeta resourceMeta = deriveResourceMeta(
1135 facesContext, loader, resourceId, contract);
1136 if (resourceMeta != null)
1137 {
1138 String contentType = facesContext.getExternalContext().getMimeType(
1139 resourceMeta.getResourceName());
1140
1141 resource = new ResourceImpl(resourceMeta, loader,
1142 getResourceHandlerSupport(), contentType);
1143
1144
1145 getResourceLoaderCache().putResource(resourceId, resourceMeta, loader,
1146 new ResourceCachedInfo(resource.getURL(), resource.getRequestPath()));
1147
1148 resolved = true;
1149 break;
1150 }
1151 }
1152 }
1153 }
1154 if (!resolved)
1155 {
1156 for (ResourceLoader loader : getResourceHandlerSupport().getResourceLoaders())
1157 {
1158 ResourceMeta resourceMeta = deriveResourceMeta(facesContext, loader, resourceId);
1159
1160 if (resourceMeta != null)
1161 {
1162 String contentType = facesContext.getExternalContext().getMimeType(
1163 resourceMeta.getResourceName());
1164
1165 resource = new ResourceImpl(resourceMeta, loader, getResourceHandlerSupport(), contentType);
1166
1167
1168 getResourceLoaderCache().putResource(resourceId, resourceMeta, loader,
1169 new ResourceCachedInfo(resource.getURL(), resource.getRequestPath()));
1170 break;
1171 }
1172 }
1173 }
1174 }
1175 return resource;
1176 }
1177
1178 protected ResourceMeta deriveResourceMeta(FacesContext context, ResourceLoader resourceLoader,
1179 String resourceId)
1180 {
1181 ResourceMeta resourceMeta = null;
1182 String token = null;
1183 String localePrefix = null;
1184 String libraryName = null;
1185 String libraryVersion = null;
1186 String resourceName = null;
1187 String resourceVersion = null;
1188
1189
1190
1191
1192
1193
1194
1195
1196 int lastSlash = resourceId.lastIndexOf('/');
1197 if (lastSlash < 0)
1198 {
1199
1200 resourceName = resourceId;
1201 }
1202 else
1203 {
1204 token = resourceId.substring(lastSlash+1);
1205 if (RESOURCE_VERSION_CHECKER.matcher(token).matches())
1206 {
1207 int secondLastSlash = resourceId.lastIndexOf('/', lastSlash-1);
1208 if (secondLastSlash < 0)
1209 {
1210 secondLastSlash = 0;
1211 }
1212
1213 String rnToken = resourceId.substring(secondLastSlash+1, lastSlash);
1214 int lastPoint = rnToken.lastIndexOf('.');
1215
1216 if (lastPoint >= 0)
1217 {
1218 String ext = rnToken.substring(lastPoint);
1219 if (token.endsWith(ext))
1220 {
1221
1222 resourceVersion = token.substring(0,token.length()-ext.length());
1223 }
1224 }
1225 }
1226
1227
1228 int start = 0;
1229 int firstSlash = resourceId.indexOf('/');
1230
1231
1232 String bundleName = context.getApplication().getMessageBundle();
1233
1234 if (null != bundleName)
1235 {
1236 token = resourceId.substring(start, firstSlash);
1237
1238 Locale locale = _LocaleUtils.deriveLocale(token);
1239
1240
1241
1242 if (locale != null && _LocaleUtils.isAvailableLocale(locale))
1243 {
1244 localePrefix = token;
1245 start = firstSlash+1;
1246 }
1247 }
1248
1249
1250 firstSlash = resourceId.indexOf('/', start);
1251 if (firstSlash < 0)
1252 {
1253
1254 resourceName = resourceId.substring(start);
1255 }
1256 else
1257 {
1258
1259 token = resourceId.substring(start, firstSlash);
1260 int minResourceNameSlash = (resourceVersion != null) ?
1261 resourceId.lastIndexOf('/', lastSlash-1) : lastSlash;
1262
1263 if (start < minResourceNameSlash)
1264 {
1265 libraryName = token;
1266 start = firstSlash+1;
1267
1268
1269 firstSlash = resourceId.indexOf('/', start);
1270 if (firstSlash >= 0)
1271 {
1272 token = resourceId.substring(start, firstSlash);
1273 if (LIBRARY_VERSION_CHECKER.matcher(token).matches())
1274 {
1275 libraryVersion = token;
1276 start = firstSlash+1;
1277 }
1278 }
1279 }
1280
1281 firstSlash = resourceId.indexOf('/', start);
1282 if (firstSlash < 0)
1283 {
1284
1285 resourceName = resourceId.substring(start);
1286 }
1287 else
1288 {
1289
1290 if (resourceVersion != null)
1291 {
1292 resourceName = resourceId.substring(start,lastSlash);
1293 }
1294 else
1295 {
1296
1297 resourceName = resourceId.substring(start);
1298 }
1299 }
1300 }
1301 }
1302
1303
1304 if (resourceName == null)
1305 {
1306 return null;
1307 }
1308 if (!ResourceValidationUtils.isValidResourceName(resourceName))
1309 {
1310 return null;
1311 }
1312
1313 if (libraryName != null && !ResourceValidationUtils.isValidLibraryName(
1314 libraryName, isAllowSlashesLibraryName()))
1315 {
1316 return null;
1317 }
1318
1319
1320 if (localePrefix != null && localePrefix.length() == 0)
1321 {
1322 localePrefix = null;
1323 }
1324 if (libraryName != null && libraryName.length() == 0)
1325 {
1326 libraryName = null;
1327 }
1328 if (libraryVersion != null && libraryVersion.length() == 0)
1329 {
1330 libraryVersion = null;
1331 }
1332 if (resourceName != null && resourceName.length() == 0)
1333 {
1334 resourceName = null;
1335 }
1336 if (resourceVersion != null && resourceVersion.length() == 0)
1337 {
1338 resourceVersion = null;
1339 }
1340
1341 resourceMeta = resourceLoader.createResourceMeta(
1342 localePrefix, libraryName, libraryVersion, resourceName, resourceVersion);
1343
1344 if (resourceMeta != null &&
1345 !resourceLoader.resourceExists(resourceMeta))
1346 {
1347 resourceMeta = null;
1348 }
1349
1350 return resourceMeta;
1351 }
1352
1353 protected ResourceMeta deriveResourceMeta(FacesContext context, ContractResourceLoader resourceLoader,
1354 String resourceId, String contractName)
1355 {
1356 ResourceMeta resourceMeta = null;
1357 String token = null;
1358 String localePrefix = null;
1359 String libraryName = null;
1360 String libraryVersion = null;
1361 String resourceName = null;
1362 String resourceVersion = null;
1363
1364
1365
1366
1367
1368
1369
1370
1371 int lastSlash = resourceId.lastIndexOf('/');
1372 if (lastSlash < 0)
1373 {
1374
1375 resourceName = resourceId;
1376 }
1377 else
1378 {
1379 token = resourceId.substring(lastSlash+1);
1380 if (RESOURCE_VERSION_CHECKER.matcher(token).matches())
1381 {
1382 int secondLastSlash = resourceId.lastIndexOf('/', lastSlash-1);
1383 if (secondLastSlash < 0)
1384 {
1385 secondLastSlash = 0;
1386 }
1387
1388 String rnToken = resourceId.substring(secondLastSlash+1, lastSlash);
1389 int lastPoint = rnToken.lastIndexOf('.');
1390
1391 if (lastPoint >= 0)
1392 {
1393 String ext = rnToken.substring(lastPoint);
1394 if (token.endsWith(ext))
1395 {
1396
1397 resourceVersion = token.substring(0,token.length()-ext.length());
1398 }
1399 }
1400 }
1401
1402
1403 int start = 0;
1404 int firstSlash = resourceId.indexOf('/');
1405
1406
1407 String bundleName = context.getApplication().getMessageBundle();
1408
1409 if (null != bundleName)
1410 {
1411 token = resourceId.substring(start, firstSlash);
1412
1413 Locale locale = _LocaleUtils.deriveLocale(token);
1414
1415
1416
1417 if (locale != null && _LocaleUtils.isAvailableLocale(locale))
1418 {
1419 localePrefix = token;
1420 start = firstSlash+1;
1421 }
1422 }
1423
1424
1425 firstSlash = resourceId.indexOf('/', start);
1426 if (firstSlash < 0)
1427 {
1428
1429 resourceName = resourceId.substring(start);
1430 }
1431 else
1432 {
1433
1434 token = resourceId.substring(start, firstSlash);
1435 int minResourceNameSlash = (resourceVersion != null) ?
1436 resourceId.lastIndexOf('/', lastSlash-1) : lastSlash;
1437
1438 if (start < minResourceNameSlash)
1439 {
1440 libraryName = token;
1441 start = firstSlash+1;
1442
1443
1444 firstSlash = resourceId.indexOf('/', start);
1445 if (firstSlash >= 0)
1446 {
1447 token = resourceId.substring(start, firstSlash);
1448 if (LIBRARY_VERSION_CHECKER.matcher(token).matches())
1449 {
1450 libraryVersion = token;
1451 start = firstSlash+1;
1452 }
1453 }
1454 }
1455
1456 firstSlash = resourceId.indexOf('/', start);
1457 if (firstSlash < 0)
1458 {
1459
1460 resourceName = resourceId.substring(start);
1461 }
1462 else
1463 {
1464
1465 if (resourceVersion != null)
1466 {
1467 resourceName = resourceId.substring(start,lastSlash);
1468 }
1469 else
1470 {
1471
1472 resourceName = resourceId.substring(start);
1473 }
1474 }
1475 }
1476 }
1477
1478
1479 if (resourceName == null)
1480 {
1481 return null;
1482 }
1483 if (!ResourceValidationUtils.isValidResourceName(resourceName))
1484 {
1485 return null;
1486 }
1487
1488 if (libraryName != null && !ResourceValidationUtils.isValidLibraryName(
1489 libraryName, isAllowSlashesLibraryName()))
1490 {
1491 return null;
1492 }
1493
1494
1495 if (localePrefix != null && localePrefix.length() == 0)
1496 {
1497 localePrefix = null;
1498 }
1499 if (libraryName != null && libraryName.length() == 0)
1500 {
1501 libraryName = null;
1502 }
1503 if (libraryVersion != null && libraryVersion.length() == 0)
1504 {
1505 libraryVersion = null;
1506 }
1507 if (resourceName != null && resourceName.length() == 0)
1508 {
1509 resourceName = null;
1510 }
1511 if (resourceVersion != null && resourceVersion.length() == 0)
1512 {
1513 resourceVersion = null;
1514 }
1515
1516 resourceMeta = resourceLoader.createResourceMeta(
1517 localePrefix, libraryName, libraryVersion, resourceName, resourceVersion, contractName);
1518
1519 if (resourceMeta != null &&
1520 !resourceLoader.resourceExists(resourceMeta))
1521 {
1522 resourceMeta = null;
1523 }
1524
1525 return resourceMeta;
1526 }
1527
1528 protected ResourceMeta deriveViewResourceMeta(FacesContext context, ResourceLoader resourceLoader,
1529 String resourceName, String localePrefix)
1530 {
1531 ResourceMeta resourceMeta = null;
1532 String resourceVersion = null;
1533
1534
1535 if (localePrefix != null)
1536 {
1537 resourceVersion = resourceLoader
1538 .getResourceVersion(localePrefix + '/'+ resourceName);
1539 if (!(resourceVersion != null && ResourceLoader.VERSION_INVALID.equals(resourceVersion)))
1540 {
1541 resourceMeta = resourceLoader.createResourceMeta(localePrefix, null, null,
1542 resourceName, resourceVersion);
1543 }
1544
1545 if (resourceMeta != null && !resourceLoader.resourceExists(resourceMeta))
1546 {
1547 resourceMeta = null;
1548 }
1549 }
1550
1551
1552 if (resourceMeta == null)
1553 {
1554 resourceVersion = resourceLoader
1555 .getResourceVersion(resourceName);
1556 if (!(resourceVersion != null && ResourceLoader.VERSION_INVALID.equals(resourceVersion)))
1557 {
1558 resourceMeta = resourceLoader.createResourceMeta(null, null, null,
1559 resourceName, resourceVersion);
1560 }
1561
1562 if (resourceMeta != null && !resourceLoader.resourceExists(resourceMeta))
1563 {
1564 resourceMeta = null;
1565 }
1566 }
1567
1568 return resourceMeta;
1569 }
1570
1571 protected ResourceMeta deriveViewResourceMeta(FacesContext context, ContractResourceLoader resourceLoader,
1572 String resourceName, String localePrefix, String contractName)
1573 {
1574 ResourceMeta resourceMeta = null;
1575 String resourceVersion = null;
1576
1577
1578 if (localePrefix != null)
1579 {
1580 resourceVersion = resourceLoader
1581 .getResourceVersion(localePrefix + '/'+ resourceName, contractName);
1582 if (!(resourceVersion != null && ResourceLoader.VERSION_INVALID.equals(resourceVersion)))
1583 {
1584 resourceMeta = resourceLoader.createResourceMeta(localePrefix, null, null,
1585 resourceName, resourceVersion, contractName);
1586 }
1587
1588 if (resourceMeta != null && !resourceLoader.resourceExists(resourceMeta))
1589 {
1590 resourceMeta = null;
1591 }
1592 }
1593
1594
1595 if (resourceMeta == null)
1596 {
1597 resourceVersion = resourceLoader
1598 .getResourceVersion(resourceName, contractName);
1599 if (!(resourceVersion != null && ResourceLoader.VERSION_INVALID.equals(resourceVersion)))
1600 {
1601 resourceMeta = resourceLoader.createResourceMeta(null, null, null,
1602 resourceName, resourceVersion, contractName);
1603 }
1604
1605 if (resourceMeta != null && !resourceLoader.resourceExists(resourceMeta))
1606 {
1607 resourceMeta = null;
1608 }
1609 }
1610
1611 return resourceMeta;
1612 }
1613
1614 @Override
1615 public Resource createViewResource(FacesContext facesContext, String resourceName)
1616 {
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638 Resource resource = null;
1639
1640 if (resourceName == null)
1641 {
1642 throw new NullPointerException();
1643 }
1644 if (resourceName.charAt(0) == '/')
1645 {
1646
1647
1648
1649 resourceName = resourceName.substring(1);
1650 }
1651
1652
1653
1654 if (!ResourceValidationUtils.isValidViewResource(resourceName))
1655 {
1656 return null;
1657 }
1658 final String localePrefix = getLocalePrefixForLocateResource(facesContext);
1659 String contentType = facesContext.getExternalContext().getMimeType(resourceName);
1660 final List<String> contracts = facesContext.getResourceLibraryContracts();
1661 String contractPreferred = getContractNameForLocateResource(facesContext);
1662 ResourceValue resourceValue = null;
1663
1664
1665
1666
1667
1668
1669
1670
1671 if (contractPreferred != null)
1672 {
1673 resourceValue = getResourceLoaderCache().getViewResource(
1674 resourceName, contentType, localePrefix, contractPreferred);
1675 }
1676 if (resourceValue == null && !contracts.isEmpty())
1677 {
1678
1679 for (String contract : contracts)
1680 {
1681 resourceValue = getResourceLoaderCache().getViewResource(
1682 resourceName, contentType, localePrefix, contract);
1683 if (resourceValue != null)
1684 {
1685 break;
1686 }
1687 }
1688 }
1689 if (resourceValue == null)
1690 {
1691
1692 resourceValue = getResourceLoaderCache().getViewResource(
1693 resourceName, contentType, localePrefix);
1694 }
1695
1696 if(resourceValue != null)
1697 {
1698 resource = new ResourceImpl(resourceValue.getResourceMeta(), resourceValue.getResourceLoader(),
1699 getResourceHandlerSupport(), contentType,
1700 resourceValue.getCachedInfo() != null ? resourceValue.getCachedInfo().getURL() : null, null);
1701 }
1702 else
1703 {
1704 boolean resolved = false;
1705 if (contractPreferred != null)
1706 {
1707 for (ContractResourceLoader loader : getResourceHandlerSupport().getContractResourceLoaders())
1708 {
1709 ResourceMeta resourceMeta = deriveViewResourceMeta(
1710 facesContext, loader, resourceName, localePrefix, contractPreferred);
1711 if (resourceMeta != null)
1712 {
1713 resource = new ResourceImpl(resourceMeta, loader,
1714 getResourceHandlerSupport(), contentType);
1715
1716
1717 getResourceLoaderCache().putViewResource(
1718 resourceName, contentType, localePrefix, contractPreferred, resourceMeta, loader,
1719 new ResourceCachedInfo(resource.getURL(), null));
1720
1721 resolved = true;
1722 break;
1723 }
1724 }
1725 }
1726 if (!resolved && !contracts.isEmpty())
1727 {
1728 for (ContractResourceLoader loader :
1729 getResourceHandlerSupport().getContractResourceLoaders())
1730 {
1731 for (String contract : contracts)
1732 {
1733 ResourceMeta resourceMeta = deriveViewResourceMeta(
1734 facesContext, loader, resourceName, localePrefix, contract);
1735 if (resourceMeta != null)
1736 {
1737 resource = new ResourceImpl(resourceMeta, loader,
1738 getResourceHandlerSupport(), contentType);
1739
1740
1741 getResourceLoaderCache().putViewResource(
1742 resourceName, contentType, localePrefix, contract, resourceMeta, loader,
1743 new ResourceCachedInfo(resource.getURL(), null));
1744
1745 resolved = true;
1746 break;
1747 }
1748 }
1749 }
1750 }
1751 if (!resolved)
1752 {
1753
1754
1755
1756
1757 for (ResourceLoader loader : getResourceHandlerSupport().getViewResourceLoaders())
1758 {
1759 ResourceMeta resourceMeta = deriveViewResourceMeta(
1760 facesContext, loader, resourceName, localePrefix);
1761
1762 if (resourceMeta != null)
1763 {
1764 resource = new ResourceImpl(resourceMeta, loader, getResourceHandlerSupport(), contentType);
1765
1766
1767 getResourceLoaderCache().putViewResource(
1768 resourceName, contentType, localePrefix, resourceMeta, loader,
1769 new ResourceCachedInfo(resource.getURL(), null));
1770 break;
1771 }
1772 }
1773 }
1774 }
1775 return resource;
1776 }
1777
1778 public Stream<java.lang.String> getViewResources(FacesContext facesContext,
1779 String path, int maxDepth, ResourceVisitOption... options)
1780 {
1781 final String localePrefix = getLocalePrefixForLocateResource(facesContext);
1782 final List<String> contracts = facesContext.getResourceLibraryContracts();
1783 String contractPreferred = getContractNameForLocateResource(facesContext);
1784
1785 if (this._viewSuffixes == null)
1786 {
1787 this._viewSuffixes = loadSuffixes(facesContext.getExternalContext());
1788 }
1789
1790 Iterator it = new FilterInvalidSuffixViewResourceIterator(new ViewResourceIterator(facesContext,
1791 getResourceHandlerSupport(), localePrefix, contracts,
1792 contractPreferred, path, maxDepth, options), facesContext, _viewSuffixes);
1793
1794 return StreamSupport.stream(Spliterators.spliteratorUnknownSize(it,Spliterator.DISTINCT), false);
1795 }
1796
1797 private Set<String> loadSuffixes (ExternalContext context)
1798 {
1799 Set<String> result = new HashSet<String>();
1800 String definedSuffixes = WebConfigParamUtils.getStringInitParameter(context,
1801 ViewHandler.DEFAULT_SUFFIX_PARAM_NAME, ViewHandler.DEFAULT_SUFFIX);
1802 StringTokenizer tokenizer;
1803
1804 if (definedSuffixes == null)
1805 {
1806 definedSuffixes = ViewHandler.DEFAULT_SUFFIX;
1807 }
1808
1809
1810
1811 tokenizer = new StringTokenizer (definedSuffixes, " ");
1812
1813 while (tokenizer.hasMoreTokens())
1814 {
1815 result.add (tokenizer.nextToken());
1816 }
1817
1818 String faceletSuffix = WebConfigParamUtils.getStringInitParameter(context,
1819 ViewHandler.FACELETS_SUFFIX_PARAM_NAME, ViewHandler.DEFAULT_FACELETS_SUFFIX);
1820
1821 if (faceletSuffix != null)
1822 {
1823 result.add(faceletSuffix.trim());
1824 }
1825
1826 String faceletViewMappings = WebConfigParamUtils.getStringInitParameter(context, FACELETS_VIEW_MAPPINGS_PARAM);
1827
1828 if (faceletViewMappings != null)
1829 {
1830 tokenizer = new StringTokenizer(faceletViewMappings, ";");
1831 while (tokenizer.hasMoreTokens())
1832 {
1833 result.add (tokenizer.nextToken());
1834 }
1835 }
1836
1837 return result;
1838 }
1839
1840
1841
1842
1843 private static class FilterInvalidSuffixViewResourceIterator extends SkipMatchIterator<String>
1844 {
1845 private FacesContext facesContext;
1846 private Set<String> validSuffixes;
1847
1848 public FilterInvalidSuffixViewResourceIterator(Iterator<String> delegate, FacesContext facesContext,
1849 Set<String> validSuffixes)
1850 {
1851 super(delegate);
1852 this.facesContext = facesContext;
1853 this.validSuffixes = validSuffixes;
1854 }
1855
1856 @Override
1857 protected boolean match(String value)
1858 {
1859 String viewId = (String) value;
1860 ViewDeclarationLanguage vdl = facesContext.getApplication().getViewHandler()
1861 .getViewDeclarationLanguage(facesContext, viewId);
1862 if (vdl != null && vdl.viewExists(facesContext, viewId))
1863 {
1864 boolean matchSuffix = false;
1865 for (String suffix : validSuffixes)
1866 {
1867 if (suffix != null && suffix.length() > 0 && viewId.endsWith(suffix))
1868 {
1869 matchSuffix = true;
1870 break;
1871 }
1872 }
1873 if (matchSuffix)
1874 {
1875
1876 return false;
1877 }
1878 else
1879 {
1880 return true;
1881 }
1882 }
1883
1884 return true;
1885 }
1886 }
1887
1888
1889
1890
1891
1892
1893
1894
1895 public boolean isResourceRendered(FacesContext facesContext, String resourceName, String libraryName)
1896 {
1897 return getRenderedResources(facesContext).containsKey(
1898 libraryName != null
1899 ? contactLibraryAndResource(facesContext, libraryName, resourceName)
1900 : resourceName);
1901 }
1902
1903
1904
1905
1906
1907
1908
1909 @Override
1910 public void markResourceRendered(FacesContext facesContext, String resourceName, String libraryName)
1911 {
1912 getRenderedResources(facesContext).put(
1913 libraryName != null
1914 ? contactLibraryAndResource(facesContext, libraryName, resourceName)
1915 : resourceName,
1916 Boolean.TRUE);
1917
1918 if (ResourceHandler.JSF_SCRIPT_LIBRARY_NAME.equals(libraryName) &&
1919 ResourceHandler.JSF_SCRIPT_RESOURCE_NAME.equals(resourceName))
1920 {
1921
1922
1923 getRenderedResources(facesContext).put(
1924 contactLibraryAndResource(facesContext, MYFACES_LIBRARY_NAME, MYFACES_JS_RESOURCE_NAME),
1925 Boolean.TRUE);
1926 }
1927 }
1928
1929
1930
1931
1932
1933
1934
1935
1936 @SuppressWarnings("unchecked")
1937 private static Map<String, Boolean> getRenderedResources(FacesContext facesContext)
1938 {
1939 Map<String, Boolean> map = (Map<String, Boolean>) facesContext.getViewRoot().getTransientStateHelper()
1940 .getTransient(RENDERED_RESOURCES_SET);
1941 if (map == null)
1942 {
1943 map = new HashMap<String, Boolean>();
1944 facesContext.getViewRoot().getTransientStateHelper().putTransient(RENDERED_RESOURCES_SET,map);
1945 }
1946 return map;
1947 }
1948
1949 private static String contactLibraryAndResource(FacesContext facesContext, String libraryName, String resourceName)
1950 {
1951 StringBuilder sb = SharedStringBuilder.get(facesContext, SHARED_STRING_BUILDER, 40);
1952 return sb.append(libraryName).append('/').append(resourceName).toString();
1953 }
1954 }