1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.myfaces.shared.application;
20
21 import java.net.MalformedURLException;
22 import java.util.Map;
23 import java.util.logging.Level;
24 import java.util.logging.Logger;
25
26 import javax.faces.application.ViewHandler;
27 import javax.faces.context.ExternalContext;
28 import javax.faces.context.FacesContext;
29 import javax.faces.render.ResponseStateManager;
30 import javax.faces.view.ViewDeclarationLanguage;
31
32 import org.apache.myfaces.shared.renderkit.html.util.SharedStringBuilder;
33 import org.apache.myfaces.shared.util.ExternalContextUtils;
34 import org.apache.myfaces.shared.util.StringUtils;
35 import org.apache.myfaces.shared.util.ViewProtectionUtils;
36
37
38
39
40
41 public class DefaultViewHandlerSupport implements ViewHandlerSupport
42 {
43
44
45
46 private static final String CACHED_SERVLET_MAPPING =
47 DefaultViewHandlerSupport.class.getName() + ".CACHED_SERVLET_MAPPING";
48
49
50 private static final Logger log = Logger.getLogger(DefaultViewHandlerSupport.class.getName());
51
52 private static final String VIEW_HANDLER_SUPPORT_SB = "oam.viewhandler.SUPPORT_SB";
53
54 private final String[] _faceletsViewMappings;
55 private final String[] _contextSuffixes;
56 private final String _faceletsContextSufix;
57 private final boolean _initialized;
58 private CheckedViewIdsCache checkedViewIdsCache = null;
59
60 public DefaultViewHandlerSupport()
61 {
62 _faceletsViewMappings = null;
63 _contextSuffixes = null;
64 _faceletsContextSufix = null;
65 _initialized = false;
66 }
67
68 public DefaultViewHandlerSupport(FacesContext facesContext)
69 {
70 _faceletsViewMappings = getFaceletsViewMappings(facesContext);
71 _contextSuffixes = getContextSuffix(facesContext);
72 _faceletsContextSufix = getFaceletsContextSuffix(facesContext);
73 _initialized = true;
74 }
75
76 public String calculateViewId(FacesContext context, String viewId)
77 {
78
79 if (viewId == null)
80 {
81 return null;
82 }
83 FacesServletMapping mapping = getFacesServletMapping(context);
84 if (mapping == null || mapping.isExtensionMapping())
85 {
86 viewId = handleSuffixMapping(context, viewId);
87 }
88 else if (mapping.isExactMapping())
89 {
90
91 if (viewId.equals(mapping.getExact()))
92 {
93 viewId = handleSuffixMapping(context, viewId + ".jsf");
94 }
95 }
96 else if(mapping.isPrefixMapping())
97 {
98 viewId = handlePrefixMapping(viewId,mapping.getPrefix());
99
100
101
102
103
104 if (viewId != null && viewId.equals(mapping.getPrefix()) &&
105 !ExternalContextUtils.isPortlet(context.getExternalContext()))
106 {
107 throw new InvalidViewIdException();
108 }
109
110
111
112
113 if (viewId != null && viewId.equals(mapping.getPrefix()))
114 {
115 viewId = handleSuffixMapping(context, viewId+".jsf");
116 }
117 }
118 else if (mapping.getUrlPattern().startsWith(viewId))
119 {
120 throw new InvalidViewIdException(viewId);
121 }
122
123
124
125
126
127
128 return viewId;
129 }
130
131 public String calculateAndCheckViewId(FacesContext context, String viewId)
132 {
133
134 if (viewId == null)
135 {
136 return null;
137 }
138 FacesServletMapping mapping = getFacesServletMapping(context);
139 if (mapping == null || mapping.isExtensionMapping())
140 {
141 viewId = handleSuffixMapping(context, viewId);
142 }
143 else if (mapping.isExactMapping())
144 {
145
146 if (viewId.equals(mapping.getExact()))
147 {
148 viewId = handleSuffixMapping(context, viewId + ".jsf");
149 }
150 }
151 else if(mapping.isPrefixMapping())
152 {
153 viewId = handlePrefixMapping(viewId,mapping.getPrefix());
154
155 if(viewId != null)
156 {
157
158
159
160
161
162
163
164
165
166
167
168
169
170 if (viewId != null && viewId.equals(mapping.getPrefix()))
171 {
172 viewId = handleSuffixMapping(context, viewId+".jsf");
173 }
174
175 return (checkResourceExists(context,viewId) ? viewId : null);
176 }
177 }
178 else if (mapping.getUrlPattern().startsWith(viewId))
179 {
180 throw new InvalidViewIdException(viewId);
181 }
182 else
183 {
184 if(viewId != null)
185 {
186 return (checkResourceExists(context,viewId) ? viewId : null);
187 }
188 }
189
190 return viewId;
191 }
192
193 public String calculateActionURL(FacesContext context, String viewId)
194 {
195 if (viewId == null || !viewId.startsWith("/"))
196 {
197 throw new IllegalArgumentException("ViewId must start with a '/': " + viewId);
198 }
199
200 FacesServletMapping mapping = getFacesServletMapping(context);
201 ExternalContext externalContext = context.getExternalContext();
202 String contextPath = externalContext.getRequestContextPath();
203
204 StringBuilder builder = SharedStringBuilder.get(context, VIEW_HANDLER_SUPPORT_SB);
205
206
207 if (contextPath != null && !(contextPath.length() == 1 && contextPath.charAt(0) == '/') )
208 {
209 builder.append(contextPath);
210 }
211
212
213
214
215 if (mapping != null && mapping.isExactMapping())
216 {
217 String exactMappingViewId = calculatePrefixedExactMapping(context, viewId);
218 if (exactMappingViewId != null && !exactMappingViewId.isEmpty())
219 {
220
221 if (!mapping.getExact().equals(exactMappingViewId))
222 {
223
224 mapping = FacesServletMappingUtils.getExactMapping(context, exactMappingViewId);
225
226
227
228 if (mapping == null)
229 {
230 mapping = FacesServletMappingUtils.getGenericPrefixOrSuffixMapping(context);
231 if (mapping == null)
232 {
233 throw new IllegalStateException(
234 "No generic (either prefix or suffix) servlet-mapping found for FacesServlet."
235 + "This is required serve views, that are not exact mapped.");
236 }
237 }
238 }
239 }
240 }
241
242 if (mapping != null)
243 {
244 if (mapping.isExactMapping())
245 {
246 builder.append(mapping.getExact());
247 }
248 else if (mapping.isExtensionMapping())
249 {
250
251 String[] contextSuffixes = _initialized ? _contextSuffixes : getContextSuffix(context);
252 boolean founded = false;
253 for (String contextSuffix : contextSuffixes)
254 {
255 if (viewId.endsWith(contextSuffix))
256 {
257 builder.append(viewId.substring(0, viewId.indexOf(contextSuffix)));
258 builder.append(mapping.getExtension());
259 founded = true;
260 break;
261 }
262 }
263 if (!founded)
264 {
265
266
267
268
269
270
271
272
273
274
275
276 if (viewId.endsWith(mapping.getExtension()))
277 {
278 builder.append(viewId);
279 }
280 else if(viewId.lastIndexOf('.') != -1 )
281 {
282 builder.append(viewId.substring(0, viewId.lastIndexOf('.')));
283 builder.append(contextSuffixes[0]);
284 }
285 else
286 {
287 builder.append(viewId);
288 builder.append(contextSuffixes[0]);
289 }
290 }
291 }
292 else if (mapping.isPrefixMapping())
293 {
294 builder.append(mapping.getPrefix());
295 builder.append(viewId);
296 }
297 }
298 else
299 {
300 builder.append(viewId);
301 }
302
303
304 if (ViewProtectionUtils.isViewProtected(context, viewId))
305 {
306 int index = builder.indexOf("?");
307 if (index >= 0)
308 {
309 builder.append("&");
310 }
311 else
312 {
313 builder.append("?");
314 }
315 builder.append(ResponseStateManager.NON_POSTBACK_VIEW_TOKEN_PARAM);
316 builder.append("=");
317 ResponseStateManager rsm = context.getRenderKit().getResponseStateManager();
318 builder.append(rsm.getCryptographicallyStrongTokenFromSession(context));
319 }
320
321 String calculatedActionURL = builder.toString();
322 if (log.isLoggable(Level.FINEST))
323 {
324 log.finest("Calculated actionURL: '" + calculatedActionURL + "' for viewId: '" + viewId + "'");
325 }
326 return calculatedActionURL;
327 }
328
329 private String calculatePrefixedExactMapping(FacesContext context, String viewId)
330 {
331 String[] contextSuffixes = _initialized ? _contextSuffixes : getContextSuffix(context);
332 String prefixedExactMapping = null;
333 for (String contextSuffix : contextSuffixes)
334 {
335 if (viewId.endsWith(contextSuffix))
336 {
337 prefixedExactMapping = viewId.substring(0, viewId.length() - contextSuffix.length());
338 break;
339 }
340 }
341 return prefixedExactMapping == null ? viewId : prefixedExactMapping;
342 }
343
344
345
346
347
348
349 protected FacesServletMapping getFacesServletMapping(FacesContext context)
350 {
351 Map<Object, Object> attributes = context.getAttributes();
352
353
354 FacesServletMapping mapping = (FacesServletMapping) attributes.get(CACHED_SERVLET_MAPPING);
355 if (mapping == null)
356 {
357 ExternalContext externalContext = context.getExternalContext();
358 mapping = FacesServletMappingUtils.calculateFacesServletMapping(
359 context, externalContext.getRequestServletPath(),
360 externalContext.getRequestPathInfo(),
361 true);
362
363 attributes.put(CACHED_SERVLET_MAPPING, mapping);
364 }
365 return mapping;
366 }
367
368 protected String[] getContextSuffix(FacesContext context)
369 {
370 String defaultSuffix = context.getExternalContext().getInitParameter(ViewHandler.DEFAULT_SUFFIX_PARAM_NAME);
371 if (defaultSuffix == null)
372 {
373 defaultSuffix = ViewHandler.DEFAULT_SUFFIX;
374 }
375 return StringUtils.splitShortString(defaultSuffix, ' ');
376 }
377
378 protected String getFaceletsContextSuffix(FacesContext context)
379 {
380 String defaultSuffix = context.getExternalContext().getInitParameter(ViewHandler.FACELETS_SUFFIX_PARAM_NAME);
381 if (defaultSuffix == null)
382 {
383 defaultSuffix = ViewHandler.DEFAULT_FACELETS_SUFFIX;
384 }
385 return defaultSuffix;
386 }
387
388
389
390 protected String[] getFaceletsViewMappings(FacesContext context)
391 {
392 String faceletsViewMappings= context.getExternalContext().getInitParameter(
393 ViewHandler.FACELETS_VIEW_MAPPINGS_PARAM_NAME);
394 if(faceletsViewMappings == null)
395 {
396 faceletsViewMappings= context.getExternalContext().getInitParameter("facelets.VIEW_MAPPINGS");
397 }
398
399 return faceletsViewMappings == null ? null : StringUtils.splitShortString(faceletsViewMappings, ';');
400 }
401
402
403
404
405
406
407
408
409 protected String handlePrefixMapping(String viewId, String prefix)
410 {
411
412
413
414
415
416
417
418
419 if ("".equals(prefix))
420 {
421
422
423
424 prefix = "//";
425 }
426 else
427 {
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457 return uri;
458 }
459
460
461
462
463
464
465
466
467 protected String handleSuffixMapping(FacesContext context, String requestViewId)
468 {
469 String[] faceletsViewMappings = _initialized ? _faceletsViewMappings : getFaceletsViewMappings(context);
470 String[] jspDefaultSuffixes = _initialized ? _contextSuffixes : getContextSuffix(context);
471
472 int slashPos = requestViewId.lastIndexOf('/');
473 int extensionPos = requestViewId.lastIndexOf('.');
474
475 StringBuilder builder = SharedStringBuilder.get(context, VIEW_HANDLER_SUPPORT_SB);
476
477
478 for (String defaultSuffix : jspDefaultSuffixes)
479 {
480
481 builder.setLength(0);
482 builder.append(requestViewId);
483
484 if (extensionPos > -1 && extensionPos > slashPos)
485 {
486 builder.replace(extensionPos, requestViewId.length(), defaultSuffix);
487 }
488 else
489 {
490 builder.append(defaultSuffix);
491 }
492 String candidateViewId = builder.toString();
493
494 if( faceletsViewMappings != null && faceletsViewMappings.length > 0 )
495 {
496 for (String mapping : faceletsViewMappings)
497 {
498 if(mapping.startsWith("/"))
499 {
500 continue;
501 }
502 if(mapping.equals(candidateViewId))
503 {
504 return candidateViewId;
505 }
506 if(mapping.startsWith("."))
507 {
508 builder.setLength(0);
509 builder.append(candidateViewId);
510 builder.replace(candidateViewId.lastIndexOf('.'), candidateViewId.length(), mapping);
511 String tempViewId = builder.toString();
512 if(checkResourceExists(context,tempViewId))
513 {
514 return tempViewId;
515 }
516 }
517 }
518 }
519
520
521 if(checkResourceExists(context,candidateViewId))
522 {
523 return candidateViewId;
524 }
525
526 }
527
528
529 String faceletsDefaultSuffix = _initialized ? _faceletsContextSufix : this.getFaceletsContextSuffix(context);
530 if (faceletsDefaultSuffix != null)
531 {
532 for (String defaultSuffix : jspDefaultSuffixes)
533 {
534 if (faceletsDefaultSuffix.equals(defaultSuffix))
535 {
536 faceletsDefaultSuffix = null;
537 break;
538 }
539 }
540 }
541 if (faceletsDefaultSuffix != null)
542 {
543
544 builder.setLength(0);
545 builder.append(requestViewId);
546
547 if (extensionPos > -1 && extensionPos > slashPos)
548 {
549 builder.replace(extensionPos, requestViewId.length(), faceletsDefaultSuffix);
550 }
551 else
552 {
553 builder.append(faceletsDefaultSuffix);
554 }
555
556 String candidateViewId = builder.toString();
557 if(checkResourceExists(context,candidateViewId))
558 {
559 return candidateViewId;
560 }
561 }
562
563
564 if(checkResourceExists(context,requestViewId))
565 {
566 return requestViewId;
567 }
568
569
570 return null;
571 }
572
573 protected boolean checkResourceExists(FacesContext facesContext, String viewId)
574 {
575 if (checkedViewIdsCache == null)
576 {
577 checkedViewIdsCache = CheckedViewIdsCache.getInstance(facesContext);
578 }
579
580 try
581 {
582 Boolean resourceExists = null;
583 if (checkedViewIdsCache.isEnabled())
584 {
585 resourceExists = checkedViewIdsCache.getCache().get(viewId);
586 }
587
588 if (resourceExists == null)
589 {
590 ViewDeclarationLanguage vdl = facesContext.getApplication().getViewHandler()
591 .getViewDeclarationLanguage(facesContext, viewId);
592 if (vdl != null)
593 {
594 resourceExists = vdl.viewExists(facesContext, viewId);
595 }
596 else
597 {
598
599 resourceExists = facesContext.getExternalContext().getResource(viewId) != null;
600 }
601
602 if (checkedViewIdsCache.isEnabled())
603 {
604 checkedViewIdsCache.getCache().put(viewId, resourceExists);
605 }
606 }
607
608 return resourceExists;
609 }
610 catch (MalformedURLException e)
611 {
612
613 }
614 return false;
615 }
616
617 }