View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package javax.faces.component;
20  
21  import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFComponent;
22  import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFJspProperty;
23  import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFProperty;
24  
25  import javax.el.ValueExpression;
26  import javax.faces.FacesException;
27  import javax.faces.component.behavior.Behavior;
28  import javax.faces.component.behavior.ClientBehavior;
29  import javax.faces.component.visit.VisitCallback;
30  import javax.faces.component.visit.VisitContext;
31  import javax.faces.context.FacesContext;
32  import javax.faces.el.ValueBinding;
33  import javax.faces.event.AbortProcessingException;
34  import javax.faces.event.BehaviorEvent;
35  import javax.faces.event.FacesEvent;
36  import javax.faces.event.FacesListener;
37  import javax.faces.event.PostAddToViewEvent;
38  import javax.faces.event.PostValidateEvent;
39  import javax.faces.event.PreRemoveFromViewEvent;
40  import javax.faces.event.PreRenderComponentEvent;
41  import javax.faces.event.PreValidateEvent;
42  import javax.faces.event.SystemEvent;
43  import javax.faces.event.SystemEventListener;
44  import javax.faces.render.RenderKit;
45  import javax.faces.render.Renderer;
46  import javax.faces.view.Location;
47  import java.io.IOException;
48  import java.io.Serializable;
49  import java.lang.reflect.Array;
50  import java.util.ArrayList;
51  import java.util.Collection;
52  import java.util.Collections;
53  import java.util.HashMap;
54  import java.util.Iterator;
55  import java.util.List;
56  import java.util.Map;
57  import java.util.logging.Level;
58  import java.util.logging.Logger;
59  
60  
61  /**
62   * TODO: IMPLEMENT HERE - Delta state saving support
63   * 
64   * Standard implementation of the UIComponent base class; all standard JSF components extend this class.
65   * <p>
66   * <i>Disclaimer</i>: The official definition for the behaviour of this class is the JSF 1.1 specification but for legal
67   * reasons the specification cannot be replicated here. Any javadoc here therefore describes the current implementation
68   * rather than the spec, though this class has been verified as correctly implementing the spec.
69   * 
70   * see Javadoc of <a href="http://java.sun.com/javaee/javaserverfaces/1.2/docs/api/index.html">JSF Specification</a> for
71   * more.
72   * 
73   * @author Manfred Geiler (latest modification by $Author: lu4242 $)
74   * @version $Revision: 1405217 $ $Date: 2012-11-02 18:47:05 -0500 (Fri, 02 Nov 2012) $
75   */
76  @JSFComponent(type = "javax.faces.ComponentBase", family = "javax.faces.ComponentBase",
77                desc = "base component when all components must inherit",
78                tagClass = "javax.faces.webapp.UIComponentELTag", configExcluded = true)
79  @JSFJspProperty(name = "binding", returnType = "javax.faces.component.UIComponent",
80                  longDesc = "Identifies a backing bean property (of type UIComponent or appropriate subclass) to bind "
81                             + "to this component instance. This value must be an EL expression.",
82                  desc = "backing bean property to bind to this component instance")
83  public abstract class UIComponentBase extends UIComponent
84  {
85      //private static Log log = LogFactory.getLog(UIComponentBase.class);
86      private static Logger log = Logger.getLogger(UIComponentBase.class.getName());
87  
88      private static final Iterator<UIComponent> _EMPTY_UICOMPONENT_ITERATOR = new _EmptyIterator<UIComponent>();
89  
90      private static final String _STRING_BUILDER_KEY
91              = "javax.faces.component.UIComponentBase.SHARED_STRING_BUILDER";
92  
93      private _ComponentAttributesMap _attributesMap = null;
94      private List<UIComponent> _childrenList = null;
95      private Map<String, UIComponent> _facetMap = null;
96      private _DeltaList<FacesListener> _facesListeners = null;
97      private String _clientId = null;
98      private String _id = null;
99      private UIComponent _parent = null;
100     private boolean _transient = false;
101     
102     private boolean _isRendererTypeSet = false;
103     private String _rendererType;
104     private String _markCreated;
105     private String _facetName;
106     private boolean _addedByHandler = false;
107     private boolean _facetCreatedUIPanel = false;
108 
109     /**
110      * This map holds ClientBehavior instances.
111      * 
112      *  Note that BehaviorBase implements PartialStateHolder, so this class 
113      *  should deal with that fact on clearInitialState() and 
114      *  markInitialState() methods.
115      * 
116      *  Also, the map used by this instance is not set from outside this class.
117      *  
118      *  Note it is possible (but maybe not expected/valid) to manipulate 
119      *  the values of the map(the list) but not put instances on the map 
120      *  directly, because ClientBehaviorHolder.getClientBehaviors says that 
121      *  this method should return a non null unmodificable map.
122      *  
123      */
124     private Map<String, List<ClientBehavior>> _behaviorsMap = null;
125     private transient Map<String, List<ClientBehavior>> _unmodifiableBehaviorsMap = null;
126     
127     private transient FacesContext _facesContext;
128     private transient Boolean _cachedIsRendered;
129     private transient Renderer _cachedRenderer;
130     
131     public UIComponentBase()
132     {
133     }
134 
135     /**
136      * Put the provided value-binding into a map of value-bindings associated with this component.
137      * 
138      * @deprecated Replaced by setValueExpression
139      */
140     @Override
141     public void setValueBinding(String name, ValueBinding binding)
142     {
143         setValueExpression(name, binding == null ? null : new _ValueBindingToValueExpression(binding));
144     }
145 
146     /**
147      * Set an identifier for this component which is unique within the scope of the nearest ancestor NamingContainer
148      * component. The id is not necessarily unique across all components in the current view.
149      * <p>
150      * The id must start with an underscore if it is generated by the JSF framework, and must <i>not</i> start with an
151      * underscore if it has been specified by the user (eg in a JSP tag).
152      * <p>
153      * The first character of the id must be an underscore or letter. Following characters may be letters, digits,
154      * underscores or dashes.
155      * <p>
156      * Null is allowed as a parameter, and will reset the id to null.
157      * <p>
158      * The clientId of this component is reset by this method; see getClientId for more info.
159      * 
160      * @throws IllegalArgumentException
161      *             if the id is not valid.
162      */
163     @Override
164     public void setId(String id)
165     {
166         isIdValid(id);
167         _id = id;
168         _clientId = null;
169     }
170 
171     /**
172      * <p>Set the parent <code>UIComponent</code> of this
173      * <code>UIComponent</code>.</p>
174      * 
175      * @param parent The new parent, or <code>null</code> for the root node
176      *  of a component tree
177      */
178     @Override
179     public void setParent(UIComponent parent)
180     {
181         // removing kids OR this is UIViewRoot
182         if (parent == null)
183         {
184             // not UIViewRoot...
185             if (_parent != null && _parent.isInView())
186             {
187                 // trigger the "remove event" lifecycle
188                 // and call setInView(false) for all children/facets
189                 // doing this => recursive
190                 FacesContext facesContext = getFacesContext();
191                 if (facesContext.isProcessingEvents())
192                 {
193                     _publishPreRemoveFromViewEvent(facesContext, this);
194                 }
195                 else
196                 {
197                     _updateInView(this, false);
198                 }
199             }
200             _parent = parent;
201         }
202         else
203         {
204             _parent = parent;
205             if (parent.isInView())
206             {
207                 // trigger the ADD_EVENT and call setInView(true)
208                 // recursive for all kids/facets...
209                 // Application.publishEvent(java.lang.Class, java.lang.Object)  must be called, passing 
210                 // PostAddToViewEvent.class as the first argument and the newly added component as the second 
211                 // argument.
212                 FacesContext facesContext = getFacesContext();
213                 if (facesContext.isProcessingEvents())
214                 {
215                     _publishPostAddToViewEvent(facesContext, this);
216                 }
217                 else
218                 {
219                     _updateInView(this, true);
220                 }
221             }
222         }
223     }
224 
225     
226     /**
227      * Publish PostAddToViewEvent to the component and all facets and children.
228      * 
229      * @param context
230      * @param component
231      */
232     private static void _publishPostAddToViewEvent(FacesContext context, UIComponent component)
233     {
234         component.setInView(true);
235         context.getApplication().publishEvent(context, PostAddToViewEvent.class, component.getClass(), component);
236         
237         if (component.getChildCount() > 0)
238         {
239             // PostAddToViewEvent could cause component relocation
240             // (h:outputScript, h:outputStylesheet, composite:insertChildren, composite:insertFacet)
241             // so we need to check if the component was relocated or not
242           
243             List<UIComponent> children = component.getChildren();
244             for (int i = 0; i < children.size(); i++)
245             {
246                 // spin on same index while component removed/replaced
247                 // to prevent skipping components:
248                 while (true)
249                 {
250                     UIComponent child = children.get(i);
251                     child.pushComponentToEL(context, child);
252                     try
253                     {
254                         _publishPostAddToViewEvent(context, child);
255                     }
256                     finally
257                     {
258                         child.popComponentFromEL(context);
259                     }
260                     if (i < children.size() && children.get(i) != child)
261                     {
262                         continue;
263                     }
264                     break;
265                 }
266             }
267         }
268         if (component.getFacetCount() > 0)
269         {
270             for (UIComponent child : component.getFacets().values())
271             {
272                 child.pushComponentToEL(context, child);
273                 try
274                 {
275                     _publishPostAddToViewEvent(context, child);
276                 }
277                 finally
278                 {
279                     child.popComponentFromEL(context);
280                 }
281             }
282         }        
283     }
284     
285     /**
286      * Publish PreRemoveFromViewEvent to the component and all facets and children.
287      * 
288      * @param context
289      * @param component
290      */
291     private static void _publishPreRemoveFromViewEvent(FacesContext context, UIComponent component)
292     {
293         component.setInView(false);
294         context.getApplication().publishEvent(context, PreRemoveFromViewEvent.class, component.getClass(), component);
295         
296         if (component.getChildCount() > 0)
297         {
298             for (int i = 0, childCount = component.getChildCount(); i < childCount; i++)
299             {
300                 UIComponent child = component.getChildren().get(i);
301                 _publishPreRemoveFromViewEvent(context, child);
302             }
303         }
304         if (component.getFacetCount() > 0)
305         {
306             for (UIComponent child : component.getFacets().values())
307             {
308                 _publishPreRemoveFromViewEvent(context, child);
309             }
310         }        
311     }    
312     
313     private static void _updateInView(UIComponent component, boolean isInView)
314     {
315         component.setInView(isInView);
316         
317         if (component.getChildCount() > 0)
318         {
319             for (int i = 0, childCount = component.getChildCount(); i < childCount; i++)
320             {
321                 UIComponent child = component.getChildren().get(i);
322                 _updateInView(child, isInView);
323             }
324         }
325         if (component.getFacetCount() > 0)
326         {
327             for (UIComponent child : component.getFacets().values())
328             {
329                 _updateInView(child, isInView);
330             }
331         }        
332     }  
333     
334     /**
335      * 
336      * @param eventName
337      * @param behavior
338      * 
339      * @since 2.0
340      */
341     public void addClientBehavior(String eventName, ClientBehavior behavior)
342     {
343         Collection<String> eventNames = getEventNames();
344         
345         if(eventNames == null)
346         {
347             //component didn't implement getEventNames properly
348             //log an error and return
349             if(log.isLoggable(Level.SEVERE))
350             {
351                 log.severe("attempted to add a behavior to a component which did not properly "
352                            + "implement getEventNames.  getEventNames must not return null");
353                 return;
354             }
355         }
356         
357         if(eventNames.contains(eventName))
358         {
359             if(_behaviorsMap == null)
360             {
361                 _behaviorsMap = new HashMap<String,List<ClientBehavior>>();
362             }
363             
364             List<ClientBehavior> behaviorsForEvent = _behaviorsMap.get(eventName);
365             if(behaviorsForEvent == null)
366             {
367                 // Normally have client only 1 client behaviour per event name,
368                 // so size 2 must be sufficient: 
369                 behaviorsForEvent = new _DeltaList<ClientBehavior>(new ArrayList<ClientBehavior>(2));
370                 _behaviorsMap.put(eventName, behaviorsForEvent);
371             }
372             
373             behaviorsForEvent.add(behavior);
374             _unmodifiableBehaviorsMap = null;
375         }
376     }
377 
378     /**
379      * Invoke any listeners attached to this object which are listening for an event whose type matches the specified
380      * event's runtime type.
381      * <p>
382      * This method does not propagate the event up to parent components, ie listeners attached to parent components
383      * don't automatically get called.
384      * <p>
385      * If any of the listeners throws AbortProcessingException then that exception will prevent any further listener
386      * callbacks from occurring, and the exception propagates out of this method without alteration.
387      * <p>
388      * ActionEvent events are typically queued by the renderer associated with this component in its decode method;
389      * ValueChangeEvent events by the component's validate method. In either case the event's source property references
390      * a component. At some later time the UIViewRoot component iterates over its queued events and invokes the
391      * broadcast method on each event's source object.
392      * 
393      * @param event
394      *            must not be null.
395      */
396     @Override
397     public void broadcast(FacesEvent event) throws AbortProcessingException
398     {
399         if (event == null)
400         {
401             throw new NullPointerException("event");
402         }
403         
404         if (event instanceof BehaviorEvent && event.getComponent() == this)
405         {
406             Behavior behavior = ((BehaviorEvent) event).getBehavior();
407             behavior.broadcast((BehaviorEvent) event);
408         }
409 
410         if (_facesListeners == null)
411         {
412             return;
413         }
414         // perf: _facesListeners is RandomAccess instance (javax.faces.component._DeltaList)
415         for (int i = 0, size = _facesListeners.size(); i < size; i++)
416         {
417             FacesListener facesListener = _facesListeners.get(i);
418             if (event.isAppropriateListener(facesListener))
419             {
420                 event.processListener(facesListener);
421             }
422         }
423     }
424     
425     public void clearInitialState()
426     {
427         super.clearInitialState();
428         if (_facesListeners != null)
429         {
430             _facesListeners.clearInitialState();
431         }
432         if (_behaviorsMap != null)
433         {
434             for (Map.Entry<String, List<ClientBehavior> > entry : _behaviorsMap.entrySet())
435             {
436                 ((PartialStateHolder) entry.getValue()).clearInitialState();
437             }
438         }
439         if (_systemEventListenerClassMap != null)
440         {
441             for (Map.Entry<Class<? extends SystemEvent>, List<SystemEventListener>> entry : 
442                 _systemEventListenerClassMap.entrySet())
443             {
444                 ((PartialStateHolder) entry.getValue()).clearInitialState();
445             }
446         }
447         _isRendererTypeSet = false;
448     }
449 
450     /**
451      * Check the submitted form parameters for data associated with this component. This default implementation
452      * delegates to this component's renderer if there is one, and otherwise ignores the call.
453      */
454     @Override
455     public void decode(FacesContext context)
456     {
457         if (context == null)
458         {
459             throw new NullPointerException("context");
460         }
461         
462         setCachedRenderer(null);
463         Renderer renderer = getRenderer(context);
464         if (renderer != null)
465         {
466             setCachedRenderer(renderer);
467             try
468             {
469                 renderer.decode(context, this);
470             }
471             finally
472             {
473                 setCachedRenderer(null);
474             }
475         }
476 
477     }
478 
479     public void encodeAll(FacesContext context) throws IOException
480     {
481         if (context == null)
482         {
483             throw new NullPointerException();
484         }
485 
486         pushComponentToEL(context, this);
487         try
488         {
489             setCachedIsRendered(null);
490             boolean rendered;
491             try
492             {
493                 setCachedFacesContext(context);
494                 rendered = isRendered();
495             }
496             finally
497             {
498                 setCachedFacesContext(null);
499             } 
500             setCachedIsRendered(rendered);
501             if (!rendered)
502             {
503                 setCachedIsRendered(null);
504                 return;
505             }
506             setCachedRenderer(null);
507             setCachedRenderer(getRenderer(context));
508         }
509         finally
510         {
511             popComponentFromEL(context);
512         }
513 
514         try
515         {
516             //if (isRendered()) {
517             this.encodeBegin(context);
518 
519             // rendering children
520             boolean rendersChildren;
521             try
522             {
523                 setCachedFacesContext(context);
524                 rendersChildren = this.getRendersChildren();
525             }
526             finally
527             {
528                 setCachedFacesContext(null);
529             }
530             if (rendersChildren)
531             {
532                 this.encodeChildren(context);
533             } // let children render itself
534             else
535             {
536                 if (this.getChildCount() > 0)
537                 {
538                     for (int i = 0; i < this.getChildCount(); i++)
539                     {
540                         UIComponent comp = this.getChildren().get(i);
541                         comp.encodeAll(context);
542                     }
543                 }
544             }
545             this.encodeEnd(context);
546             //}
547         }
548         finally
549         {
550             setCachedIsRendered(null);
551             setCachedRenderer(null);
552         }
553     }
554 
555     @Override
556     public void encodeBegin(FacesContext context) throws IOException
557     {
558         if (context == null)
559         {
560             throw new NullPointerException("context");
561         }
562 
563         try
564         {
565             setCachedFacesContext(context);
566             // Call UIComponent.pushComponentToEL(javax.faces.context.FacesContext, javax.faces.component.UIComponent)
567             pushComponentToEL(context, this);
568     
569             if (isRendered())
570             {
571                 // If our rendered property is true, render the beginning of the current state of this
572                 // UIComponent to the response contained in the specified FacesContext.
573     
574                 // Call Application.publishEvent(java.lang.Class, java.lang.Object), passing BeforeRenderEvent.class as
575                 // the first argument and the component instance to be rendered as the second argument.
576     
577                 // The main issue we have here is that the listeners are normally just registered
578                 // to UIComponent, how do we deal with inherited ones?
579                 // We have to ask the EG
580                 context.getApplication().publishEvent(context,  PreRenderComponentEvent.class, UIComponent.class, this);
581     
582                 Renderer renderer = getRenderer(context);
583                 if (renderer != null)
584                 {
585                     // If a Renderer is associated with this UIComponent, the actual encoding will be delegated to
586                     // Renderer.encodeBegin(FacesContext, UIComponent).
587                     renderer.encodeBegin(context, this);
588                 }
589             }
590         }
591         finally
592         {
593             setCachedFacesContext(null);
594         }
595     }
596 
597     @Override
598     public void encodeChildren(FacesContext context) throws IOException
599     {
600         if (context == null)
601         {
602             throw new NullPointerException("context");
603         }
604 
605         boolean isCachedFacesContext = isCachedFacesContext();
606         try
607         {
608             if (!isCachedFacesContext)
609             {
610                 setCachedFacesContext(context);
611             }
612             if (isRendered())
613             {
614                 // If our rendered property is true, render the child UIComponents of this UIComponent.
615     
616                 Renderer renderer = getRenderer(context);
617                 if (renderer == null)
618                 {
619                     // If no Renderer is associated with this UIComponent, iterate over each of the children of this
620                     // component and call UIComponent.encodeAll(javax.faces.context.FacesContext).
621                     if (getChildCount() > 0)
622                     {
623                         for (int i = 0, childCount = getChildCount(); i < childCount; i++)
624                         {
625                             UIComponent child = getChildren().get(i);
626                             child.encodeAll(context);
627                         }
628                     }
629                 }
630                 else
631                 {
632                     // If a Renderer is associated with this UIComponent, the actual encoding will be delegated to
633                     // Renderer.encodeChildren(FacesContext, UIComponent).
634                     renderer.encodeChildren(context, this);
635                 }
636             }
637         }
638         finally
639         {
640             if (!isCachedFacesContext)
641             {
642                 setCachedFacesContext(null);
643             }
644         }
645     }
646 
647     @Override
648     public void encodeEnd(FacesContext context) throws IOException
649     {
650         try
651         {
652             if (context == null)
653             {
654                 throw new NullPointerException("context");
655             }
656             setCachedFacesContext(context);
657             if (isRendered())
658             {
659                 // If our rendered property is true, render the ending of the current state of this UIComponent.
660                 Renderer renderer = getRenderer(context);
661                 if (renderer != null)
662                 {
663                     // If a Renderer is associated with this UIComponent, the actual encoding will be delegated to
664                     // Renderer.encodeEnd(FacesContext, UIComponent).
665                     renderer.encodeEnd(context, this);
666                 }
667             }
668         }
669         finally
670         {
671             // Call UIComponent.popComponentFromEL(javax.faces.context.FacesContext). before returning regardless
672             // of the value of the rendered property.
673             popComponentFromEL(context);
674             setCachedFacesContext(null);
675         }
676     }
677     
678     /**
679      * Standard method for finding other components by id, inherited by most UIComponent objects.
680      * <p>
681      * The lookup is performed in a manner similar to finding a file in a filesystem; there is a "base" at which to
682      * start, and the id can be for something in the "local directory", or can include a relative path. Here,
683      * NamingContainer components fill the role of directories, and ":" is the "path separator". Note, however, that
684      * although components have a strict parent/child hierarchy, component ids are only prefixed ("namespaced") with the
685      * id of their parent when the parent is a NamingContainer.
686      * <p>
687      * The base node at which the search starts is determined as follows:
688      * <ul>
689      * <li>When expr starts with ':', the search starts with the root component of the tree that this component is in
690      * (ie the ancestor whose parent is null).
691      * <li>Otherwise, if this component is a NamingContainer then the search starts with this component.
692      * <li>Otherwise, the search starts from the nearest ancestor NamingContainer (or the root component if there is no
693      * NamingContainer ancestor).
694      * </ul>
695      * 
696      * @param expr
697      *            is of form "id1:id2:id3".
698      * @return UIComponent or null if no component with the specified id is found.
699      */
700 
701     @Override
702     public UIComponent findComponent(String expr)
703     {
704         if (expr == null)
705         {
706             throw new NullPointerException("expr");
707         }
708         if (expr.length() == 0)
709         {
710             return null;
711         }
712 
713         char separatorChar = UINamingContainer.getSeparatorChar(getFacesContext());
714         UIComponent findBase;
715         if (expr.charAt(0) == separatorChar)
716         {
717             findBase = _ComponentUtils.getRootComponent(this);
718             expr = expr.substring(1);
719         }
720         else
721         {
722             if (this instanceof NamingContainer)
723             {
724                 findBase = this;
725             }
726             else
727             {
728                 findBase = _ComponentUtils.findParentNamingContainer(this, true /* root if not found */);
729             }
730         }
731 
732         int separator = expr.indexOf(separatorChar);
733         if (separator == -1)
734         {
735             return _ComponentUtils.findComponent(findBase, expr, separatorChar);
736         }
737 
738         String id = expr.substring(0, separator);
739         findBase = _ComponentUtils.findComponent(findBase, id, separatorChar);
740         if (findBase == null)
741         {
742             return null;
743         }
744 
745         if (!(findBase instanceof NamingContainer))
746         {
747             throw new IllegalArgumentException("Intermediate identifier " + id + " in search expression " + expr
748                     + " identifies a UIComponent that is not a NamingContainer");
749         }
750 
751         return findBase.findComponent(expr.substring(separator + 1));
752 
753     }
754 
755     /**
756      * Get a map through which all the UIComponent's properties, value-bindings and non-property attributes can be read
757      * and written.
758      * <p>
759      * When writing to the returned map:
760      * <ul>
761      * <li>If this component has an explicit property for the specified key then the setter method is called. An
762      * IllegalArgumentException is thrown if the property is read-only. If the property is readable then the old value
763      * is returned, otherwise null is returned.
764      * <li>Otherwise the key/value pair is stored in a map associated with the component.
765      * </ul>
766      * Note that value-bindings are <i>not</i> written by put calls to this map. Writing to the attributes map using a
767      * key for which a value-binding exists will just store the value in the attributes map rather than evaluating the
768      * binding, effectively "hiding" the value-binding from later attributes.get calls. Setter methods on components
769      * commonly do <i>not</i> evaluate a binding of the same name; they just store the provided value directly on the
770      * component.
771      * <p>
772      * When reading from the returned map:
773      * <ul>
774      * <li>If this component has an explicit property for the specified key then the getter method is called. If the
775      * property exists, but is read-only (ie only a setter method is defined) then an IllegalArgumentException is
776      * thrown.
777      * <li>If the attribute map associated with the component has an entry with the specified key, then that is
778      * returned.
779      * <li>If this component has a value-binding for the specified key, then the value-binding is evaluated to fetch the
780      * value.
781      * <li>Otherwise, null is returned.
782      * </ul>
783      * Note that components commonly define getter methods such that they evaluate a value-binding of the same name if
784      * there isn't yet a local property.
785      * <p>
786      * Assigning values to the map which are not explicit properties on the underlying component can be used to "tunnel"
787      * attributes from the JSP tag (or view-specific equivalent) to the associated renderer without modifying the
788      * component itself.
789      * <p>
790      * Any value-bindings and non-property attributes stored in this map are automatically serialized along with the
791      * component when the view is serialized.
792      */
793     @Override
794     public Map<String, Object> getAttributes()
795     {
796         if (_attributesMap == null)
797         {
798             _attributesMap = new _ComponentAttributesMap(this);
799         }
800 
801         return _attributesMap;
802     }
803 
804     /**
805      * Return the number of direct child components this component has.
806      * <p>
807      * Identical to getChildren().size() except that when this component has no children this method will not force an
808      * empty list to be created.
809      */
810     @Override
811     public int getChildCount()
812     {
813         return _childrenList == null ? 0 : _childrenList.size();
814     }
815 
816     /**
817      * Return a list of the UIComponent objects which are direct children of this component.
818      * <p>
819      * The list object returned has some non-standard behaviour:
820      * <ul>
821      * <li>The list is type-checked; only UIComponent objects can be added.
822      * <li>If a component is added to the list with an id which is the same as some other component in the list then an
823      * exception is thrown. However multiple components with a null id may be added.
824      * <li>The component's parent property is set to this component. If the component already had a parent, then the
825      * component is first removed from its original parent's child list.
826      * </ul>
827      */
828     @Override
829     public List<UIComponent> getChildren()
830     {
831         if (_childrenList == null)
832         {
833             _childrenList = new _ComponentChildrenList(this);
834         }
835         return _childrenList;
836     }
837     
838     /**
839      * 
840      * @return
841      * 
842      * @since 2.0
843      */
844     public Map<String,List<ClientBehavior>> getClientBehaviors()
845     {
846         if(_behaviorsMap == null)
847         {
848             return Collections.emptyMap();
849         }
850 
851         return wrapBehaviorsMap();
852     }
853 
854     /**
855      * Get a string which can be output to the response which uniquely identifies this UIComponent within the current
856      * view.
857      * <p>
858      * The component should have an id attribute already assigned to it; however if the id property is currently null
859      * then a unique id is generated and set for this component. This only happens when components are programmatically
860      * created without ids, as components created by a ViewHandler should be assigned ids when they are created.
861      * <p>
862      * If this component is a descendant of a NamingContainer then the client id is of form
863      * "{namingContainerId}:{componentId}". Note that the naming container's id may itself be of compound form if it has
864      * an ancestor naming container. Note also that this only applies to naming containers; other UIComponent types in
865      * the component's ancestry do not affect the clientId.
866      * <p>
867      * Finally the renderer associated with this component is asked to convert the id into a suitable form. This allows
868      * escaping of any characters in the clientId which are significant for the markup language generated by that
869      * renderer.
870      */
871     @Override
872     public String getClientId(FacesContext context)
873     {
874         if (context == null)
875         {
876             throw new NullPointerException("context");
877         }
878 
879         if (_clientId != null)
880         {
881             return _clientId;
882         }
883 
884         //boolean idWasNull = false;
885         String id = getId();
886         if (id == null)
887         {
888             // Although this is an error prone side effect, we automatically create a new id
889             // just to be compatible to the RI
890             
891             // The documentation of UniqueIdVendor says that this interface should be implemented by
892             // components that also implements NamingContainer. The only component that does not implement
893             // NamingContainer but UniqueIdVendor is UIViewRoot. Anyway we just can't be 100% sure about this
894             // fact, so it is better to scan for the closest UniqueIdVendor. If it is not found use 
895             // viewRoot.createUniqueId, otherwise use UniqueIdVendor.createUniqueId(context,seed).
896             UniqueIdVendor parentUniqueIdVendor = _ComponentUtils.findParentUniqueIdVendor(this);
897             if (parentUniqueIdVendor == null)
898             {
899                 UIViewRoot viewRoot = context.getViewRoot();
900                 if (viewRoot != null)
901                 {
902                     id = viewRoot.createUniqueId();
903                 }
904                 else
905                 {
906                     // The RI throws a NPE
907                     String location = getComponentLocation(this);
908                     throw new FacesException("Cannot create clientId. No id is assigned for component"
909                             + " to create an id and UIViewRoot is not defined: "
910                             + getPathToComponent(this)
911                             + (location != null ? " created from: " + location : ""));
912                 }
913             }
914             else
915             {
916                 id = parentUniqueIdVendor.createUniqueId(context, null);
917             }
918             setId(id);
919             // We remember that the id was null and log a warning down below
920             // idWasNull = true;
921         }
922 
923         UIComponent namingContainer = _ComponentUtils.findParentNamingContainer(this, false);
924         if (namingContainer != null)
925         {
926             String containerClientId = namingContainer.getContainerClientId(context);
927             if (containerClientId != null)
928             {
929                 StringBuilder bld = _getSharedStringBuilder(context);
930                 _clientId = bld.append(containerClientId).append(
931                                       UINamingContainer.getSeparatorChar(context)).append(id).toString();
932             }
933             else
934             {
935                 _clientId = id;
936             }
937         }
938         else
939         {
940             _clientId = id;
941         }
942 
943         Renderer renderer = getRenderer(context);
944         if (renderer != null)
945         {
946             _clientId = renderer.convertClientId(context, _clientId);
947         }
948 
949         // -=Leonardo Uribe=- In jsf 1.1 and 1.2 this warning has sense, but in jsf 2.0 it is common to have
950         // components without any explicit id (UIViewParameter components and UIOuput resource components) instances.
951         // So, this warning is becoming obsolete in this new context and should be removed.
952         //if (idWasNull && log.isLoggable(Level.WARNING))
953         //{
954         //    log.warning("WARNING: Component " + _clientId
955         //            + " just got an automatic id, because there was no id assigned yet. "
956         //            + "If this component was created dynamically (i.e. not by a JSP tag) you should assign it an "
957         //            + "explicit static id or assign it the id you get from "
958         //            + "the createUniqueId from the current UIViewRoot "
959         //            + "component right after creation! Path to Component: " + getPathToComponent(this));
960         //}
961 
962         return _clientId;
963     }
964     
965     /**
966      * 
967      * @return
968      * 
969      * @since 2.0
970      */
971     public String getDefaultEventName()
972     {
973         // if a default event exists for a component, this method is overriden thus assume null
974         return null;
975     }
976     
977     /**
978      * 
979      * @return
980      * 
981      * @since 2.0
982      */
983     public Collection<String> getEventNames()
984     {
985         // must be specified by the implementing component.
986         // Returning null will force an error message in addClientBehavior.
987         return null;
988     }
989 
990     @Override
991     public UIComponent getFacet(String name)
992     {
993         return _facetMap == null ? null : _facetMap.get(name);
994     }
995 
996     /**
997      * @since 1.2
998      */
999     @Override
1000     public int getFacetCount()
1001     {
1002         return _facetMap == null ? 0 : _facetMap.size();
1003     }
1004 
1005     @Override
1006     public Map<String, UIComponent> getFacets()
1007     {
1008         if (_facetMap == null)
1009         {
1010             _facetMap = new _ComponentFacetMap<UIComponent>(this);
1011         }
1012         return _facetMap;
1013     }
1014 
1015     @Override
1016     public Iterator<UIComponent> getFacetsAndChildren()
1017     {
1018         // we can't use _facetMap and _childrenList here directly,
1019         // because some component implementation could keep their 
1020         // own properties for facets and children and just override
1021         // getFacets() and getChildren() (e.g. seen in PrimeFaces).
1022         // See MYFACES-2611 for details.
1023         if (getFacetCount() == 0)
1024         {
1025             if (getChildCount() == 0)
1026             {
1027                 return _EMPTY_UICOMPONENT_ITERATOR;
1028             }
1029 
1030             return getChildren().iterator();
1031         }
1032         else
1033         {
1034             if (getChildCount() == 0)
1035             {
1036                 return getFacets().values().iterator();
1037             }
1038 
1039             return new _FacetsAndChildrenIterator(getFacets(), getChildren());
1040         }
1041     }
1042 
1043     /**
1044      * Get a string which uniquely identifies this UIComponent within the scope of the nearest ancestor NamingContainer
1045      * component. The id is not necessarily unique across all components in the current view.
1046      */
1047     @JSFProperty(rtexprvalue = true)
1048     public String getId()
1049     {
1050         return _id;
1051     }
1052 
1053     @Override
1054     public UIComponent getParent()
1055     {
1056         return _parent;
1057     }
1058 
1059     @Override
1060     public String getRendererType()
1061     {
1062         // rendererType is literal-only, no ValueExpression - MYFACES-3136:
1063         // Even if this is true, according to JSF spec section 8 Rendering Model,
1064         // this part is essential to implement "delegated implementation" pattern,
1065         // so we can't do this optimization here. Instead, JSF developers could prevent
1066         // this evaluation overriding this method directly.
1067         if (_rendererType != null)
1068         {
1069             return _rendererType;
1070         }
1071         ValueExpression expression = getValueExpression("rendererType");
1072         if (expression != null)
1073         {
1074             return (String) expression.getValue(getFacesContext().getELContext());
1075         }
1076         return null;
1077     }
1078 
1079     /**
1080      * Indicates whether this component or its renderer manages the invocation of the rendering methods of its child
1081      * components. When this is true:
1082      * <ul>
1083      * <li>This component's encodeBegin method will only be called after all the child components have been created and
1084      * added to this component. <li>This component's encodeChildren method will be called after its encodeBegin method.
1085      * Components for which this method returns false do not get this method invoked at all. <li>No rendering methods
1086      * will be called automatically on child components; this component is required to invoke the
1087      * encodeBegin/encodeEnd/etc on them itself.
1088      * </ul>
1089      */
1090     @Override
1091     public boolean getRendersChildren()
1092     {
1093         Renderer renderer = getRenderer(getFacesContext());
1094         return renderer != null ? renderer.getRendersChildren() : false;
1095     }
1096 
1097     /**
1098      * Get the named value-binding associated with this component.
1099      * <p>
1100      * Value-bindings are stored in a map associated with the component, though there is commonly a property
1101      * (setter/getter methods) of the same name defined on the component itself which evaluates the value-binding when
1102      * called.
1103      * 
1104      * @deprecated Replaced by getValueExpression
1105      */
1106     @Override
1107     public ValueBinding getValueBinding(String name)
1108     {
1109         ValueExpression expression = getValueExpression(name);
1110         if (expression != null)
1111         {
1112             if (expression instanceof _ValueBindingToValueExpression)
1113             {
1114                 return ((_ValueBindingToValueExpression) expression).getValueBinding();
1115             }
1116             return new _ValueExpressionToValueBinding(expression);
1117         }
1118         return null;
1119     }
1120     
1121     public boolean initialStateMarked()
1122     {
1123         // TODO: IMPLEMENT HERE
1124         // FIXME: Nofity EG, this method should be in the specification
1125         return super.initialStateMarked();
1126     }
1127     
1128     /**
1129      * <code>invokeOnComponent</code> must be implemented in <code>UIComponentBase</code> too...
1130      */
1131     @Override
1132     public boolean invokeOnComponent(FacesContext context, String clientId, ContextCallback callback)
1133             throws FacesException
1134     {
1135         if (isCachedFacesContext())
1136         {
1137             return super.invokeOnComponent(context, clientId, callback);
1138         }
1139         else
1140         {
1141             try
1142             {
1143                 setCachedFacesContext(context);
1144                 return super.invokeOnComponent(context, clientId, callback);
1145             }
1146             finally
1147             {
1148                 setCachedFacesContext(null);
1149             }
1150         }
1151     }
1152     
1153     
1154 
1155     @Override
1156     public boolean visitTree(VisitContext context, VisitCallback callback)
1157     {
1158         if (isCachedFacesContext())
1159         {
1160             return super.visitTree(context, callback);
1161         }
1162         else
1163         {
1164             try
1165             {
1166                 setCachedFacesContext(context.getFacesContext());
1167                 return super.visitTree(context, callback);
1168             }
1169             finally
1170             {
1171                 setCachedFacesContext(null);
1172             }
1173         }
1174     }
1175 
1176     /**
1177      * A boolean value that indicates whether this component should be rendered. Default value: true.
1178      **/
1179     @Override
1180     @JSFProperty
1181     public boolean isRendered()
1182     {
1183         if (_cachedIsRendered != null)
1184         {
1185             return Boolean.TRUE.equals(_cachedIsRendered);
1186         }
1187         return (Boolean) getStateHelper().eval(PropertyKeys.rendered, DEFAULT_RENDERED);
1188     }
1189 
1190     @JSFProperty(literalOnly = true, istransient = true, tagExcluded = true)
1191     public boolean isTransient()
1192     {
1193         return _transient;
1194     }
1195     
1196     public void markInitialState()
1197     {
1198         super.markInitialState();
1199         if (_facesListeners != null)
1200         {
1201             _facesListeners.markInitialState();
1202         }
1203         if (_behaviorsMap != null)
1204         {
1205             for (Map.Entry<String, List<ClientBehavior> > entry : _behaviorsMap.entrySet())
1206             {
1207                 ((PartialStateHolder) entry.getValue()).markInitialState();
1208             }
1209         }
1210         if (_systemEventListenerClassMap != null)
1211         {
1212             for (Map.Entry<Class<? extends SystemEvent>, List<SystemEventListener>> entry : 
1213                 _systemEventListenerClassMap.entrySet())
1214             {
1215                 ((PartialStateHolder) entry.getValue()).markInitialState();
1216             }
1217         }
1218     }
1219 
1220     @Override
1221     protected void addFacesListener(FacesListener listener)
1222     {
1223         if (listener == null)
1224         {
1225             throw new NullPointerException("listener");
1226         }
1227         if (_facesListeners == null)
1228         {
1229             // How many facesListeners have single component normally? 
1230             _facesListeners = new _DeltaList<FacesListener>(new ArrayList<FacesListener>(5));
1231         }
1232         _facesListeners.add(listener);
1233     }
1234 
1235     @Override
1236     protected FacesContext getFacesContext()
1237     {
1238         if (_facesContext == null)
1239         {
1240             return FacesContext.getCurrentInstance();
1241         }
1242         else
1243         {
1244             return _facesContext;
1245         }
1246     }
1247 
1248     // FIXME: Notify EG for generic usage
1249     @Override
1250     protected FacesListener[] getFacesListeners(Class clazz)
1251     {
1252         if (clazz == null)
1253         {
1254             throw new NullPointerException("Class is null");
1255         }
1256         if (!FacesListener.class.isAssignableFrom(clazz))
1257         {
1258             throw new IllegalArgumentException("Class " + clazz.getName() + " must implement " + FacesListener.class);
1259         }
1260 
1261         if (_facesListeners == null)
1262         {
1263             return (FacesListener[]) Array.newInstance(clazz, 0);
1264         }
1265         List<FacesListener> lst = null;
1266         // perf: _facesListeners is RandomAccess instance (javax.faces.component._DeltaList)
1267         for (int i = 0, size = _facesListeners.size(); i < size; i++)
1268         {
1269             FacesListener facesListener = _facesListeners.get(i);
1270             if (facesListener != null && clazz.isAssignableFrom(facesListener.getClass()))
1271             {
1272                 if (lst == null)
1273                 {
1274                     lst = new ArrayList<FacesListener>();
1275                 }
1276                 lst.add(facesListener);
1277             }
1278         }
1279         if (lst == null)
1280         {
1281             return (FacesListener[]) Array.newInstance(clazz, 0);
1282         }
1283 
1284         return lst.toArray((FacesListener[]) Array.newInstance(clazz, lst.size()));
1285     }
1286 
1287     @Override
1288     protected Renderer getRenderer(FacesContext context)
1289     {
1290         if (context == null)
1291         {
1292             throw new NullPointerException("context");
1293         }
1294         Renderer renderer = getCachedRenderer();
1295         if (renderer != null)
1296         {
1297             return renderer;
1298         }
1299         String rendererType = getRendererType();
1300         if (rendererType == null)
1301         {
1302             return null;
1303         }
1304         
1305         RenderKit renderKit = context.getRenderKit();
1306         renderer = renderKit.getRenderer(getFamily(), rendererType);
1307         if (renderer == null)
1308         {
1309             String location = getComponentLocation(this);
1310             String logStr = "No Renderer found for component " + getPathToComponent(this)
1311                     + " (component-family=" + getFamily()
1312                     + ", renderer-type=" + rendererType + ")"
1313                     + (location != null ? " created from: " + location : "");
1314             
1315             getFacesContext().getExternalContext().log(logStr);
1316             log.warning(logStr);
1317         }
1318         return renderer;
1319     }
1320 
1321     @Override
1322     protected void removeFacesListener(FacesListener listener)
1323     {
1324         if (listener == null)
1325         {
1326             throw new NullPointerException("listener is null");
1327         }
1328 
1329         if (_facesListeners != null)
1330         {
1331             _facesListeners.remove(listener);
1332         }
1333     }
1334 
1335     @Override
1336     public void queueEvent(FacesEvent event)
1337     {
1338         if (event == null)
1339         {
1340             throw new NullPointerException("event");
1341         }
1342         UIComponent parent = getParent();
1343         if (parent == null)
1344         {
1345             throw new IllegalStateException("component is not a descendant of a UIViewRoot");
1346         }
1347         parent.queueEvent(event);
1348     }
1349 
1350     @Override
1351     public void processDecodes(FacesContext context)
1352     {
1353         try
1354         {
1355             setCachedFacesContext(context);
1356             // Call UIComponent.pushComponentToEL(javax.faces.context.FacesContext, javax.faces.component.UIComponent)
1357             pushComponentToEL(context, this);
1358             if (_isPhaseExecutable(context))
1359             {
1360                 // Call the processDecodes() method of all facets and children of this UIComponent, in the order
1361                 // determined by a call to getFacetsAndChildren().
1362                 int facetCount = getFacetCount();
1363                 if (facetCount > 0)
1364                 {
1365                     for (UIComponent facet : getFacets().values())
1366                     {
1367                         facet.processDecodes(context);
1368                     }
1369                 }
1370                 for (int i = 0, childCount = getChildCount(); i < childCount; i++)
1371                 {
1372                     UIComponent child = getChildren().get(i);
1373                     child.processDecodes(context);
1374                 }
1375 
1376                 try
1377                 {
1378                     // Call the decode() method of this component.
1379                     decode(context);
1380                 }
1381                 catch (RuntimeException e)
1382                 {
1383                     // If a RuntimeException is thrown during decode processing, call FacesContext.renderResponse()
1384                     // and re-throw the exception.
1385                     context.renderResponse();
1386                     throw e;
1387                 }
1388             }
1389         }
1390         finally
1391         {
1392             // Call UIComponent.popComponentFromEL(javax.faces.context.FacesContext) from inside of a finally
1393             // block, just before returning.
1394 
1395             popComponentFromEL(context);
1396             setCachedFacesContext(null);
1397         }
1398     }
1399 
1400     @Override
1401     public void processValidators(FacesContext context)
1402     {
1403         try
1404         {
1405             setCachedFacesContext(context);
1406             // Call UIComponent.pushComponentToEL(javax.faces.context.FacesContext, javax.faces.component.UIComponent)
1407             pushComponentToEL(context, this);
1408             if (_isPhaseExecutable(context))
1409             {
1410                 //Pre validation event dispatch for component
1411                 context.getApplication().publishEvent(context,  PreValidateEvent.class, getClass(), this);
1412                 
1413                 try
1414                 {
1415                     // Call the processValidators() method of all facets and children of this UIComponent, in the order
1416                     // determined by a call to getFacetsAndChildren().
1417                     int facetCount = getFacetCount();
1418                     if (facetCount > 0)
1419                     {
1420                         for (UIComponent facet : getFacets().values())
1421                         {
1422                             facet.processValidators(context);
1423                         }
1424                     }
1425     
1426                     for (int i = 0, childCount = getChildCount(); i < childCount; i++)
1427                     {
1428                         UIComponent child = getChildren().get(i);
1429                         child.processValidators(context);
1430                     }
1431                 }
1432                 finally
1433                 {
1434                     context.getApplication().publishEvent(context,  PostValidateEvent.class, getClass(), this);
1435                 }
1436             }
1437         }
1438         finally
1439         {
1440             popComponentFromEL(context);
1441             setCachedFacesContext(null);
1442         }
1443     }
1444 
1445     /**
1446      * This isn't an input component, so just pass on the processUpdates call to child components and facets that might
1447      * be input components.
1448      * <p>
1449      * Components that were never rendered can't possibly be receiving update data (no corresponding fields were ever
1450      * put into the response) so if this component is not rendered then this method does not invoke processUpdates on
1451      * its children.
1452      */
1453     @Override
1454     public void processUpdates(FacesContext context)
1455     {
1456         try
1457         {
1458             setCachedFacesContext(context);
1459             // Call UIComponent.pushComponentToEL(javax.faces.context.FacesContext, javax.faces.component.UIComponent)
1460             pushComponentToEL(context, this);
1461             if (_isPhaseExecutable(context))
1462             {
1463                 // Call the processUpdates() method of all facets and children of this UIComponent, in the order
1464                 // determined by a call to getFacetsAndChildren().
1465                 int facetCount = getFacetCount();
1466                 if (facetCount > 0)
1467                 {
1468                     for (UIComponent facet : getFacets().values())
1469                     {
1470                         facet.processUpdates(context);
1471                     }
1472                 }
1473 
1474                 for (int i = 0, childCount = getChildCount(); i < childCount; i++)
1475                 {
1476                     UIComponent child = getChildren().get(i);
1477                     child.processUpdates(context);
1478                 }
1479                 popComponentFromEL(context);
1480             }
1481         }
1482         finally
1483         {
1484             // After returning from the processUpdates() method on a child or facet, call
1485             // UIComponent.popComponentFromEL(javax.faces.context.FacesContext)
1486             setCachedFacesContext(null);
1487         }
1488     }
1489 
1490     @Override
1491     public Object processSaveState(FacesContext context)
1492     {
1493         if (context == null)
1494         {
1495             throw new NullPointerException("context");
1496         }
1497 
1498         if (isTransient())
1499         {
1500             // consult the transient property of this component. If true, just return null.
1501             return null;
1502         }
1503 
1504         // Call UIComponent.pushComponentToEL(javax.faces.context.FacesContext, javax.faces.component.UIComponent)
1505         pushComponentToEL(context, this);
1506 
1507         Map<String, Object> facetMap;
1508 
1509         List<Object> childrenList;
1510         
1511         Object savedState;
1512         try
1513         {
1514             facetMap = null;
1515             int facetCount = getFacetCount();
1516             if (facetCount > 0)
1517             {
1518                 // Call the processSaveState() method of all facets and children of this UIComponent in the order
1519                 // determined by a call to getFacetsAndChildren(), skipping children and facets that are transient.
1520 
1521                 // To improve speed and robustness, the facets and children processing is splited to maintain the
1522                 // facet --> state coherence based on the facet's name
1523                 for (Map.Entry<String, UIComponent> entry : getFacets().entrySet())
1524                 {
1525                     UIComponent component = entry.getValue();
1526                     if (!component.isTransient())
1527                     {
1528                         if (facetMap == null)
1529                         {
1530                             facetMap = new HashMap<String, Object>(facetCount, 1);
1531                         }
1532 
1533                         facetMap.put(entry.getKey(), component.processSaveState(context));
1534 
1535                         // Ensure that UIComponent.popComponentFromEL(javax.faces.context.FacesContext) is called
1536                         // correctly after each child or facet.
1537                         // popComponentFromEL(context);
1538                     }
1539                 }
1540             }
1541             childrenList = null;
1542             int childCount = getChildCount();
1543             if (childCount > 0)
1544             {
1545                 // Call the processSaveState() method of all facets and children of this UIComponent in the order
1546                 // determined by a call to getFacetsAndChildren(), skipping children and facets that are transient.
1547 
1548                 // To improve speed and robustness, the facets and children processing is splited to maintain the
1549                 // facet --> state coherence based on the facet's name
1550                 for (int i = 0; i < childCount; i++)
1551                 {
1552                     UIComponent child = getChildren().get(i);
1553                     if (!child.isTransient())
1554                     {
1555                         if (childrenList == null)
1556                         {
1557                             childrenList = new ArrayList<Object>(childCount);
1558                         }
1559 
1560                         Object childState = child.processSaveState(context);
1561                         if (childState != null)
1562                         { // FIXME: Isn't that check dangerous for restoration since the child isn't marked transient?
1563                             childrenList.add(childState);
1564                         }
1565 
1566                         // Ensure that UIComponent.popComponentFromEL(javax.faces.context.FacesContext) is called
1567                         // correctly after each child or facet.
1568                     }
1569                 }
1570             }
1571             
1572             // Call the saveState() method of this component.
1573             savedState = saveState(context);
1574         }
1575         finally
1576         {
1577             popComponentFromEL(context);
1578         }
1579 
1580         // Encapsulate the child state and your state into a Serializable Object and return it.
1581         return new Object[] { savedState, facetMap, childrenList };
1582     }
1583 
1584     @SuppressWarnings("unchecked")
1585     @Override
1586     public void processRestoreState(FacesContext context, Object state)
1587     {
1588         if (context == null)
1589         {
1590             throw new NullPointerException("context");
1591         }
1592 
1593         Object[] stateValues = (Object[]) state;
1594 
1595         try
1596         {
1597             // Call UIComponent.pushComponentToEL(javax.faces.context.FacesContext, javax.faces.component.UIComponent)
1598             pushComponentToEL(context, this);
1599 
1600             // Call the restoreState() method of this component.
1601             restoreState(context, stateValues[0]);
1602             
1603             Map<String, Object> facetMap = (Map<String, Object>) stateValues[1];
1604             if (facetMap != null && getFacetCount() > 0)
1605             {
1606                 // Call the processRestoreState() method of all facets and children of this UIComponent in the order
1607                 // determined by a call to getFacetsAndChildren().
1608 
1609                 // To improve speed and robustness, the facets and children processing is splited to maintain the
1610                 // facet --> state coherence based on the facet's name
1611                 for (Map.Entry<String, UIComponent> entry : getFacets().entrySet())
1612                 {
1613                     Object facetState = facetMap.get(entry.getKey());
1614                     if (facetState != null)
1615                     {
1616                         entry.getValue().processRestoreState(context, facetState);
1617 
1618                         // After returning from the processRestoreState() method on a child or facet, call
1619                         // UIComponent.popComponentFromEL(javax.faces.context.FacesContext)
1620                         // popComponentFromEL(context);
1621                     }
1622                     else
1623                     {
1624                         context.getExternalContext().log("No state found to restore facet " + entry.getKey());
1625                     }
1626                 }
1627             }
1628             List<Object> childrenList = (List<Object>) stateValues[2];
1629             if (childrenList != null && getChildCount() > 0)
1630             {
1631                 // Call the processRestoreState() method of all facets and children of this UIComponent in the order
1632                 // determined by a call to getFacetsAndChildren().
1633 
1634                 // To improve speed and robustness, the facets and children processing is splited to maintain the
1635                 // facet --> state coherence based on the facet's name
1636                 int idx = 0;
1637                 for (int i = 0, childCount = getChildCount(); i < childCount; i++)
1638                 {
1639                     UIComponent child = getChildren().get(i);
1640                     if (!child.isTransient())
1641                     {
1642                         Object childState = childrenList.get(idx++);
1643                         if (childState != null)
1644                         {
1645                             child.processRestoreState(context, childState);
1646 
1647                             // After returning from the processRestoreState() method on a child or facet, call
1648                             // UIComponent.popComponentFromEL(javax.faces.context.FacesContext)
1649                             // popComponentFromEL(context);
1650                         }
1651                         else
1652                         {
1653                             context.getExternalContext().log("No state found to restore child of component " + getId());
1654                         }
1655                     }
1656                 }
1657             }
1658         }
1659         finally
1660         {
1661             popComponentFromEL(context);
1662         }
1663     }
1664     
1665     /**
1666      * Gets the Location of the given UIComponent from its attribute map.
1667      * @param component
1668      * @return
1669      */
1670     private String getComponentLocation(UIComponent component)
1671     {
1672         Location location = (Location) component.getAttributes()
1673                 .get(UIComponent.VIEW_LOCATION_KEY);
1674         if (location != null)
1675         {
1676             return location.toString();
1677         }
1678         return null;
1679     }
1680 
1681     private String getPathToComponent(UIComponent component)
1682     {
1683         StringBuffer buf = new StringBuffer();
1684 
1685         if (component == null)
1686         {
1687             buf.append("{Component-Path : ");
1688             buf.append("[null]}");
1689             return buf.toString();
1690         }
1691 
1692         getPathToComponent(component, buf);
1693 
1694         buf.insert(0, "{Component-Path : ");
1695         buf.append("}");
1696 
1697         return buf.toString();
1698     }
1699 
1700     private void getPathToComponent(UIComponent component, StringBuffer buf)
1701     {
1702         if (component == null)
1703         {
1704             return;
1705         }
1706 
1707         StringBuffer intBuf = new StringBuffer();
1708 
1709         intBuf.append("[Class: ");
1710         intBuf.append(component.getClass().getName());
1711         if (component instanceof UIViewRoot)
1712         {
1713             intBuf.append(",ViewId: ");
1714             intBuf.append(((UIViewRoot) component).getViewId());
1715         }
1716         else
1717         {
1718             intBuf.append(",Id: ");
1719             intBuf.append(component.getId());
1720         }
1721         intBuf.append("]");
1722 
1723         buf.insert(0, intBuf.toString());
1724 
1725         getPathToComponent(component.getParent(), buf);
1726     }
1727 
1728     public void setTransient(boolean transientFlag)
1729     {
1730         _transient = transientFlag;
1731     }
1732 
1733     /**
1734      * Serializes objects which are "attached" to this component but which are not UIComponent children of it. Examples
1735      * are validator and listener objects. To be precise, it returns an object which implements java.io.Serializable,
1736      * and which when serialized will persist the state of the provided object.
1737      * <p>
1738      * If the attachedObject is a List then every object in the list is saved via a call to this method, and the
1739      * returned wrapper object contains a List object.
1740      * <p>
1741      * If the object implements StateHolder then the object's saveState is called immediately, and a wrapper is returned
1742      * which contains both this saved state and the original class name. However in the case where the
1743      * StateHolder.isTransient method returns true, null is returned instead.
1744      * <p>
1745      * If the object implements java.io.Serializable then the object is simply returned immediately; standard java
1746      * serialization will later be used to store this object.
1747      * <p>
1748      * In all other cases, a wrapper is returned which simply stores the type of the provided object. When deserialized,
1749      * a default instance of that type will be recreated.
1750      */
1751     public static Object saveAttachedState(FacesContext context, Object attachedObject)
1752     {
1753         if (context == null)
1754         {
1755             throw new NullPointerException ("context");
1756         }
1757         
1758         if (attachedObject == null)
1759         {
1760             return null;
1761         }
1762         // StateHolder interface should take precedence over
1763         // List children
1764         if (attachedObject instanceof StateHolder)
1765         {
1766             StateHolder holder = (StateHolder) attachedObject;
1767             if (holder.isTransient())
1768             {
1769                 return null;
1770             }
1771 
1772             return new _AttachedStateWrapper(attachedObject.getClass(), holder.saveState(context));
1773         }
1774         else if (attachedObject instanceof Collection)
1775         {
1776             if (ArrayList.class.equals(attachedObject.getClass()))
1777             {
1778                 ArrayList<?> list = (ArrayList<?>) attachedObject;
1779                 int size = list.size();
1780                 List<Object> lst = new ArrayList<Object>(size);
1781                 for (int i = 0; i < size; i++)
1782                 {
1783                     Object item = list.get(i);
1784                     if (item != null)
1785                     {
1786                         lst.add(saveAttachedState(context, item));
1787                     }
1788                 }
1789                 return new _AttachedListStateWrapper(lst);
1790             }
1791             else
1792             {
1793                 List<Object> lst = new ArrayList<Object>(((Collection<?>) attachedObject).size());
1794                 for (Object item : (Collection<?>) attachedObject)
1795                 {
1796                     if (item != null)
1797                     {
1798                         lst.add(saveAttachedState(context, item));
1799                     }
1800                 }
1801                 return new _AttachedCollectionStateWrapper(attachedObject.getClass(), lst);
1802             }
1803         }
1804         else if (attachedObject instanceof Serializable)
1805         {
1806             return attachedObject;
1807         }
1808         else
1809         {
1810             return new _AttachedStateWrapper(attachedObject.getClass(), null);
1811         }
1812     }
1813 
1814     public static Object restoreAttachedState(FacesContext context, Object stateObj) throws IllegalStateException
1815     {
1816         if (context == null)
1817         {
1818             throw new NullPointerException("context");
1819         }
1820         if (stateObj == null)
1821         {
1822             return null;
1823         }
1824         if (stateObj instanceof _AttachedListStateWrapper)
1825         {
1826             // perf: getWrappedStateList in _AttachedListStateWrapper is always ArrayList: see saveAttachedState
1827             ArrayList<Object> lst = (ArrayList<Object>) ((_AttachedListStateWrapper) stateObj).getWrappedStateList();
1828             List<Object> restoredList = new ArrayList<Object>(lst.size());
1829             for (int i = 0, size = lst.size(); i < size; i++)
1830             {
1831                 Object item = lst.get(i);
1832                 restoredList.add(restoreAttachedState(context, item));
1833             }
1834             return restoredList;
1835         }
1836         else if (stateObj instanceof _AttachedCollectionStateWrapper)
1837         {
1838             _AttachedCollectionStateWrapper wrappedState = (_AttachedCollectionStateWrapper) stateObj; 
1839             Class<?> clazz = wrappedState.getClazz();
1840             List<Object> lst = wrappedState.getWrappedStateList();
1841             Collection restoredList;
1842             try
1843             {
1844                 restoredList = (Collection) clazz.newInstance();
1845             }
1846             catch (InstantiationException e)
1847             {
1848                 throw new RuntimeException("Could not restore StateHolder of type " + clazz.getName()
1849                         + " (missing no-args constructor?)", e);
1850             }
1851             catch (IllegalAccessException e)
1852             {
1853                 throw new RuntimeException(e);
1854             }
1855 
1856             for (Object item : lst)
1857             {
1858                 restoredList.add(restoreAttachedState(context, item));
1859             }
1860             return restoredList;
1861 
1862         }
1863         else if (stateObj instanceof _AttachedStateWrapper)
1864         {
1865             Class<?> clazz = ((_AttachedStateWrapper) stateObj).getClazz();
1866             Object restoredObject;
1867             try
1868             {
1869                 restoredObject = clazz.newInstance();
1870             }
1871             catch (InstantiationException e)
1872             {
1873                 throw new RuntimeException("Could not restore StateHolder of type " + clazz.getName()
1874                         + " (missing no-args constructor?)", e);
1875             }
1876             catch (IllegalAccessException e)
1877             {
1878                 throw new RuntimeException(e);
1879             }
1880             if (restoredObject instanceof StateHolder)
1881             {
1882                 _AttachedStateWrapper wrapper = (_AttachedStateWrapper) stateObj;
1883                 Object wrappedState = wrapper.getWrappedStateObject();
1884 
1885                 StateHolder holder = (StateHolder) restoredObject;
1886                 holder.restoreState(context, wrappedState);
1887             }
1888             return restoredObject;
1889         }
1890         else
1891         {
1892             return stateObj;
1893         }
1894     }
1895 
1896     /**
1897      * Invoked after the render phase has completed, this method returns an object which can be passed to the
1898      * restoreState of some other instance of UIComponentBase to reset that object's state to the same values as this
1899      * object currently has.
1900      */
1901     public Object saveState(FacesContext context)
1902     {
1903         if (context == null)
1904         {
1905             throw new NullPointerException ("context");
1906         }
1907         
1908         if (initialStateMarked())
1909         {
1910             //Delta
1911             //_id and _clientId was already restored from template
1912             //and never changes during component life.
1913             Object facesListenersSaved = saveFacesListenersList(context);
1914             Object behaviorsMapSaved = saveBehaviorsMap(context);
1915             Object systemEventListenerClassMapSaved = saveSystemEventListenerClassMap(context);
1916             Object stateHelperSaved = null;
1917             StateHelper stateHelper = getStateHelper(false);
1918             if (stateHelper != null)
1919             {
1920                 stateHelperSaved = stateHelper.saveState(context);
1921             }
1922             
1923             if (facesListenersSaved == null && stateHelperSaved == null && 
1924                 behaviorsMapSaved == null && systemEventListenerClassMapSaved == null &&
1925                !_isRendererTypeSet)
1926             {
1927                 return null;
1928             }
1929             
1930             if (_isRendererTypeSet)
1931             {
1932                 return new Object[] {facesListenersSaved, stateHelperSaved, behaviorsMapSaved,
1933                                     systemEventListenerClassMapSaved, 
1934                                     _rendererType};
1935             }
1936             else
1937             {
1938                 return new Object[] {facesListenersSaved, stateHelperSaved, behaviorsMapSaved,
1939                     systemEventListenerClassMapSaved};
1940             }
1941         }
1942         else
1943         {
1944             //Full
1945             Object values[] = new Object[11];
1946             values[0] = saveFacesListenersList(context);
1947             StateHelper stateHelper = getStateHelper(false);
1948             if (stateHelper != null)
1949             {
1950                 values[1] = stateHelper.saveState(context);
1951             }
1952             values[2] = saveBehaviorsMap(context);
1953             values[3] = saveSystemEventListenerClassMap(context);
1954             values[4] = _id;
1955             values[5] = _clientId;
1956             values[6] = _markCreated;
1957             values[7] = _rendererType;
1958             values[8] = _isRendererTypeSet;
1959             values[9] = _addedByHandler;
1960             values[10] = _facetCreatedUIPanel;
1961 
1962             return values;
1963         }
1964     }
1965 
1966     /**
1967      * Invoked in the "restore view" phase, this initialises this object's members from the values saved previously into
1968      * the provided state object.
1969      * <p>
1970      * 
1971      * @param state
1972      *            is an object previously returned by the saveState method of this class.
1973      */
1974     @SuppressWarnings("unchecked")
1975     public void restoreState(FacesContext context, Object state)
1976     {
1977         if (context == null)
1978         {
1979             throw new NullPointerException ("context");
1980         }
1981         
1982         if (state == null)
1983         {
1984             //Only happens if initialStateMarked return true
1985             
1986             if (initialStateMarked())
1987             {
1988                 return;
1989             }
1990             
1991             throw new NullPointerException ("state");
1992         }
1993         
1994         Object values[] = (Object[]) state;
1995         
1996         if ( values.length == 11 && initialStateMarked())
1997         {
1998             //Delta mode is active, but we are restoring a full state.
1999             //we need to clear the initial state, to restore state without
2000             //take into account delta.
2001             clearInitialState();
2002         }
2003         
2004         if (values[0] instanceof _AttachedDeltaWrapper)
2005         {
2006             //Delta: check for null is not necessary since _facesListener field
2007             //is only set once and never reset
2008             //if (_facesListeners != null)
2009             //{
2010                 ((StateHolder)_facesListeners).restoreState(context,
2011                         ((_AttachedDeltaWrapper) values[0]).getWrappedStateObject());
2012             //}
2013         }
2014         else if (values[0] != null || (values.length == 11))
2015         {
2016             //Full
2017             _facesListeners = (_DeltaList<FacesListener>)
2018                 restoreAttachedState(context,values[0]);
2019         }
2020         // Note that if values[0] == null && initialStateMarked(),
2021         // means delta is null, not that _facesListeners == null. 
2022         // We can do this here because _facesListeners instance once
2023         // is created is never replaced or set to null.
2024         
2025         getStateHelper().restoreState(context, values[1]);
2026         
2027         if (values.length == 11)
2028         {
2029             _id = (String) values[4];
2030             _clientId = (String) values[5];
2031             _markCreated = (String) values[6];
2032             _rendererType = (String) values[7];
2033             _isRendererTypeSet = (Boolean) values[8];
2034             _addedByHandler = (Boolean) values[9];
2035             _facetCreatedUIPanel = (Boolean) values[10];
2036         }
2037         else if (values.length == 5)
2038         {
2039             _rendererType = (String) values[4];
2040             _isRendererTypeSet = true;
2041         }
2042 
2043         // rendererType needs to be restored before SystemEventListener,
2044         // otherwise UIComponent.getCurrentComponent(context).getRenderer(context)
2045         // will not work correctly
2046         if (values.length == 11)
2047         {
2048             //Full restore
2049             restoreFullBehaviorsMap(context, values[2]);
2050             restoreFullSystemEventListenerClassMap(context, values[3]);
2051         }
2052         else
2053         {
2054             //Delta restore
2055             restoreDeltaBehaviorsMap(context, values[2]);
2056             restoreDeltaSystemEventListenerClassMap(context, values[3]);
2057         }
2058     }
2059     
2060     private Object saveFacesListenersList(FacesContext facesContext)
2061     {
2062         PartialStateHolder holder = (PartialStateHolder) _facesListeners;
2063         if (initialStateMarked() && _facesListeners != null && holder.initialStateMarked())
2064         {                
2065             Object attachedState = holder.saveState(facesContext);
2066             if (attachedState != null)
2067             {
2068                 return new _AttachedDeltaWrapper(_facesListeners.getClass(),
2069                         attachedState);
2070             }
2071             //_facesListeners instances once is created never changes, we can return null
2072             return null;
2073         }
2074         else
2075         {
2076             return saveAttachedState(facesContext,_facesListeners);
2077         }            
2078     }
2079 
2080     @SuppressWarnings("unchecked")
2081     private void restoreFullBehaviorsMap(FacesContext facesContext, Object stateObj)
2082     {
2083         if (stateObj != null)
2084         {
2085             Map<String, Object> stateMap = (Map<String, Object>) stateObj;
2086             int initCapacity = (stateMap.size() * 4 + 3) / 3;
2087             _behaviorsMap = new HashMap<String,  List<ClientBehavior> >(initCapacity);
2088             _unmodifiableBehaviorsMap = null;
2089             for (Map.Entry<String, Object> entry : stateMap.entrySet())
2090             {
2091                 _behaviorsMap.put(entry.getKey(),
2092                                   (List<ClientBehavior>) restoreAttachedState(facesContext, entry.getValue()));
2093             }
2094         }
2095         else
2096         {
2097             _behaviorsMap = null;
2098             _unmodifiableBehaviorsMap = null;
2099         }        
2100     }
2101     
2102     @SuppressWarnings("unchecked")
2103     private void restoreDeltaBehaviorsMap(FacesContext facesContext, Object stateObj)
2104     {
2105         if (stateObj != null)
2106         {
2107             _unmodifiableBehaviorsMap = null;
2108             Map<String, Object> stateMap = (Map<String, Object>) stateObj;
2109             int initCapacity = (stateMap.size() * 4 + 3) / 3;
2110             if (_behaviorsMap == null)
2111             {
2112                 _behaviorsMap = new HashMap<String,  List<ClientBehavior> >(initCapacity);
2113             }
2114             for (Map.Entry<String, Object> entry : stateMap.entrySet())
2115             {
2116                 Object savedObject = entry.getValue(); 
2117                 if (savedObject instanceof _AttachedDeltaWrapper)
2118                 {
2119                     StateHolder holderList = (StateHolder) _behaviorsMap.get(entry.getKey());
2120                     holderList.restoreState(facesContext,
2121                                             ((_AttachedDeltaWrapper) savedObject).getWrappedStateObject());
2122                 }
2123                 else
2124                 {
2125                     _behaviorsMap.put(entry.getKey(),
2126                                       (List<ClientBehavior>) restoreAttachedState(facesContext, savedObject));
2127                 }
2128             }
2129         }
2130     }
2131     
2132     private Object saveBehaviorsMap(FacesContext facesContext)
2133     {
2134         if (_behaviorsMap != null)
2135         {
2136             if (initialStateMarked())
2137             {
2138                 HashMap<String, Object> stateMap = new HashMap<String, Object>(_behaviorsMap.size(), 1);
2139                 boolean nullDelta = true;
2140                 for (Map.Entry<String, List<ClientBehavior> > entry : _behaviorsMap.entrySet())
2141                 {
2142                     // The list is always an instance of _DeltaList so we can cast to
2143                     // PartialStateHolder 
2144                     PartialStateHolder holder = (PartialStateHolder) entry.getValue();
2145                     if (holder.initialStateMarked())
2146                     {
2147                         Object attachedState = holder.saveState(facesContext);
2148                         if (attachedState != null)
2149                         {
2150                             stateMap.put(entry.getKey(), new _AttachedDeltaWrapper(_behaviorsMap.getClass(),
2151                                     attachedState));
2152                             nullDelta = false;
2153                         }
2154                     }
2155                     else
2156                     {
2157                         stateMap.put(entry.getKey(), saveAttachedState(facesContext, holder));
2158                         nullDelta = false;
2159                     }
2160                 }
2161                 if (nullDelta)
2162                 {
2163                     return null;
2164                 }
2165                 return stateMap;
2166             }
2167             else
2168             {
2169                 //Save it in the traditional way
2170                 HashMap<String, Object> stateMap = 
2171                     new HashMap<String, Object>(_behaviorsMap.size(), 1);
2172                 for (Map.Entry<String, List<ClientBehavior> > entry : _behaviorsMap.entrySet())
2173                 {
2174                     stateMap.put(entry.getKey(), saveAttachedState(facesContext, entry.getValue()));
2175                 }
2176                 return stateMap;
2177             }
2178         }
2179         else
2180         {
2181             return null;
2182         }
2183     }
2184     
2185     @SuppressWarnings("unchecked")
2186     private void restoreFullSystemEventListenerClassMap(FacesContext facesContext, Object stateObj)
2187     {
2188         if (stateObj != null)
2189         {
2190             Map<Class<? extends SystemEvent>, Object> stateMap = (Map<Class<? extends SystemEvent>, Object>) stateObj;
2191             int initCapacity = (stateMap.size() * 4 + 3) / 3;
2192             _systemEventListenerClassMap
2193                     = new HashMap<Class<? extends SystemEvent>, List<SystemEventListener>>(initCapacity);
2194             for (Map.Entry<Class<? extends SystemEvent>, Object> entry : stateMap.entrySet())
2195             {
2196                 _systemEventListenerClassMap.put(entry.getKey(),
2197                         (List<SystemEventListener>) restoreAttachedState(facesContext, entry.getValue()));
2198             }
2199         }
2200         else
2201         {
2202             _systemEventListenerClassMap = null;
2203         }        
2204     }
2205     
2206     @SuppressWarnings("unchecked")
2207     private void restoreDeltaSystemEventListenerClassMap(FacesContext facesContext, Object stateObj)
2208     {
2209         if (stateObj != null)
2210         {
2211             Map<Class<? extends SystemEvent>, Object> stateMap = (Map<Class<? extends SystemEvent>, Object>) stateObj;
2212             int initCapacity = (stateMap.size() * 4 + 3) / 3;
2213             if (_systemEventListenerClassMap == null)
2214             {
2215                 _systemEventListenerClassMap
2216                         = new HashMap<Class<? extends SystemEvent>, List<SystemEventListener>>(initCapacity);
2217             }
2218             for (Map.Entry<Class<? extends SystemEvent>, Object> entry : stateMap.entrySet())
2219             {
2220                 Object savedObject = entry.getValue(); 
2221                 if (savedObject instanceof _AttachedDeltaWrapper)
2222                 {
2223                     StateHolder holderList = (StateHolder) _systemEventListenerClassMap.get(entry.getKey());
2224                     holderList.restoreState(facesContext,
2225                                             ((_AttachedDeltaWrapper) savedObject).getWrappedStateObject());
2226                 }
2227                 else
2228                 {
2229                     _systemEventListenerClassMap.put(entry.getKey(),
2230                             (List<SystemEventListener>) restoreAttachedState(facesContext, savedObject));
2231                 }
2232             }
2233         }
2234     }
2235     
2236     private Object saveSystemEventListenerClassMap(FacesContext facesContext)
2237     {
2238         if (_systemEventListenerClassMap != null)
2239         {
2240             if (initialStateMarked())
2241             {
2242                 HashMap<Class<? extends SystemEvent>, Object> stateMap
2243                         = new HashMap<Class<? extends SystemEvent>, Object>(_systemEventListenerClassMap.size(), 1);
2244                 boolean nullDelta = true;
2245                 for (Map.Entry<Class<? extends SystemEvent>, List<SystemEventListener> > entry
2246                         : _systemEventListenerClassMap.entrySet())
2247                 {
2248                     // The list is always an instance of _DeltaList so we can cast to
2249                     // PartialStateHolder 
2250                     PartialStateHolder holder = (PartialStateHolder) entry.getValue();
2251                     if (holder.initialStateMarked())
2252                     {
2253                         Object attachedState = holder.saveState(facesContext);
2254                         if (attachedState != null)
2255                         {
2256                             stateMap.put(entry.getKey(),
2257                                     new _AttachedDeltaWrapper(_systemEventListenerClassMap.getClass(), attachedState));
2258                             nullDelta = false;
2259                         }
2260                     }
2261                     else
2262                     {
2263                         stateMap.put(entry.getKey(), saveAttachedState(facesContext, holder));
2264                         nullDelta = false;
2265                     }
2266                 }
2267                 if (nullDelta)
2268                 {
2269                     return null;
2270                 }
2271                 return stateMap;
2272             }
2273             else
2274             {
2275                 //Save it in the traditional way
2276                 HashMap<Class<? extends SystemEvent>, Object> stateMap = 
2277                     new HashMap<Class<? extends SystemEvent>, Object>(_systemEventListenerClassMap.size(), 1);
2278                 for (Map.Entry<Class<? extends SystemEvent>, List<SystemEventListener> > entry
2279                         : _systemEventListenerClassMap.entrySet())
2280                 {
2281                     stateMap.put(entry.getKey(), saveAttachedState(facesContext, entry.getValue()));
2282                 }
2283                 return stateMap;
2284             }
2285         }
2286         else
2287         {
2288             return null;
2289         }
2290     }
2291     
2292     /*
2293     private Object saveBindings(FacesContext context)
2294     {
2295         if (bindings != null)
2296         {
2297             HashMap<String, Object> stateMap = new HashMap<String, Object>(bindings.size(), 1);
2298             for (Iterator<Entry<String, ValueExpression>> it = bindings.entrySet().iterator(); it.hasNext();)
2299             {
2300                 Entry<String, ValueExpression> entry = it.next();
2301                 stateMap.put(entry.getKey(), saveAttachedState(context, entry.getValue()));
2302             }
2303             return stateMap;
2304         }
2305 
2306         return null;
2307     }
2308 
2309     @SuppressWarnings("unchecked")
2310     private void restoreValueExpressionMap(FacesContext context, Object stateObj)
2311     {
2312         if (stateObj != null)
2313         {
2314             Map<String, Object> stateMap = (Map<String, Object>) stateObj;
2315             int initCapacity = (stateMap.size() * 4 + 3) / 3;
2316             bindings = new HashMap<String, ValueExpression>(initCapacity);
2317             for (Map.Entry<String, Object> entry : stateMap.entrySet())
2318             {
2319                 bindings.put(entry.getKey(), (ValueExpression) restoreAttachedState(context, entry.getValue()));
2320             }
2321         }
2322         else
2323         {
2324             bindings = null;
2325         }
2326     }*/
2327 
2328     /**
2329      * @param string
2330      *            the component id, that should be a vaild one.
2331      */
2332     private void isIdValid(String string)
2333     {
2334 
2335         // is there any component identifier ?
2336         if (string == null)
2337         {
2338             return;
2339         }
2340 
2341         // Component identifiers must obey the following syntax restrictions:
2342         // 1. Must not be a zero-length String.
2343         if (string.length() == 0)
2344         {
2345             throw new IllegalArgumentException("component identifier must not be a zero-length String");
2346         }
2347 
2348         // If new id is the same as old it must be valid
2349         if (string.equals(_id))
2350         {
2351             return;
2352         }
2353 
2354         // 2. First character must be a letter or an underscore ('_').
2355         if (!Character.isLetter(string.charAt(0)) && string.charAt(0) != '_')
2356         {
2357             throw new IllegalArgumentException("component identifier's first character must be a letter "
2358                                                + "or an underscore ('_')! But it is \""
2359                                                + string.charAt(0) + "\"");
2360         }
2361         for (int i = 1; i < string.length(); i++)
2362         {
2363             char c = string.charAt(i);
2364             // 3. Subsequent characters must be a letter, a digit, an underscore ('_'), or a dash ('-').
2365             if (!Character.isLetterOrDigit(c) && c != '-' && c != '_')
2366             {
2367                 throw new IllegalArgumentException("Subsequent characters of component identifier must be a letter, "
2368                                                    + "a digit, an underscore ('_'), or a dash ('-')! "
2369                                                    + "But component identifier contains \""
2370                                                    + c + "\"");
2371             }
2372         }
2373     }
2374 
2375     private boolean _isPhaseExecutable(FacesContext context)
2376     {
2377         if (context == null)
2378         {
2379             throw new NullPointerException("context");
2380         }
2381 
2382         // If the rendered property of this UIComponent is false, skip further processing.
2383         return isRendered();
2384     }
2385 
2386     boolean isCachedFacesContext()
2387     {
2388         return _facesContext != null;
2389     }
2390     
2391     void setCachedFacesContext(FacesContext facesContext)
2392     {
2393         _facesContext = facesContext;
2394     }
2395     
2396     Renderer getCachedRenderer()
2397     {
2398         return _cachedRenderer;
2399     }
2400     
2401     void setCachedRenderer(Renderer renderer)
2402     {
2403         _cachedRenderer = renderer;
2404     }
2405 
2406     Boolean isCachedIsRendered()
2407     {
2408         return _cachedIsRendered;
2409     }
2410     
2411     void setCachedIsRendered(Boolean rendered)
2412     {
2413        _cachedIsRendered = rendered;
2414     }
2415     
2416     <T> T getExpressionValue(String attribute, T explizitValue, T defaultValueIfExpressionNull)
2417     {
2418         return _ComponentUtils.getExpressionValue(this, attribute, explizitValue, defaultValueIfExpressionNull);
2419     }
2420 
2421     void setOamVfMarkCreated(String markCreated)
2422     {
2423         _markCreated = markCreated;
2424     }
2425     
2426     String getOamVfMarkCreated()
2427     {
2428         return _markCreated;
2429     }
2430     
2431     String getOamVfFacetName()
2432     {
2433         return _facetName;
2434     }
2435     
2436     void setOamVfFacetName(String facetName)
2437     {
2438         _facetName = facetName;
2439     }
2440     
2441     boolean isOamVfAddedByHandler()
2442     {
2443         return _addedByHandler;
2444     }
2445     
2446     void setOamVfAddedByHandler(boolean addedByHandler)
2447     {
2448         _addedByHandler = addedByHandler;
2449     }
2450     
2451     boolean isOamVfFacetCreatedUIPanel()
2452     {
2453         return _facetCreatedUIPanel;
2454     }
2455     
2456     void setOamVfFacetCreatedUIPanel(boolean facetCreatedUIPanel)
2457     {
2458         _facetCreatedUIPanel = facetCreatedUIPanel;
2459     }
2460 
2461 /**
2462      * <p>
2463      * This gets a single FacesContext-local shared stringbuilder instance, each time you call
2464      * _getSharedStringBuilder it sets the length of the stringBuilder instance to 0.
2465      * </p><p>
2466      * This allows you to use the same StringBuilder instance over and over.
2467      * You must call toString on the instance before calling _getSharedStringBuilder again.
2468      * </p>
2469      * Example that works
2470      * <pre><code>
2471      * StringBuilder sb1 = _getSharedStringBuilder();
2472      * sb1.append(a).append(b);
2473      * String c = sb1.toString();
2474      *
2475      * StringBuilder sb2 = _getSharedStringBuilder();
2476      * sb2.append(b).append(a);
2477      * String d = sb2.toString();
2478      * </code></pre>
2479      * <br><br>
2480      * Example that doesn't work, you must call toString on sb1 before
2481      * calling _getSharedStringBuilder again.
2482      * <pre><code>
2483      * StringBuilder sb1 = _getSharedStringBuilder();
2484      * StringBuilder sb2 = _getSharedStringBuilder();
2485      *
2486      * sb1.append(a).append(b);
2487      * String c = sb1.toString();
2488      *
2489      * sb2.append(b).append(a);
2490      * String d = sb2.toString();
2491      * </code></pre>
2492      *
2493      */
2494     static StringBuilder _getSharedStringBuilder()
2495     {
2496         return _getSharedStringBuilder(FacesContext.getCurrentInstance());
2497     }
2498 
2499     // TODO checkstyle complains; does this have to lead with __ ?
2500     static StringBuilder _getSharedStringBuilder(FacesContext facesContext)
2501     {
2502         Map<Object, Object> attributes = facesContext.getAttributes();
2503 
2504         StringBuilder sb = (StringBuilder) attributes.get(_STRING_BUILDER_KEY);
2505 
2506         if (sb == null)
2507         {
2508             sb = new StringBuilder();
2509             attributes.put(_STRING_BUILDER_KEY, sb);
2510         }
2511         else
2512         {
2513 
2514             // clear out the stringBuilder by setting the length to 0
2515             sb.setLength(0);
2516         }
2517 
2518         return sb;
2519     }
2520 
2521     // ------------------ GENERATED CODE BEGIN (do not modify!) --------------------
2522 
2523     private static final Boolean DEFAULT_RENDERED = Boolean.TRUE;
2524 
2525     @Override
2526     public void setRendered(boolean rendered)
2527     {
2528         getStateHelper().put(PropertyKeys.rendered, rendered );
2529         setCachedIsRendered(null);
2530     }
2531 
2532     @Override
2533     public void setRendererType(String rendererType)
2534     {
2535         this._rendererType = rendererType;
2536         if (initialStateMarked())
2537         {
2538             //This flag just indicates the rendererType 
2539             //should be included on the delta
2540             this._isRendererTypeSet = true;
2541         }
2542         setCachedRenderer(null);
2543     }
2544 
2545     // ------------------ GENERATED CODE END ---------------------------------------
2546 
2547     private Map<String, List<ClientBehavior>> wrapBehaviorsMap()
2548     {
2549         if (_unmodifiableBehaviorsMap == null)
2550         {
2551             _unmodifiableBehaviorsMap = Collections.unmodifiableMap(_behaviorsMap); 
2552         }
2553         return _unmodifiableBehaviorsMap; 
2554     }
2555 }