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