1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.myfaces.trinidad.component;
20
21 import java.io.ByteArrayOutputStream;
22 import java.io.InputStream;
23 import java.io.IOException;
24 import java.io.ObjectOutputStream;
25
26 import java.net.URL;
27 import java.util.Iterator;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.NoSuchElementException;
31 import java.util.Properties;
32
33 import javax.el.ELContext;
34 import javax.el.ELException;
35 import javax.el.MethodExpression;
36 import javax.el.ValueExpression;
37
38 import javax.faces.component.NamingContainer;
39 import javax.faces.component.UIComponent;
40 import javax.faces.context.FacesContext;
41 import javax.faces.el.EvaluationException;
42 import javax.faces.el.MethodBinding;
43 import javax.faces.el.ValueBinding;
44 import javax.faces.event.AbortProcessingException;
45 import javax.faces.event.FacesEvent;
46 import javax.faces.event.FacesListener;
47 import javax.faces.render.RenderKit;
48 import javax.faces.render.Renderer;
49
50 import org.apache.myfaces.trinidad.bean.FacesBean;
51 import org.apache.myfaces.trinidad.bean.FacesBeanFactory;
52 import org.apache.myfaces.trinidad.bean.PropertyKey;
53 import org.apache.myfaces.trinidad.bean.util.StateUtils;
54 import org.apache.myfaces.trinidad.bean.util.ValueMap;
55 import org.apache.myfaces.trinidad.change.AttributeComponentChange;
56 import org.apache.myfaces.trinidad.context.RequestContext;
57 import org.apache.myfaces.trinidad.event.AttributeChangeEvent;
58 import org.apache.myfaces.trinidad.event.AttributeChangeListener;
59 import org.apache.myfaces.trinidad.logging.TrinidadLogger;
60 import org.apache.myfaces.trinidad.render.ExtendedRenderer;
61 import org.apache.myfaces.trinidad.render.LifecycleRenderer;
62
63
64 /**
65 * Base implementation of components for all of Trinidad. UIXComponentBase
66 * offers a number of features not supplied by the standard UIComponentBase
67 * class:
68 * <ul>
69 * <li>Use of FacesBean for better and easier state saving</li>
70 * <li>Support of the LifecycleRenderer class for greater Renderer
71 * control over the lifecycle</li>
72 * <li>Built-in support for both the "partialTriggers" attribute
73 * (declarative support for being a PPR target) and for triggering
74 * such components (for being a the source of a PPR-causing event).</li>
75 * </ul>
76 * <h3>FacesBean and UIXComponentBase</h3>
77 * <p>
78 * UIXComponentBase differs from UIXComponent most particularly
79 * in its use of FacesBeans to store all state. This offers
80 * a number of advantages:
81 * <ul>
82 * <li>Subclassers - if they use FacesBean for their state as well -
83 * do not need to write overrides of saveState() and restoreState().
84 * </li>
85 * <li>State is optimized by default</li>
86 * <li>Future optimizations - partly exposed today with
87 * markInitialState() - can offer major state saving improvements.
88 * </ul>
89 * </p>
90 */
91
92
93 abstract public class UIXComponentBase extends UIXComponent
94 {
95
96
97 static private final TrinidadLogger _LOG = TrinidadLogger.createTrinidadLogger(UIXComponentBase.class);
98
99 static public final FacesBean.Type TYPE = _createType();
100 static public final PropertyKey ID_KEY =
101 TYPE.registerKey("id", String.class, PropertyKey.CAP_NOT_BOUND);
102 static private final PropertyKey _GENERATED_ID_KEY =
103 TYPE.registerKey("_genId", String.class, PropertyKey.CAP_NOT_BOUND);
104 static public final PropertyKey RENDERED_KEY =
105 TYPE.registerKey("rendered", Boolean.class, Boolean.TRUE);
106 static public final PropertyKey BINDING_KEY =
107 TYPE.registerKey("binding");
108 static public final PropertyKey TRANSIENT_KEY =
109 TYPE.registerKey("transient", Boolean.class,
110 PropertyKey.CAP_NOT_BOUND |
111 PropertyKey.CAP_TRANSIENT);
112 static public final PropertyKey RENDERER_TYPE_KEY =
113 TYPE.registerKey("rendererType", String.class, PropertyKey.CAP_NOT_BOUND);
114 static private final PropertyKey _LISTENERS_KEY =
115 TYPE.registerKey("listeners", FacesListener[].class, PropertyKey.CAP_LIST);
116 static private final PropertyKey _ATTRIBUTE_CHANGE_LISTENER_KEY =
117 TYPE.registerKey("attributeChangeListener", MethodExpression.class);
118
119
120
121
122 static
123 {
124
125
126
127
128 TYPE.registerKey("javax.faces.webapp.COMPONENT_IDS",
129 List.class,
130 PropertyKey.CAP_NOT_BOUND);
131 TYPE.registerKey("javax.faces.webapp.FACET_NAMES",
132 List.class,
133 PropertyKey.CAP_NOT_BOUND);
134 TYPE.lock();
135 }
136
137 public UIXComponentBase()
138 {
139 }
140
141 public UIXComponentBase(String rendererType)
142 {
143 setRendererType(rendererType);
144 }
145
146 protected FacesBean createFacesBean(
147 String rendererType)
148 {
149 FacesBean bean = FacesBeanFactory.createFacesBean(getClass(),
150 rendererType);
151 UIXFacesBean uixBean = (UIXFacesBean) bean;
152 uixBean.init(this, getBeanType());
153 return uixBean;
154 }
155
156 protected PropertyKey getPropertyKey(String name)
157 {
158 PropertyKey key = getBeanType().findKey(name);
159 if (key == null)
160 key = PropertyKey.createPropertyKey(name);
161
162 return key;
163 }
164
165 protected FacesBean.Type getBeanType()
166 {
167 return TYPE;
168 }
169
170 @Override
171 public FacesBean getFacesBean()
172 {
173 if (_facesBean == null)
174 _init(null);
175
176 return _facesBean;
177 }
178
179 @Override
180 public String getContainerClientId(FacesContext context, UIComponent child)
181 {
182 return getContainerClientId(context);
183 }
184
185 @Override
186 public void addAttributeChangeListener(AttributeChangeListener acl)
187 {
188 addFacesListener(acl);
189 }
190
191 @Override
192 public void removeAttributeChangeListener(AttributeChangeListener acl)
193 {
194 removeFacesListener(acl);
195 }
196
197 @Override
198 public AttributeChangeListener[] getAttributeChangeListeners()
199 {
200 return (AttributeChangeListener[])
201 getFacesListeners(AttributeChangeListener.class);
202 }
203
204 @Override
205 public void setAttributeChangeListener(MethodExpression mb)
206 {
207 setProperty(_ATTRIBUTE_CHANGE_LISTENER_KEY, mb);
208 }
209
210 @Deprecated
211 public void setAttributeChangeListener(MethodBinding mb)
212 {
213 setAttributeChangeListener(adaptMethodBinding(mb));
214 }
215
216 @Override
217 public MethodExpression getAttributeChangeListener()
218 {
219 return (MethodExpression) getProperty(_ATTRIBUTE_CHANGE_LISTENER_KEY);
220 }
221
222
223 @Override
224 public ValueExpression getValueExpression(String name)
225 {
226 if (name == null)
227 throw new NullPointerException();
228
229 PropertyKey key = getPropertyKey(name);
230
231
232
233
234 if (!key.getSupportsBinding())
235 return null;
236
237 return getFacesBean().getValueExpression(key);
238 }
239
240 @Override
241 public void setValueExpression(String name,
242 ValueExpression expression)
243 {
244 if (name == null)
245 throw new NullPointerException();
246
247 if ((expression != null) && expression.isLiteralText())
248 {
249 ELContext context =
250 FacesContext.getCurrentInstance().getELContext();
251 getAttributes().put(name, expression.getValue(context));
252 }
253 else
254 {
255 PropertyKey key = getPropertyKey(name);
256 getFacesBean().setValueExpression(key, expression);
257 }
258 }
259
260
261
262 /**
263 */
264 @Override
265 public ValueBinding getValueBinding(String name)
266 {
267 if (name == null)
268 throw new NullPointerException();
269
270 PropertyKey key = getPropertyKey(name);
271
272
273
274
275 if (!key.getSupportsBinding())
276 return null;
277
278 return getFacesBean().getValueBinding(key);
279 }
280
281
282 @Override
283 public void setValueBinding(String name, ValueBinding binding)
284 {
285 if (name == null)
286 throw new NullPointerException();
287
288 PropertyKey key = getPropertyKey(name);
289 getFacesBean().setValueBinding(key, binding);
290 }
291
292
293 @Override
294 public Map<String, Object> getAttributes()
295 {
296 if (_attributes == null)
297 _init(null);
298
299 return _attributes;
300 }
301
302
303
304
305
306 @Override
307 public String getClientId(FacesContext context)
308 {
309
310
311
312 String clientId = getId();
313 if (clientId == null)
314 {
315 clientId = (String) getProperty(_GENERATED_ID_KEY);
316 if (clientId == null)
317 {
318 clientId = context.getViewRoot().createUniqueId();
319 setProperty(_GENERATED_ID_KEY, clientId);
320 }
321 }
322
323
324 UIComponent containerComponent = getParent();
325 while (null != containerComponent)
326 {
327 if (containerComponent instanceof NamingContainer)
328 {
329 String contClientId;
330
331
332 if (containerComponent instanceof UIXComponent)
333 contClientId = ((UIXComponent)containerComponent).getContainerClientId(context, this);
334 else
335 contClientId = containerComponent.getContainerClientId(context);
336
337 StringBuilder bld = __getSharedStringBuilder();
338 bld.append(contClientId).append(NamingContainer.SEPARATOR_CHAR).append(clientId);
339 clientId = bld.toString();
340 break;
341 }
342
343 containerComponent = containerComponent.getParent();
344 }
345
346 Renderer renderer = getRenderer(context);
347 if (null != renderer)
348 clientId = renderer.convertClientId(context, clientId);
349
350 return clientId;
351 }
352
353
354 /**
355 * Gets the identifier for the component.
356 */
357 @Override
358 public String getId()
359 {
360 return (String) getProperty(ID_KEY);
361 }
362
363
364 /**
365 * Sets the identifier for the component. The identifier
366 * must follow a subset of the syntax allowed in HTML:
367 * <ul>
368 * <li>Must not be a zero-length String.</li>
369 * <li>First character must be an ASCII letter (A-Za-z) or an underscore ('_').</li>
370 * <li>Subsequent characters must be an ASCII letter or digit (A-Za-z0-9), an underscore ('_'), or a dash ('-').
371 * </ul>
372 */
373 @Override
374 public void setId(String id)
375 {
376
377
378 _validateId(id);
379
380
381 if (id != null)
382 setProperty(_GENERATED_ID_KEY, null);
383
384 setProperty(ID_KEY, id);
385 }
386
387
388
389 @Override
390 abstract public String getFamily();
391
392
393 @Override
394 public UIComponent getParent()
395 {
396 return _parent;
397 }
398
399
400 /**
401 * <p>Set the parent <code>UIComponent</code> of this
402 * <code>UIComponent</code>.</p>
403 *
404 * @param parent The new parent, or <code>null</code> for the root node
405 * of a component tree
406 */
407 @Override
408 public void setParent(UIComponent parent)
409 {
410 _parent = parent;
411 }
412
413
414 @Override
415 public boolean isRendered()
416 {
417 return getBooleanProperty(RENDERED_KEY, true);
418 }
419
420
421 @Override
422 public void setRendered(boolean rendered)
423 {
424 setBooleanProperty(RENDERED_KEY, rendered);
425 }
426
427 public boolean isTransient()
428 {
429 return getBooleanProperty(TRANSIENT_KEY, false);
430 }
431
432 public void setTransient(boolean newTransient)
433 {
434 setBooleanProperty(TRANSIENT_KEY, newTransient);
435 }
436
437 @Override
438 public String getRendererType()
439 {
440
441
442
443
444 if (_facesBean == null)
445 return null;
446
447 return (String) getProperty(RENDERER_TYPE_KEY);
448 }
449
450 @Override
451 public void setRendererType(String rendererType)
452 {
453 String oldRendererType = getRendererType();
454 if (oldRendererType == null)
455 {
456 if (rendererType == null)
457 return;
458 }
459 else if (oldRendererType.equals(rendererType))
460 {
461 return;
462 }
463
464
465 _init(rendererType);
466 setProperty(RENDERER_TYPE_KEY, rendererType);
467 }
468
469
470 @Override
471 public boolean getRendersChildren()
472 {
473 Renderer renderer = getRenderer(getFacesContext());
474 if (renderer == null)
475 return false;
476
477 return renderer.getRendersChildren();
478 }
479
480
481
482
483
484
485
486
487 @Override
488 public UIComponent findComponent(String id)
489 {
490 if (id == null)
491 throw new NullPointerException();
492
493 if ("".equals(id))
494 throw new IllegalArgumentException();
495
496 UIComponent from = this;
497
498
499 if (id.charAt(0) == NamingContainer.SEPARATOR_CHAR)
500 {
501 id = id.substring(1);
502 while (from.getParent() != null)
503 from = from.getParent();
504 }
505
506 else if (this instanceof NamingContainer)
507 {
508 ;
509 }
510
511 else
512 {
513 while (from.getParent() != null)
514 {
515 from = from.getParent();
516 if (from instanceof NamingContainer)
517 break;
518 }
519 }
520
521
522 String searchId;
523 int separatorIndex = id.indexOf(NamingContainer.SEPARATOR_CHAR);
524 if (separatorIndex < 0)
525 searchId = id;
526 else
527 searchId = id.substring(0, separatorIndex);
528
529 if (searchId.equals(from.getId()))
530 {
531
532 ;
533 }
534 else
535 {
536 from = _findInsideOf(from, searchId);
537 }
538
539
540 if (separatorIndex < 0)
541 {
542 return from;
543 }
544
545
546 else
547 {
548 if (from == null)
549 return null;
550
551 if (!(from instanceof NamingContainer))
552 throw new IllegalArgumentException();
553 return from.findComponent(id.substring(separatorIndex + 1));
554 }
555 }
556
557
558
559 /**
560 * <p>Create (if necessary) and return a List of the children associated
561 * with this component.</p>
562 */
563 @Override
564 public List<UIComponent> getChildren()
565 {
566 if (_children == null)
567 _children = new ChildArrayList(this);
568
569 return _children;
570 }
571
572 @Override
573 public int getChildCount()
574 {
575 if (_children == null)
576 return 0;
577 return getChildren().size();
578 }
579
580
581 /**
582 * <p>Create (if necessary) and return a Map of the facets associated
583 * with this component.</p>
584 */
585 @Override
586 public Map<String, UIComponent> getFacets()
587 {
588
589 if (_facets == null)
590 _facets = new FacetHashMap(this);
591
592 return _facets;
593 }
594
595
596 @Override
597 public UIComponent getFacet(String facetName)
598 {
599 if (facetName == null)
600 throw new NullPointerException();
601 if (_facets == null)
602 return null;
603 return getFacets().get(facetName);
604 }
605
606
607 /**
608 * Returns an Iterator over the names of all facets.
609 * Unlike getFacets().keySet().iterator(), this does
610 * not require instantiating a Map if there are
611 * no facets. (Note that this is not part of the
612 * UIComponent API.)
613 */
614 public Iterator<String> getFacetNames()
615 {
616 if (_facets == null)
617 return _EMPTY_STRING_ITERATOR;
618 return _facets.keySet().iterator();
619 }
620
621 @Override
622 public Iterator<UIComponent> getFacetsAndChildren()
623 {
624
625 if (_facets == null)
626 {
627 if (_children == null)
628 return _EMPTY_UICOMPONENT_ITERATOR;
629
630 return _children.iterator();
631 }
632 else
633 {
634 if (_children == null)
635 return _facets.values().iterator();
636 }
637
638 return new CompositeIterator<UIComponent>(_children.iterator(), _facets.values().iterator());
639 }
640
641
642
643 @Override
644 public void broadcast(FacesEvent event)
645 throws AbortProcessingException
646 {
647 if (event == null)
648 throw new NullPointerException();
649
650 if (_LOG.isFine())
651 _LOG.fine("Broadcasting event " + event + " to " + this);
652
653 UIComponent component = event.getComponent();
654 if (component != null)
655 {
656 RequestContext adfContext = RequestContext.getCurrentInstance();
657 if (adfContext != null)
658 adfContext.partialUpdateNotify(component);
659 }
660
661 Iterator<FacesListener> iter =
662 (Iterator<FacesListener>)getFacesBean().entries(_LISTENERS_KEY);
663
664 while (iter.hasNext())
665 {
666 FacesListener listener = iter.next();
667 if (event.isAppropriateListener(listener))
668 {
669 event.processListener(listener);
670 }
671 }
672
673 if (event instanceof AttributeChangeEvent)
674 {
675 broadcastToMethodExpression(event, getAttributeChangeListener());
676 }
677 }
678
679
680
681
682
683 @Override
684 public void decode(FacesContext context)
685 {
686 if (context == null)
687 throw new NullPointerException();
688
689
690 Map<String, Object> attrs = getAttributes();
691 Object triggers = attrs.get("partialTriggers");
692 if (triggers instanceof String[])
693 {
694 RequestContext adfContext = RequestContext.getCurrentInstance();
695 if (adfContext != null)
696 adfContext.addPartialTriggerListeners(this, (String[]) triggers);
697 }
698
699 __rendererDecode(context);
700 }
701
702 @Override
703 public void encodeBegin(FacesContext context) throws IOException
704 {
705 if (context == null)
706 throw new NullPointerException();
707
708 if (!isRendered())
709 return;
710
711 _cacheRenderer(context);
712 Renderer renderer = getRenderer(context);
713
714 if (renderer != null)
715 {
716 renderer.encodeBegin(context, this);
717 }
718 }
719
720 @Override
721 public void encodeChildren(FacesContext context) throws IOException
722 {
723 if (context == null)
724 throw new NullPointerException();
725
726 if (!isRendered())
727 return;
728
729 Renderer renderer = getRenderer(context);
730
731 if (renderer != null)
732 {
733 renderer.encodeChildren(context, this);
734 }
735 }
736
737 @Override
738 public void encodeEnd(FacesContext context) throws IOException
739 {
740 if (context == null)
741 throw new NullPointerException();
742
743 if (isRendered())
744 {
745 Renderer renderer = getRenderer(context);
746
747 if (renderer != null)
748 {
749 renderer.encodeEnd(context, this);
750 }
751 }
752 }
753
754 /**
755 * Encodes a component and all of its children, whether
756 * getRendersChildren() is true or false. When rendersChildren
757 * is false, each child whose "rendered" property is true
758 * will be sequentially rendered; facets will be ignored.
759 */
760 @Override
761 public void encodeAll(FacesContext context) throws IOException
762 {
763 if (context == null)
764 throw new NullPointerException();
765
766
767
768
769 __encodeRecursive(context, this);
770 }
771
772 @Override
773 public void queueEvent(FacesEvent event)
774 {
775 if (event == null)
776 throw new NullPointerException();
777
778 UIComponent parent = getParent();
779 if (parent == null)
780 throw new IllegalStateException();
781
782 parent.queueEvent(event);
783 }
784
785
786
787 @Override
788 public void processDecodes(FacesContext context)
789 {
790 if (context == null)
791 throw new NullPointerException();
792
793 if (!isRendered())
794 return;
795
796
797 decodeChildren(context);
798
799
800 decode(context);
801
802 }
803
804 @Override
805 public void processValidators(FacesContext context)
806 {
807 if (context == null)
808 throw new NullPointerException();
809
810 if (!isRendered())
811 return;
812
813
814 validateChildren(context);
815 }
816
817 @Override
818 public void processUpdates(FacesContext context)
819 {
820 if (context == null)
821 throw new NullPointerException();
822
823 if (!isRendered())
824 return;
825
826
827 updateChildren(context);
828 }
829
830 @Override
831 public Object processSaveState(FacesContext context)
832 {
833 if (context == null)
834 throw new NullPointerException();
835
836 if (_LOG.isFiner())
837 _LOG.finer("processSaveState() on " + this);
838
839 Object state = null;
840
841 try
842 {
843 if (((_children == null) || _children.isEmpty()) &&
844 ((_facets == null) || _facets.isEmpty()))
845 {
846 state = saveState(context);
847 }
848 else
849 {
850 TreeState treeState = new TreeState();
851 treeState.saveState(context, this);
852 if (treeState.isEmpty())
853 state = null;
854
855 state = treeState;
856 }
857 }
858 catch (RuntimeException e)
859 {
860 _LOG.warning(_LOG.getMessage("COMPONENT_CHILDREN_SAVED_STATE_FAILED", this));
861
862 throw e;
863 }
864
865
866
867
868
869
870
871 if (StateUtils.checkComponentStateSerialization(context))
872 {
873 try
874 {
875 new ObjectOutputStream(new ByteArrayOutputStream()).writeObject(state);
876 }
877 catch (IOException e)
878 {
879 throw new RuntimeException(_LOG.getMessage("COMPONENT_SAVED_STATE_FAILED", this), e);
880 }
881 }
882
883 return state;
884 }
885
886
887
888
889
890 @Override
891 public void processRestoreState(FacesContext context, Object state)
892 {
893 if (context == null)
894 throw new NullPointerException();
895
896 if (_LOG.isFiner())
897 _LOG.finer("processRestoreState() on " + this);
898
899
900 if (state instanceof TreeState)
901 {
902 ((TreeState) state).restoreState(context, this);
903 }
904
905
906 else
907 {
908 restoreState(context, state);
909 }
910 }
911
912 @Override
913 public void markInitialState()
914 {
915
916
917
918 getFacesBean().markInitialState();
919 }
920
921 public Object saveState(FacesContext context)
922 {
923 return getFacesBean().saveState(context);
924 }
925
926 public void restoreState(FacesContext context, Object stateObj)
927 {
928 getFacesBean().restoreState(context, stateObj);
929 }
930
931
932 @Override
933 public String toString()
934 {
935 String className = getClass().getName();
936 int periodIndex = className.lastIndexOf('.');
937 if (periodIndex >= 0)
938 className = className.substring(periodIndex + 1);
939
940 return className + "[" + getFacesBean().toString() + ", id=" + getId() + "]";
941 }
942
943 /**
944 * <p>Return the {@link FacesContext} instance for the current request.</p>
945 */
946 @Override
947 protected FacesContext getFacesContext()
948 {
949
950
951
952 return FacesContext.getCurrentInstance();
953 }
954
955
956 /**
957 * Delegates to LifecycleRenderer, if present,
958 * otherwise calls decodeChildrenImpl.
959 *
960 * @param context the current FacesContext
961 */
962 final protected void decodeChildren(FacesContext context)
963 {
964 LifecycleRenderer renderer = getLifecycleRenderer(context);
965
966 if (renderer != null)
967 {
968 if (renderer.decodeChildren(context, this))
969 return;
970 }
971
972 decodeChildrenImpl(context);
973 }
974
975 /**
976 * Calls processDecodes on all facets and children of this
977 * component.
978 * @param context the current FacesContext
979 */
980 protected void decodeChildrenImpl(FacesContext context)
981 {
982 Iterator<UIComponent> kids = getFacetsAndChildren();
983 while (kids.hasNext())
984 {
985 UIComponent kid = kids.next();
986 kid.processDecodes(context);
987 }
988 }
989
990
991 /**
992 * Delegates to LifecycleRenderer, if present,
993 * otherwise calls validateChildrenImpl.
994 *
995 * @param context the current FacesContext
996 */
997 final protected void validateChildren(FacesContext context)
998 {
999 LifecycleRenderer renderer = getLifecycleRenderer(context);
1000
1001 if (renderer != null)
1002 {
1003 if (renderer.validateChildren(context, this))
1004 return;
1005 }
1006
1007 validateChildrenImpl(context);
1008 }
1009
1010 /**
1011 * Calls processValidators on all facets and children of this
1012 * component.
1013 * @param context the current FacesContext
1014 */
1015 protected void validateChildrenImpl(FacesContext context)
1016 {
1017
1018 Iterator<UIComponent> kids = getFacetsAndChildren();
1019 while (kids.hasNext())
1020 {
1021 UIComponent kid = kids.next();
1022 kid.processValidators(context);
1023 }
1024 }
1025
1026
1027 /**
1028 * Delegates to LifecycleRenderer, if present,
1029 * otherwise calls upateChildrenImpl.
1030 *
1031 * @param context the current FacesContext
1032 */
1033 final protected void updateChildren(FacesContext context)
1034 {
1035 LifecycleRenderer renderer = getLifecycleRenderer(context);
1036
1037 if (renderer != null)
1038 {
1039 if (renderer.updateChildren(context, this))
1040 return;
1041 }
1042
1043 updateChildrenImpl(context);
1044 }
1045
1046 protected void updateChildrenImpl(FacesContext context)
1047 {
1048
1049 Iterator<UIComponent> kids = getFacetsAndChildren();
1050 while (kids.hasNext())
1051 {
1052 UIComponent kid = kids.next();
1053 kid.processUpdates(context);
1054 }
1055 }
1056
1057 @Override
1058 protected void addFacesListener(FacesListener listener)
1059 {
1060 if (listener == null)
1061 throw new NullPointerException();
1062
1063 getFacesBean().addEntry(_LISTENERS_KEY, listener);
1064 }
1065
1066 @Override
1067 protected void removeFacesListener(FacesListener listener)
1068 {
1069 if (listener == null)
1070 throw new NullPointerException();
1071
1072 getFacesBean().removeEntry(_LISTENERS_KEY, listener);
1073 }
1074
1075 @Override
1076 protected FacesListener[] getFacesListeners(Class clazz)
1077 {
1078 if (clazz == null)
1079 throw new NullPointerException();
1080
1081 if (!FacesListener.class.isAssignableFrom(clazz))
1082 throw new IllegalArgumentException();
1083
1084 return (FacesListener[])
1085 getFacesBean().getEntries(_LISTENERS_KEY, clazz);
1086 }
1087
1088 protected void addAttributeChange(
1089 String attributeName,
1090 Object attributeValue)
1091 {
1092 AttributeComponentChange aa =
1093 new AttributeComponentChange(attributeName, attributeValue);
1094 RequestContext adfContext = RequestContext.getCurrentInstance();
1095 adfContext.getChangeManager().addComponentChange(getFacesContext(), this, aa);
1096 }
1097
1098 void __rendererDecode(FacesContext context)
1099 {
1100 _cacheRenderer(context);
1101 Renderer renderer = getRenderer(context);
1102
1103 if (renderer != null)
1104 {
1105 renderer.decode(context, this);
1106 }
1107 }
1108
1109 private void _cacheRenderer(FacesContext context)
1110 {
1111 Renderer renderer = _getRendererImpl(context);
1112 _cachedRenderer = renderer;
1113
1114
1115 if (renderer instanceof LifecycleRenderer)
1116 {
1117 _cachedLifecycleRenderer = (LifecycleRenderer)renderer;
1118 }
1119 else
1120 {
1121 _cachedLifecycleRenderer = null;
1122 }
1123 }
1124
1125 private Renderer _getRendererImpl(FacesContext context)
1126 {
1127 String rendererType = getRendererType();
1128 if (rendererType != null)
1129 {
1130 RenderKit renderKit = context.getRenderKit();
1131 Renderer renderer = renderKit.getRenderer(getFamily(), rendererType);
1132 if (renderer == null)
1133 {
1134 _LOG.warning("CANNOT_FIND_RENDERER", new Object[]{this, rendererType});
1135 }
1136
1137 return renderer;
1138 }
1139
1140 return null;
1141 }
1142
1143 private LifecycleRenderer _getLifecycleRendererImpl(FacesContext context)
1144 {
1145 Renderer renderer = _getRendererImpl(context);
1146 if (renderer instanceof LifecycleRenderer)
1147 {
1148 return (LifecycleRenderer)renderer;
1149 }
1150
1151 return null;
1152 }
1153
1154 @Override
1155 protected Renderer getRenderer(FacesContext context)
1156 {
1157 Renderer renderer = _cachedRenderer;
1158 if (renderer != _UNDEFINED_RENDERER)
1159 return renderer;
1160
1161 return _getRendererImpl(context);
1162 }
1163
1164 protected LifecycleRenderer getLifecycleRenderer(FacesContext context)
1165 {
1166 LifecycleRenderer renderer = _cachedLifecycleRenderer;
1167 if (renderer != _UNDEFINED_LIFECYCLE_RENDERER)
1168 return renderer;
1169
1170 return _getLifecycleRendererImpl(context);
1171
1172 }
1173
1174 protected void setProperty(PropertyKey key, Object value)
1175 {
1176 getFacesBean().setProperty(key, value);
1177 }
1178
1179 protected Object getProperty(PropertyKey key)
1180 {
1181 return getFacesBean().getProperty(key);
1182 }
1183
1184 protected void setBooleanProperty(PropertyKey key, boolean value)
1185 {
1186 getFacesBean().setProperty(key, value ? Boolean.TRUE : Boolean.FALSE);
1187 }
1188
1189 protected boolean getBooleanProperty(PropertyKey key, boolean defaultValue)
1190 {
1191 Object o = getFacesBean().getProperty(key);
1192 if (defaultValue)
1193 return !Boolean.FALSE.equals(o);
1194 else
1195 return Boolean.TRUE.equals(o);
1196 }
1197
1198 protected void setIntProperty(PropertyKey key, int value)
1199 {
1200 getFacesBean().setProperty(key, Integer.valueOf(value));
1201 }
1202
1203 protected int getIntProperty(PropertyKey key, int defaultValue)
1204 {
1205 Number n = (Number) getFacesBean().getProperty(key);
1206 if (n == null)
1207 return defaultValue;
1208
1209 return n.intValue();
1210 }
1211
1212
1213 /**
1214 * Return the number of facets. This is more efficient than
1215 * calling getFacets().size();
1216 */
1217 @Override
1218 public int getFacetCount()
1219 {
1220 if (_facets == null)
1221 return 0;
1222
1223 return _facets.size();
1224 }
1225
1226
1227 /**
1228 * Broadcast an event to a MethodBinding.
1229 * This can be used to support MethodBindings such as the "actionListener"
1230 * binding on ActionSource components:
1231 * <tr:commandButton actionListener="#{mybean.myActionListener}">
1232 * @deprecated
1233 */
1234 protected final void broadcastToMethodBinding(
1235 FacesEvent event,
1236 MethodBinding method) throws AbortProcessingException
1237 {
1238 if (method != null)
1239 {
1240 try
1241 {
1242 FacesContext context = getFacesContext();
1243 method.invoke(context, new Object[] { event });
1244 }
1245 catch (EvaluationException ee)
1246 {
1247 Throwable t = ee.getCause();
1248
1249 if (t instanceof AbortProcessingException)
1250 throw ((AbortProcessingException) t);
1251 throw ee;
1252 }
1253 }
1254 }
1255
1256 /**
1257 * Given a MethodBinding, create a MethodExpression that
1258 * adapts it.
1259 */
1260 static public MethodExpression adaptMethodBinding(MethodBinding binding)
1261 {
1262 return new MethodBindingMethodExpression(binding);
1263 }
1264
1265 /**
1266 * Broadcast an event to a MethodExpression.
1267 * This can be used to support MethodBindings such as the "actionListener"
1268 * binding on ActionSource components:
1269 * <tr:commandButton actionListener="#{mybean.myActionListener}">
1270 */
1271 protected final void broadcastToMethodExpression(
1272 FacesEvent event,
1273 MethodExpression method) throws AbortProcessingException
1274 {
1275 if (method != null)
1276 {
1277 try
1278 {
1279 FacesContext context = getFacesContext();
1280 method.invoke(context.getELContext(), new Object[] { event });
1281 }
1282 catch (ELException ee)
1283 {
1284 Throwable t = ee.getCause();
1285
1286 if (t instanceof AbortProcessingException)
1287 throw ((AbortProcessingException) t);
1288 throw ee;
1289 }
1290 }
1291 }
1292
1293
1294 /**
1295 * <p>
1296 * This gets a single threadlocal shared stringbuilder instance, each time you call
1297 * __getSharedStringBuilder it sets the length of the stringBuilder instance to 0.
1298 * </p><p>
1299 * This allows you to use the same StringBuilder instance over and over.
1300 * You must call toString on the instance before calling __getSharedStringBuilder again.
1301 * </p>
1302 * Example that works
1303 * <pre><code>
1304 * StringBuilder sb1 = __getSharedStringBuilder();
1305 * sb1.append(a).append(b);
1306 * String c = sb1.toString();
1307 *
1308 * StringBuilder sb2 = __getSharedStringBuilder();
1309 * sb2.append(b).append(a);
1310 * String d = sb2.toString();
1311 * </code></pre>
1312 * <br><br>
1313 * Example that doesn't work, you must call toString on sb1 before
1314 * calling __getSharedStringBuilder again.
1315 * <pre><code>
1316 * StringBuilder sb1 = __getSharedStringBuilder();
1317 * StringBuilder sb2 = __getSharedStringBuilder();
1318 *
1319 * sb1.append(a).append(b);
1320 * String c = sb1.toString();
1321 *
1322 * sb2.append(b).append(a);
1323 * String d = sb2.toString();
1324 * </code></pre>
1325 *
1326 */
1327 static StringBuilder __getSharedStringBuilder()
1328 {
1329 StringBuilder sb = _STRING_BUILDER.get();
1330
1331 if (sb == null)
1332 {
1333 sb = new StringBuilder();
1334 _STRING_BUILDER.set(sb);
1335 }
1336
1337
1338 sb.setLength(0);
1339
1340 return sb;
1341 }
1342
1343 /**
1344 * render a component. this is called by renderers whose
1345 * getRendersChildren() return true.
1346 */
1347 void __encodeRecursive(FacesContext context, UIComponent component)
1348 throws IOException
1349 {
1350 if (component.isRendered())
1351 {
1352 component.encodeBegin(context);
1353 if (component.getRendersChildren())
1354 {
1355 component.encodeChildren(context);
1356 }
1357 else
1358 {
1359 if (component.getChildCount() > 0)
1360 {
1361 for(UIComponent child : component.getChildren())
1362 {
1363 __encodeRecursive(context, child);
1364 }
1365 }
1366 }
1367
1368 component.encodeEnd(context);
1369 }
1370 }
1371
1372
1373 static private UIComponent _findInsideOf(
1374 UIComponent from,
1375 String id)
1376 {
1377 Iterator<UIComponent> kids = from.getFacetsAndChildren();
1378 while (kids.hasNext())
1379 {
1380 UIComponent kid = kids.next();
1381 if (id.equals(kid.getId()))
1382 return kid;
1383
1384 if (!(kid instanceof NamingContainer))
1385 {
1386 UIComponent returned = _findInsideOf(kid, id);
1387 if (returned != null)
1388 return returned;
1389 }
1390 }
1391
1392 return null;
1393 }
1394
1395 /**
1396 * <p>Verify that the specified component id is safe to add to the tree.
1397 * </p>
1398 *
1399 * @param id The proposed component id to check for validity
1400 *
1401 * @exception IllegalArgumentException if <code>id</code>
1402 * is <code>null</code> or contains invalid characters
1403 */
1404 private void _validateId(String id)
1405 {
1406 if (id == null)
1407 return;
1408
1409
1410 int n = id.length();
1411 if (0 == n ||
1412 NamingContainer.SEPARATOR_CHAR == id.charAt(0))
1413 _throwBadId(id);
1414
1415 for (int i = 0; i < n; i++)
1416 {
1417 char c = id.charAt(i);
1418 if (i == 0)
1419 {
1420 if (!Character.isLetter(c) && (c != '_'))
1421 _throwBadId(id);
1422 }
1423 else
1424 {
1425 if (!(Character.isLetter(c) ||
1426 Character.isDigit(c) ||
1427 (c == '-') || (c == '_')))
1428 {
1429 _throwBadId(id);
1430 }
1431 }
1432 }
1433 }
1434
1435 private void _throwBadId(String id)
1436 {
1437 throw new IllegalArgumentException(_LOG.getMessage(
1438 "ILLEGAL_ID", id));
1439 }
1440
1441 private void _init(
1442 String rendererType)
1443 {
1444 FacesBean oldBean = _facesBean;
1445 _facesBean = createFacesBean(rendererType);
1446 if (oldBean != null)
1447 _facesBean.addAll(oldBean);
1448
1449 _attributes = new ValueMap(_facesBean);
1450 }
1451
1452 private FacesBean _facesBean;
1453 private List<UIComponent> _children;
1454 private Map<String, Object> _attributes;
1455 private Map<String, UIComponent> _facets;
1456 private UIComponent _parent;
1457
1458
1459
1460 private transient Renderer _cachedRenderer = _UNDEFINED_RENDERER;
1461 private transient LifecycleRenderer _cachedLifecycleRenderer =
1462 _UNDEFINED_LIFECYCLE_RENDERER;
1463
1464
1465
1466
1467
1468
1469 private static final Iterator<String> _EMPTY_STRING_ITERATOR =
1470 new EmptyIterator<String>();
1471
1472 private static final Iterator<UIComponent> _EMPTY_UICOMPONENT_ITERATOR =
1473 new EmptyIterator<UIComponent>();
1474
1475
1476 static private final ThreadLocal<StringBuilder> _STRING_BUILDER =
1477 new ThreadLocal<StringBuilder>();
1478
1479 static private FacesBean.Type _createType()
1480 {
1481 try
1482 {
1483 ClassLoader cl = _getClassLoader();
1484 URL url = cl.getResource("META-INF/faces-bean-type.properties");
1485 if (url != null)
1486 {
1487 Properties properties = new Properties();
1488 InputStream is = url.openStream();
1489 try
1490 {
1491 properties.load(is);
1492 String className = (String)
1493 properties.get(UIXComponentBase.class.getName());
1494 return (FacesBean.Type) cl.loadClass(className).newInstance();
1495 }
1496 finally
1497 {
1498 is.close();
1499 }
1500 }
1501 }
1502 catch (Exception e)
1503 {
1504 _LOG.severe("CANNOT_LOAD_TYPE_PROPERTIES", e);
1505 }
1506
1507
1508 return new FacesBean.Type();
1509 }
1510
1511 static private ClassLoader _getClassLoader()
1512 {
1513 ClassLoader loader = Thread.currentThread().getContextClassLoader();
1514 if (loader == null)
1515 loader = FacesBeanFactory.class.getClassLoader();
1516 return loader;
1517 }
1518
1519 static private class RendererImpl extends Renderer
1520 {
1521 }
1522
1523 static private class ExtendedRendererImpl extends ExtendedRenderer
1524 {
1525 }
1526
1527 private static class EmptyIterator<T> implements Iterator<T>
1528 {
1529 public boolean hasNext()
1530 {
1531 return false;
1532 }
1533
1534 public T next()
1535 {
1536 throw new NoSuchElementException();
1537 }
1538
1539 public void remove()
1540 {
1541 throw new UnsupportedOperationException();
1542 }
1543
1544 }
1545
1546 static private final LifecycleRenderer _UNDEFINED_LIFECYCLE_RENDERER =
1547 new ExtendedRendererImpl();
1548 static private final Renderer _UNDEFINED_RENDERER = new RendererImpl();
1549 }