1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.myfaces.view.facelets.tag.jsf;
20
21 import java.io.IOException;
22 import java.util.Iterator;
23 import java.util.List;
24 import java.util.Map;
25 import java.util.logging.Level;
26 import java.util.logging.Logger;
27
28 import javax.el.ValueExpression;
29 import javax.faces.FacesWrapper;
30 import javax.faces.application.Application;
31 import javax.faces.application.ProjectStage;
32 import javax.faces.component.ActionSource;
33 import javax.faces.component.EditableValueHolder;
34 import javax.faces.component.UIComponent;
35 import javax.faces.component.UniqueIdVendor;
36 import javax.faces.component.ValueHolder;
37 import javax.faces.component.behavior.ClientBehaviorHolder;
38 import javax.faces.context.FacesContext;
39 import javax.faces.validator.BeanValidator;
40 import javax.faces.validator.Validator;
41 import javax.faces.view.EditableValueHolderAttachedObjectHandler;
42 import javax.faces.view.facelets.ComponentConfig;
43 import javax.faces.view.facelets.ComponentHandler;
44 import javax.faces.view.facelets.FaceletContext;
45 import javax.faces.view.facelets.MetaRuleset;
46 import javax.faces.view.facelets.TagAttribute;
47 import javax.faces.view.facelets.TagException;
48 import javax.faces.view.facelets.TagHandlerDelegate;
49 import javax.faces.view.facelets.ValidatorHandler;
50
51 import org.apache.myfaces.util.ExternalSpecifications;
52 import org.apache.myfaces.view.facelets.AbstractFaceletContext;
53 import org.apache.myfaces.view.facelets.FaceletCompositionContext;
54 import org.apache.myfaces.view.facelets.tag.MetaRulesetImpl;
55 import org.apache.myfaces.view.facelets.tag.jsf.core.AjaxHandler;
56 import org.apache.myfaces.view.facelets.tag.jsf.core.FacetHandler;
57
58
59
60
61
62
63
64
65
66
67
68 public class ComponentTagHandlerDelegate extends TagHandlerDelegate
69 {
70 private final static Logger log = Logger.getLogger(ComponentTagHandlerDelegate.class.getName());
71
72 private final ComponentHandler _delegate;
73
74 private final String _componentType;
75
76 private final TagAttribute _id;
77
78 private final String _rendererType;
79
80 private final ComponentBuilderHandler _componentBuilderHandlerDelegate;
81
82 private final RelocatableResourceHandler _relocatableResourceHandler;
83
84 @SuppressWarnings("unchecked")
85 public ComponentTagHandlerDelegate(ComponentHandler delegate)
86 {
87 _delegate = delegate;
88
89 ComponentHandler handler = _delegate;
90 boolean found = false;
91 while(handler != null && !found)
92 {
93 if (handler instanceof ComponentBuilderHandler)
94 {
95 found = true;
96 }
97 else if (handler instanceof FacesWrapper)
98 {
99 handler = ((FacesWrapper<? extends ComponentHandler>)handler).getWrapped();
100 }
101 else
102 {
103 handler = null;
104 }
105 }
106 if (found)
107 {
108 _componentBuilderHandlerDelegate = (ComponentBuilderHandler) handler;
109 }
110 else
111 {
112 _componentBuilderHandlerDelegate = null;
113 }
114
115
116 handler = _delegate;
117 found = false;
118 while(handler != null && !found)
119 {
120 if (handler instanceof RelocatableResourceHandler)
121 {
122 found = true;
123 }
124 else if (handler instanceof FacesWrapper)
125 {
126 handler = ((FacesWrapper<? extends ComponentHandler>)handler).getWrapped();
127 }
128 else
129 {
130 handler = null;
131 }
132 }
133 if (found)
134 {
135 _relocatableResourceHandler = (RelocatableResourceHandler) handler;
136 }
137 else
138 {
139 _relocatableResourceHandler = null;
140 }
141
142 ComponentConfig delegateComponentConfig = delegate.getComponentConfig();
143 _componentType = delegateComponentConfig.getComponentType();
144 _rendererType = delegateComponentConfig.getRendererType();
145 _id = delegate.getTagAttribute("id");
146 }
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175 @SuppressWarnings("unchecked")
176 @Override
177 public void apply(FaceletContext ctx, UIComponent parent) throws IOException
178 {
179
180 if (parent == null)
181 {
182 throw new TagException(_delegate.getTag(), "Parent UIComponent was null");
183 }
184
185 FacesContext facesContext = ctx.getFacesContext();
186
187
188 String facetName = this.getFacetName(ctx, parent);
189
190
191 String id = ctx.generateUniqueId(_delegate.getTagId());
192
193
194 FaceletCompositionContext mctx = (FaceletCompositionContext) FaceletCompositionContext.getCurrentInstance(ctx);
195
196
197 UIComponent c = null;
198
199
200
201
202 UIComponent oldParent = parent;
203
204 if (mctx.isRefreshingSection())
205 {
206 if (_relocatableResourceHandler != null)
207 {
208 c = _relocatableResourceHandler.findChildByTagId(ctx, parent, id);
209 }
210 else
211 {
212 c = ComponentSupport.findChildByTagId(parent, id);
213 }
214 }
215 boolean componentFound = false;
216 if (c != null)
217 {
218 componentFound = true;
219
220 mctx.incrementUniqueComponentId();
221
222
223 if (log.isLoggable(Level.FINE))
224 {
225 log.fine(_delegate.getTag() + " Component[" + id + "] Found, marking children for cleanup");
226 }
227 mctx.markForDeletion(c);
228 }
229 else
230 {
231 c = this.createComponent(ctx);
232 if (log.isLoggable(Level.FINE))
233 {
234 log.fine(_delegate.getTag() + " Component[" + id + "] Created: " + c.getClass().getName());
235 }
236
237 _delegate.setAttributes(ctx, c);
238
239
240 c.getAttributes().put(ComponentSupport.MARK_CREATED, id);
241
242 if (facesContext.isProjectStage(ProjectStage.Development))
243 {
244 c.getAttributes().put(UIComponent.VIEW_LOCATION_KEY,
245 _delegate.getTag().getLocation());
246 }
247
248
249 if (this._id != null)
250 {
251 mctx.incrementUniqueComponentId();
252 c.setId(this._id.getValue(ctx));
253 }
254 else
255 {
256 String componentId = mctx.generateUniqueComponentId();
257 UniqueIdVendor uniqueIdVendor = mctx.getUniqueIdVendorFromStack();
258 if (uniqueIdVendor == null)
259 {
260 uniqueIdVendor = facesContext.getViewRoot();
261
262 if (uniqueIdVendor == null)
263 {
264
265
266
267 uniqueIdVendor = ComponentSupport.getViewRoot(ctx, parent);
268 }
269 }
270 if (uniqueIdVendor != null)
271 {
272
273
274 String uid = uniqueIdVendor.createUniqueId(facesContext, componentId);
275 c.setId(uid);
276 }
277 }
278
279 if (this._rendererType != null)
280 {
281 c.setRendererType(this._rendererType);
282 }
283
284
285 _delegate.onComponentCreated(ctx, c, parent);
286 }
287 c.pushComponentToEL(facesContext, c);
288
289 if (c instanceof UniqueIdVendor)
290 {
291 mctx.pushUniqueIdVendorToStack((UniqueIdVendor)c);
292 }
293
294 _delegate.applyNextHandler(ctx, c);
295
296 boolean oldProcessingEvents = facesContext.isProcessingEvents();
297
298 if (componentFound)
299 {
300 mctx.finalizeForDeletion(c);
301
302
303
304 if (mctx.isRefreshingSection())
305 {
306 facesContext.setProcessingEvents(false);
307 if (_relocatableResourceHandler != null &&
308 parent != null && !parent.equals(c.getParent()))
309 {
310
311 parent = c.getParent();
312 }
313 }
314 if (facetName == null)
315 {
316 parent.getChildren().remove(c);
317 }
318 else
319 {
320 ComponentSupport.removeFacet(ctx, parent, c, facetName);
321 }
322 if (mctx.isRefreshingSection())
323 {
324 facesContext.setProcessingEvents(oldProcessingEvents);
325 }
326
327 }
328
329
330 if (!componentFound)
331 {
332 if (c instanceof ClientBehaviorHolder && !UIComponent.isCompositeComponent(c))
333 {
334 Iterator<AjaxHandler> it = ((AbstractFaceletContext) ctx).getAjaxHandlers();
335 if (it != null)
336 {
337 while(it.hasNext())
338 {
339 it.next().applyAttachedObject(facesContext, c);
340 }
341 }
342 }
343
344 if (c instanceof EditableValueHolder)
345 {
346
347
348 addEnclosingAndDefaultValidators(ctx, mctx, facesContext, (EditableValueHolder) c);
349 }
350 }
351
352 _delegate.onComponentPopulated(ctx, c, oldParent);
353
354 if (componentFound && mctx.isRefreshingSection())
355 {
356 facesContext.setProcessingEvents(false);
357 }
358 if (facetName == null)
359 {
360 parent.getChildren().add(c);
361 }
362 else
363 {
364 ComponentSupport.addFacet(ctx, parent, c, facetName);
365 }
366 if (componentFound && mctx.isRefreshingSection())
367 {
368 facesContext.setProcessingEvents(oldProcessingEvents);
369 }
370
371 if (c instanceof UniqueIdVendor)
372 {
373 mctx.popUniqueIdVendorToStack();
374 }
375
376 c.popComponentFromEL(facesContext);
377
378 if (mctx.isMarkInitialState())
379 {
380
381 c.markInitialState();
382 }
383 }
384
385
386
387
388
389
390
391 protected final String getFacetName(FaceletContext ctx, UIComponent parent)
392 {
393 return (String) parent.getAttributes().get(FacetHandler.KEY);
394 }
395
396
397
398
399
400
401
402
403
404
405
406
407 protected UIComponent createComponent(FaceletContext ctx)
408 {
409 if (_componentBuilderHandlerDelegate != null)
410 {
411
412
413 return _componentBuilderHandlerDelegate.createComponent(ctx);
414 }
415 UIComponent c = null;
416 FacesContext faces = ctx.getFacesContext();
417 Application app = faces.getApplication();
418 if (_delegate.getBinding() != null)
419 {
420 ValueExpression ve = _delegate.getBinding().getValueExpression(ctx, Object.class);
421 if (this._rendererType == null)
422 {
423 c = app.createComponent(ve, faces, this._componentType);
424 }
425 else
426 {
427 c = app.createComponent(ve, faces, this._componentType, this._rendererType);
428 }
429 if (c != null)
430 {
431 c.setValueExpression("binding", ve);
432
433 if (!ve.isReadOnly(faces.getELContext()))
434 {
435 ComponentSupport.getViewRoot(ctx, c).getAttributes().put("oam.CALL_PRE_DISPOSE_VIEW", Boolean.TRUE);
436 c.subscribeToEvent(PreDisposeViewEvent.class, new ClearBindingValueExpressionListener());
437 }
438 }
439 }
440 else
441 {
442
443
444
445
446
447
448
449
450
451
452
453
454 c = app.createComponent(faces, this._componentType, this._rendererType);
455
456 }
457 return c;
458 }
459
460
461
462
463
464
465
466
467
468 protected String getId(FaceletContext ctx)
469 {
470 if (this._id != null)
471 {
472 return this._id.getValue(ctx);
473 }
474 return ctx.generateUniqueId(_delegate.getTagId());
475 }
476
477 @Override
478 public MetaRuleset createMetaRuleset(Class type)
479 {
480 MetaRuleset m = new MetaRulesetImpl(_delegate.getTag(), type);
481
482 m.ignore("binding").ignore("id");
483
484
485 m.addRule(ComponentRule.INSTANCE);
486
487
488 if (ActionSource.class.isAssignableFrom(type))
489 {
490 m.addRule(ActionSourceRule.INSTANCE);
491 }
492
493
494 if (ValueHolder.class.isAssignableFrom(type))
495 {
496 m.addRule(ValueHolderRule.INSTANCE);
497
498
499 if (EditableValueHolder.class.isAssignableFrom(type))
500 {
501 m.ignore("submittedValue");
502 m.ignore("valid");
503 m.addRule(EditableValueHolderRule.INSTANCE);
504 }
505 }
506
507 return m;
508 }
509
510
511
512
513
514
515
516
517
518
519 private void addEnclosingAndDefaultValidators(FaceletContext ctx,
520 FaceletCompositionContext mctx,
521 FacesContext context,
522 EditableValueHolder component)
523 {
524
525 Iterator<Map.Entry<String, EditableValueHolderAttachedObjectHandler>> enclosingValidatorIds =
526 mctx.getEnclosingValidatorIdsAndHandlers();
527 if (enclosingValidatorIds != null)
528 {
529 while (enclosingValidatorIds.hasNext())
530 {
531 Map.Entry<String, EditableValueHolderAttachedObjectHandler> entry = enclosingValidatorIds.next();
532 addEnclosingValidator(ctx, mctx, context, component, entry.getKey(), entry.getValue());
533 }
534 }
535
536 Map<String, String> defaultValidators = context.getApplication().getDefaultValidatorInfo();
537 if (defaultValidators != null && defaultValidators.size() != 0)
538 {
539 for (Map.Entry<String, String> entry : defaultValidators.entrySet())
540 {
541 if (!mctx.containsEnclosingValidatorId(entry.getKey()))
542 {
543 addDefaultValidator(ctx, mctx, context, component, entry.getKey(), entry.getValue());
544 }
545 }
546 }
547 }
548
549 private void addDefaultValidator(FaceletContext ctx, FaceletCompositionContext mctx, FacesContext context,
550 EditableValueHolder component, String validatorId, String validatorClassName)
551 {
552 Validator enclosingValidator = null;
553
554 if (validatorClassName == null)
555 {
556
557
558
559 enclosingValidator = context.getApplication().createValidator(validatorId);
560 validatorClassName = enclosingValidator.getClass().getName();
561 }
562
563
564
565 Validator validator = null;
566 for (Validator v : component.getValidators())
567 {
568 if (v.getClass().getName().equals(validatorClassName))
569 {
570
571 validator = v;
572 break;
573 }
574 }
575
576 if (validator == null)
577 {
578 if (shouldAddDefaultValidator(ctx, mctx, context, component, validatorId))
579 {
580 if (enclosingValidator != null)
581 {
582
583 validator = enclosingValidator;
584 }
585 else
586 {
587
588 validator = context.getApplication().createValidator(validatorId);
589 }
590
591 component.addValidator(validator);
592 }
593 else
594 {
595
596 return;
597 }
598 }
599
600
601 if (validator instanceof BeanValidator)
602 {
603 BeanValidator beanValidator = (BeanValidator) validator;
604
605
606 String validationGroups = beanValidator.getValidationGroups();
607 if (validationGroups == null
608 || validationGroups.matches(BeanValidator.EMPTY_VALIDATION_GROUPS_PATTERN))
609 {
610
611
612
613
614
615
616
617
618
619
620
621 validationGroups = javax.validation.groups.Default.class.getName();
622
623 beanValidator.setValidationGroups(validationGroups);
624 }
625 }
626 }
627
628
629
630
631
632
633
634
635
636
637 @SuppressWarnings("unchecked")
638 private boolean shouldAddDefaultValidator(FaceletContext ctx, FaceletCompositionContext mctx,
639 FacesContext facesContext,
640 EditableValueHolder component,
641 String validatorId)
642 {
643
644 List<String> exclusionList
645 = (List<String>) ((UIComponent) component).getAttributes()
646 .get(ValidatorTagHandlerDelegate.VALIDATOR_ID_EXCLUSION_LIST_KEY);
647 if (exclusionList != null)
648 {
649 for (String excludedId : exclusionList)
650 {
651 if (excludedId.equals(validatorId))
652 {
653 return false;
654 }
655 }
656 }
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672 Iterator<Map.Entry<String, EditableValueHolderAttachedObjectHandler>> enclosingValidatorIds =
673 mctx.getEnclosingValidatorIdsAndHandlers();
674 if (enclosingValidatorIds != null)
675 {
676 while (enclosingValidatorIds.hasNext())
677 {
678 Map.Entry<String, EditableValueHolderAttachedObjectHandler> entry = enclosingValidatorIds.next();
679 boolean validatorIdAvailable = entry.getKey() != null && !"".equals(entry.getKey());
680 if (validatorIdAvailable && entry.getKey().equals(validatorId))
681 {
682 if (((ValidatorHandler)((FacesWrapper<ValidatorHandler>)entry.getValue()).getWrapped())
683 .isDisabled(ctx))
684 {
685 return false;
686 }
687 }
688 }
689 }
690
691
692 if (validatorId.equals(BeanValidator.VALIDATOR_ID))
693 {
694 if (!ExternalSpecifications.isBeanValidationAvailable())
695 {
696
697
698
699 log.log(Level.WARNING, "Bean validation is not available on the " +
700 "classpath, thus the BeanValidator will not be added for " +
701 "the component " + component);
702 return false;
703 }
704 }
705
706
707 return true;
708 }
709
710 private void addEnclosingValidator(FaceletContext ctx, FaceletCompositionContext mctx, FacesContext context,
711 EditableValueHolder component, String validatorId,
712 EditableValueHolderAttachedObjectHandler attachedObjectHandler)
713 {
714 if (shouldAddEnclosingValidator(mctx, context, component, validatorId))
715 {
716 if (attachedObjectHandler != null)
717 {
718 attachedObjectHandler.applyAttachedObject(context, (UIComponent) component);
719 }
720 else
721 {
722 Validator validator = null;
723
724 validator = context.getApplication().createValidator(validatorId);
725
726
727 if (validator instanceof BeanValidator)
728 {
729 BeanValidator beanValidator = (BeanValidator) validator;
730
731
732 String validationGroups = beanValidator.getValidationGroups();
733 if (validationGroups == null
734 || validationGroups.matches(BeanValidator.EMPTY_VALIDATION_GROUPS_PATTERN))
735 {
736
737
738
739
740
741
742
743
744
745
746
747 validationGroups = javax.validation.groups.Default.class.getName();
748
749 beanValidator.setValidationGroups(validationGroups);
750 }
751 }
752
753
754 component.addValidator(validator);
755 }
756 }
757 }
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772 @SuppressWarnings("unchecked")
773 private boolean shouldAddEnclosingValidator(FaceletCompositionContext mctx,
774 FacesContext facesContext,
775 EditableValueHolder component,
776 String validatorId)
777 {
778
779 List<String> exclusionList = (List<String>) ((UIComponent) component)
780 .getAttributes()
781 .get(ValidatorTagHandlerDelegate.VALIDATOR_ID_EXCLUSION_LIST_KEY);
782 if (exclusionList != null)
783 {
784 for (String excludedId : exclusionList)
785 {
786 if (excludedId.equals(validatorId))
787 {
788 return false;
789 }
790 }
791 }
792
793
794 if (validatorId.equals(BeanValidator.VALIDATOR_ID))
795 {
796 if (!ExternalSpecifications.isBeanValidationAvailable())
797 {
798
799
800
801 log.log(Level.WARNING,
802 "Bean validation is not available on the "
803 + "classpath, thus the BeanValidator will not be added for "
804 + "the component " + component);
805 return false;
806 }
807 }
808
809
810 return true;
811 }
812 }