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: 1569181 $ $Date: 2014-02-17 23:14:07 -0500 (Mon, 17 Feb 2014) $
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     @Override
1154     public boolean visitTree(VisitContext context, VisitCallback callback)
1155     {
1156         if (isCachedFacesContext())
1157         {
1158             return super.visitTree(context, callback);
1159         }
1160         else
1161         {
1162             try
1163             {
1164                 setCachedFacesContext(context.getFacesContext());
1165                 return super.visitTree(context, callback);
1166             }
1167             finally
1168             {
1169                 setCachedFacesContext(null);
1170             }
1171         }
1172     }
1173 
1174     /**
1175      * A boolean value that indicates whether this component should be rendered. Default value: true.
1176      **/
1177     @Override
1178     @JSFProperty
1179     public boolean isRendered()
1180     {
1181         if (_cachedIsRendered != null)
1182         {
1183             return Boolean.TRUE.equals(_cachedIsRendered);
1184         }
1185         return (Boolean) getStateHelper().eval(PropertyKeys.rendered, DEFAULT_RENDERED);
1186     }
1187 
1188     @JSFProperty(literalOnly = true, istransient = true, tagExcluded = true)
1189     public boolean isTransient()
1190     {
1191         return _transient;
1192     }
1193     
1194     public void markInitialState()
1195     {
1196         super.markInitialState();
1197         if (_facesListeners != null)
1198         {
1199             _facesListeners.markInitialState();
1200         }
1201         if (_behaviorsMap != null)
1202         {
1203             for (Map.Entry<String, List<ClientBehavior> > entry : _behaviorsMap.entrySet())
1204             {
1205                 ((PartialStateHolder) entry.getValue()).markInitialState();
1206             }
1207         }
1208         if (_systemEventListenerClassMap != null)
1209         {
1210             for (Map.Entry<Class<? extends SystemEvent>, List<SystemEventListener>> entry : 
1211                 _systemEventListenerClassMap.entrySet())
1212             {
1213                 ((PartialStateHolder) entry.getValue()).markInitialState();
1214             }
1215         }
1216     }
1217 
1218     @Override
1219     protected void addFacesListener(FacesListener listener)
1220     {
1221         if (listener == null)
1222         {
1223             throw new NullPointerException("listener");
1224         }
1225         if (_facesListeners == null)
1226         {
1227             // How many facesListeners have single component normally? 
1228             _facesListeners = new _DeltaList<FacesListener>(new ArrayList<FacesListener>(5));
1229         }
1230         _facesListeners.add(listener);
1231     }
1232 
1233     @Override
1234     protected FacesContext getFacesContext()
1235     {
1236         if (_facesContext == null)
1237         {
1238             return FacesContext.getCurrentInstance();
1239         }
1240         else
1241         {
1242             return _facesContext;
1243         }
1244     }
1245 
1246     // FIXME: Notify EG for generic usage
1247     @Override
1248     protected FacesListener[] getFacesListeners(Class clazz)
1249     {
1250         if (clazz == null)
1251         {
1252             throw new NullPointerException("Class is null");
1253         }
1254         if (!FacesListener.class.isAssignableFrom(clazz))
1255         {
1256             throw new IllegalArgumentException("Class " + clazz.getName() + " must implement " + FacesListener.class);
1257         }
1258 
1259         if (_facesListeners == null)
1260         {
1261             return (FacesListener[]) Array.newInstance(clazz, 0);
1262         }
1263         List<FacesListener> lst = null;
1264         // perf: _facesListeners is RandomAccess instance (javax.faces.component._DeltaList)
1265         for (int i = 0, size = _facesListeners.size(); i < size; i++)
1266         {
1267             FacesListener facesListener = _facesListeners.get(i);
1268             if (facesListener != null && clazz.isAssignableFrom(facesListener.getClass()))
1269             {
1270                 if (lst == null)
1271                 {
1272                     lst = new ArrayList<FacesListener>();
1273                 }
1274                 lst.add(facesListener);
1275             }
1276         }
1277         if (lst == null)
1278         {
1279             return (FacesListener[]) Array.newInstance(clazz, 0);
1280         }
1281 
1282         return lst.toArray((FacesListener[]) Array.newInstance(clazz, lst.size()));
1283     }
1284 
1285     @Override
1286     protected Renderer getRenderer(FacesContext context)
1287     {
1288         if (context == null)
1289         {
1290             throw new NullPointerException("context");
1291         }
1292         Renderer renderer = getCachedRenderer();
1293         if (renderer != null)
1294         {
1295             return renderer;
1296         }
1297         String rendererType = getRendererType();
1298         if (rendererType == null)
1299         {
1300             return null;
1301         }
1302         
1303         RenderKit renderKit = context.getRenderKit();
1304         renderer = renderKit.getRenderer(getFamily(), rendererType);
1305         if (renderer == null)
1306         {
1307             String location = getComponentLocation(this);
1308             String logStr = "No Renderer found for component " + getPathToComponent(this)
1309                     + " (component-family=" + getFamily()
1310                     + ", renderer-type=" + rendererType + ")"
1311                     + (location != null ? " created from: " + location : "");
1312             
1313             getFacesContext().getExternalContext().log(logStr);
1314             log.warning(logStr);
1315         }
1316         return renderer;
1317     }
1318 
1319     @Override
1320     protected void removeFacesListener(FacesListener listener)
1321     {
1322         if (listener == null)
1323         {
1324             throw new NullPointerException("listener is null");
1325         }
1326 
1327         if (_facesListeners != null)
1328         {
1329             _facesListeners.remove(listener);
1330         }
1331     }
1332 
1333     @Override
1334     public void queueEvent(FacesEvent event)
1335     {
1336         if (event == null)
1337         {
1338             throw new NullPointerException("event");
1339         }
1340         UIComponent parent = getParent();
1341         if (parent == null)
1342         {
1343             throw new IllegalStateException("component is not a descendant of a UIViewRoot");
1344         }
1345         parent.queueEvent(event);
1346     }
1347 
1348     @Override
1349     public void processDecodes(FacesContext context)
1350     {
1351         try
1352         {
1353             setCachedFacesContext(context);
1354             // Call UIComponent.pushComponentToEL(javax.faces.context.FacesContext, javax.faces.component.UIComponent)
1355             pushComponentToEL(context, this);
1356             if (_isPhaseExecutable(context))
1357             {
1358                 // Call the processDecodes() method of all facets and children of this UIComponent, in the order
1359                 // determined by a call to getFacetsAndChildren().
1360                 int facetCount = getFacetCount();
1361                 if (facetCount > 0)
1362                 {
1363                     for (UIComponent facet : getFacets().values())
1364                     {
1365                         facet.processDecodes(context);
1366                     }
1367                 }
1368                 for (int i = 0, childCount = getChildCount(); i < childCount; i++)
1369                 {
1370                     UIComponent child = getChildren().get(i);
1371                     child.processDecodes(context);
1372                 }
1373 
1374                 try
1375                 {
1376                     // Call the decode() method of this component.
1377                     decode(context);
1378                 }
1379                 catch (RuntimeException e)
1380                 {
1381                     // If a RuntimeException is thrown during decode processing, call FacesContext.renderResponse()
1382                     // and re-throw the exception.
1383                     context.renderResponse();
1384                     throw e;
1385                 }
1386             }
1387         }
1388         finally
1389         {
1390             // Call UIComponent.popComponentFromEL(javax.faces.context.FacesContext) from inside of a finally
1391             // block, just before returning.
1392 
1393             popComponentFromEL(context);
1394             setCachedFacesContext(null);
1395         }
1396     }
1397 
1398     @Override
1399     public void processValidators(FacesContext context)
1400     {
1401         try
1402         {
1403             setCachedFacesContext(context);
1404             // Call UIComponent.pushComponentToEL(javax.faces.context.FacesContext, javax.faces.component.UIComponent)
1405             pushComponentToEL(context, this);
1406             if (_isPhaseExecutable(context))
1407             {
1408                 //Pre validation event dispatch for component
1409                 context.getApplication().publishEvent(context,  PreValidateEvent.class, getClass(), this);
1410                 
1411                 try
1412                 {
1413                     // Call the processValidators() method of all facets and children of this UIComponent, in the order
1414                     // determined by a call to getFacetsAndChildren().
1415                     int facetCount = getFacetCount();
1416                     if (facetCount > 0)
1417                     {
1418                         for (UIComponent facet : getFacets().values())
1419                         {
1420                             facet.processValidators(context);
1421                         }
1422                     }
1423     
1424                     for (int i = 0, childCount = getChildCount(); i < childCount; i++)
1425                     {
1426                         UIComponent child = getChildren().get(i);
1427                         child.processValidators(context);
1428                     }
1429                 }
1430                 finally
1431                 {
1432                     context.getApplication().publishEvent(context,  PostValidateEvent.class, getClass(), this);
1433                 }
1434             }
1435         }
1436         finally
1437         {
1438             popComponentFromEL(context);
1439             setCachedFacesContext(null);
1440         }
1441     }
1442 
1443     /**
1444      * This isn't an input component, so just pass on the processUpdates call to child components and facets that might
1445      * be input components.
1446      * <p>
1447      * Components that were never rendered can't possibly be receiving update data (no corresponding fields were ever
1448      * put into the response) so if this component is not rendered then this method does not invoke processUpdates on
1449      * its children.
1450      */
1451     @Override
1452     public void processUpdates(FacesContext context)
1453     {
1454         try
1455         {
1456             setCachedFacesContext(context);
1457             // Call UIComponent.pushComponentToEL(javax.faces.context.FacesContext, javax.faces.component.UIComponent)
1458             pushComponentToEL(context, this);
1459             if (_isPhaseExecutable(context))
1460             {
1461                 // Call the processUpdates() method of all facets and children of this UIComponent, in the order
1462                 // determined by a call to getFacetsAndChildren().
1463                 int facetCount = getFacetCount();
1464                 if (facetCount > 0)
1465                 {
1466                     for (UIComponent facet : getFacets().values())
1467                     {
1468                         facet.processUpdates(context);
1469                     }
1470                 }
1471 
1472                 for (int i = 0, childCount = getChildCount(); i < childCount; i++)
1473                 {
1474                     UIComponent child = getChildren().get(i);
1475                     child.processUpdates(context);
1476                 }
1477             }
1478         }
1479         finally
1480         {
1481             // After returning from the processUpdates() method on a child or facet, call
1482             // UIComponent.popComponentFromEL(javax.faces.context.FacesContext)
1483             popComponentFromEL(context);
1484             
1485             setCachedFacesContext(null);
1486         }
1487     }
1488 
1489     @Override
1490     public Object processSaveState(FacesContext context)
1491     {
1492         if (context == null)
1493         {
1494             throw new NullPointerException("context");
1495         }
1496 
1497         if (isTransient())
1498         {
1499             // consult the transient property of this component. If true, just return null.
1500             return null;
1501         }
1502 
1503         // Call UIComponent.pushComponentToEL(javax.faces.context.FacesContext, javax.faces.component.UIComponent)
1504         pushComponentToEL(context, this);
1505 
1506         Map<String, Object> facetMap;
1507 
1508         List<Object> childrenList;
1509         
1510         Object savedState;
1511         try
1512         {
1513             facetMap = null;
1514             int facetCount = getFacetCount();
1515             if (facetCount > 0)
1516             {
1517                 // Call the processSaveState() method of all facets and children of this UIComponent in the order
1518                 // determined by a call to getFacetsAndChildren(), skipping children and facets that are transient.
1519 
1520                 // To improve speed and robustness, the facets and children processing is splited to maintain the
1521                 // facet --> state coherence based on the facet's name
1522                 for (Map.Entry<String, UIComponent> entry : getFacets().entrySet())
1523                 {
1524                     UIComponent component = entry.getValue();
1525                     if (!component.isTransient())
1526                     {
1527                         if (facetMap == null)
1528                         {
1529                             facetMap = new HashMap<String, Object>(facetCount, 1);
1530                         }
1531 
1532                         facetMap.put(entry.getKey(), component.processSaveState(context));
1533 
1534                         // Ensure that UIComponent.popComponentFromEL(javax.faces.context.FacesContext) is called
1535                         // correctly after each child or facet.
1536                         // popComponentFromEL(context);
1537                     }
1538                 }
1539             }
1540             childrenList = null;
1541             int childCount = getChildCount();
1542             if (childCount > 0)
1543             {
1544                 // Call the processSaveState() method of all facets and children of this UIComponent in the order
1545                 // determined by a call to getFacetsAndChildren(), skipping children and facets that are transient.
1546 
1547                 // To improve speed and robustness, the facets and children processing is splited to maintain the
1548                 // facet --> state coherence based on the facet's name
1549                 for (int i = 0; i < childCount; i++)
1550                 {
1551                     UIComponent child = getChildren().get(i);
1552                     if (!child.isTransient())
1553                     {
1554                         if (childrenList == null)
1555                         {
1556                             childrenList = new ArrayList<Object>(childCount);
1557                         }
1558 
1559                         Object childState = child.processSaveState(context);
1560                         if (childState != null)
1561                         { // FIXME: Isn't that check dangerous for restoration since the child isn't marked transient?
1562                             childrenList.add(childState);
1563                         }
1564 
1565                         // Ensure that UIComponent.popComponentFromEL(javax.faces.context.FacesContext) is called
1566                         // correctly after each child or facet.
1567                     }
1568                 }
1569             }
1570             
1571             // Call the saveState() method of this component.
1572             savedState = saveState(context);
1573         }
1574         finally
1575         {
1576             popComponentFromEL(context);
1577         }
1578 
1579         // Encapsulate the child state and your state into a Serializable Object and return it.
1580         return new Object[] { savedState, facetMap, childrenList };
1581     }
1582 
1583     @SuppressWarnings("unchecked")
1584     @Override
1585     public void processRestoreState(FacesContext context, Object state)
1586     {
1587         if (context == null)
1588         {
1589             throw new NullPointerException("context");
1590         }
1591 
1592         Object[] stateValues = (Object[]) state;
1593 
1594         try
1595         {
1596             // Call UIComponent.pushComponentToEL(javax.faces.context.FacesContext, javax.faces.component.UIComponent)
1597             pushComponentToEL(context, this);
1598 
1599             // Call the restoreState() method of this component.
1600             restoreState(context, stateValues[0]);
1601             
1602             Map<String, Object> facetMap = (Map<String, Object>) stateValues[1];
1603             if (facetMap != null && getFacetCount() > 0)
1604             {
1605                 // Call the processRestoreState() method of all facets and children of this UIComponent in the order
1606                 // determined by a call to getFacetsAndChildren().
1607 
1608                 // To improve speed and robustness, the facets and children processing is splited to maintain the
1609                 // facet --> state coherence based on the facet's name
1610                 for (Map.Entry<String, UIComponent> entry : getFacets().entrySet())
1611                 {
1612                     Object facetState = facetMap.get(entry.getKey());
1613                     if (facetState != null)
1614                     {
1615                         entry.getValue().processRestoreState(context, facetState);
1616 
1617                         // After returning from the processRestoreState() method on a child or facet, call
1618                         // UIComponent.popComponentFromEL(javax.faces.context.FacesContext)
1619                         // popComponentFromEL(context);
1620                     }
1621                     else
1622                     {
1623                         context.getExternalContext().log("No state found to restore facet " + entry.getKey());
1624                     }
1625                 }
1626             }
1627             List<Object> childrenList = (List<Object>) stateValues[2];
1628             if (childrenList != null && getChildCount() > 0)
1629             {
1630                 // Call the processRestoreState() method of all facets and children of this UIComponent in the order
1631                 // determined by a call to getFacetsAndChildren().
1632 
1633                 // To improve speed and robustness, the facets and children processing is splited to maintain the
1634                 // facet --> state coherence based on the facet's name
1635                 int idx = 0;
1636                 for (int i = 0, childCount = getChildCount(); i < childCount; i++)
1637                 {
1638                     UIComponent child = getChildren().get(i);
1639                     if (!child.isTransient())
1640                     {
1641                         Object childState = childrenList.get(idx++);
1642                         if (childState != null)
1643                         {
1644                             child.processRestoreState(context, childState);
1645 
1646                             // After returning from the processRestoreState() method on a child or facet, call
1647                             // UIComponent.popComponentFromEL(javax.faces.context.FacesContext)
1648                             // popComponentFromEL(context);
1649                         }
1650                         else
1651                         {
1652                             context.getExternalContext().log("No state found to restore child of component " + getId());
1653                         }
1654                     }
1655                 }
1656             }
1657         }
1658         finally
1659         {
1660             popComponentFromEL(context);
1661         }
1662     }
1663     
1664     /**
1665      * Gets the Location of the given UIComponent from its attribute map.
1666      * @param component
1667      * @return
1668      */
1669     private String getComponentLocation(UIComponent component)
1670     {
1671         Location location = (Location) component.getAttributes()
1672                 .get(UIComponent.VIEW_LOCATION_KEY);
1673         if (location != null)
1674         {
1675             return location.toString();
1676         }
1677         return null;
1678     }
1679 
1680     private String getPathToComponent(UIComponent component)
1681     {
1682         StringBuffer buf = new StringBuffer();
1683 
1684         if (component == null)
1685         {
1686             buf.append("{Component-Path : ");
1687             buf.append("[null]}");
1688             return buf.toString();
1689         }
1690 
1691         getPathToComponent(component, buf);
1692 
1693         buf.insert(0, "{Component-Path : ");
1694         buf.append("}");
1695 
1696         return buf.toString();
1697     }
1698 
1699     private void getPathToComponent(UIComponent component, StringBuffer buf)
1700     {
1701         if (component == null)
1702         {
1703             return;
1704         }
1705 
1706         StringBuffer intBuf = new StringBuffer();
1707 
1708         intBuf.append("[Class: ");
1709         intBuf.append(component.getClass().getName());
1710         if (component instanceof UIViewRoot)
1711         {
1712             intBuf.append(",ViewId: ");
1713             intBuf.append(((UIViewRoot) component).getViewId());
1714         }
1715         else
1716         {
1717             intBuf.append(",Id: ");
1718             intBuf.append(component.getId());
1719         }
1720         intBuf.append("]");
1721 
1722         buf.insert(0, intBuf.toString());
1723 
1724         getPathToComponent(component.getParent(), buf);
1725     }
1726 
1727     public void setTransient(boolean transientFlag)
1728     {
1729         _transient = transientFlag;
1730     }
1731 
1732     /**
1733      * Serializes objects which are "attached" to this component but which are not UIComponent children of it. Examples
1734      * are validator and listener objects. To be precise, it returns an object which implements java.io.Serializable,
1735      * and which when serialized will persist the state of the provided object.
1736      * <p>
1737      * If the attachedObject is a List then every object in the list is saved via a call to this method, and the
1738      * returned wrapper object contains a List object.
1739      * <p>
1740      * If the object implements StateHolder then the object's saveState is called immediately, and a wrapper is returned
1741      * which contains both this saved state and the original class name. However in the case where the
1742      * StateHolder.isTransient method returns true, null is returned instead.
1743      * <p>
1744      * If the object implements java.io.Serializable then the object is simply returned immediately; standard java
1745      * serialization will later be used to store this object.
1746      * <p>
1747      * In all other cases, a wrapper is returned which simply stores the type of the provided object. When deserialized,
1748      * a default instance of that type will be recreated.
1749      */
1750     public static Object saveAttachedState(FacesContext context, Object attachedObject)
1751     {
1752         if (context == null)
1753         {
1754             throw new NullPointerException ("context");
1755         }
1756         
1757         if (attachedObject == null)
1758         {
1759             return null;
1760         }
1761         // StateHolder interface should take precedence over
1762         // List children
1763         if (attachedObject instanceof StateHolder)
1764         {
1765             StateHolder holder = (StateHolder) attachedObject;
1766             if (holder.isTransient())
1767             {
1768                 return null;
1769             }
1770 
1771             return new _AttachedStateWrapper(attachedObject.getClass(), holder.saveState(context));
1772         }
1773         else if (attachedObject instanceof Collection)
1774         {
1775             if (ArrayList.class.equals(attachedObject.getClass()))
1776             {
1777                 ArrayList<?> list = (ArrayList<?>) attachedObject;
1778                 int size = list.size();
1779                 List<Object> lst = new ArrayList<Object>(size);
1780                 for (int i = 0; i < size; i++)
1781                 {
1782                     Object item = list.get(i);
1783                     if (item != null)
1784                     {
1785                         lst.add(saveAttachedState(context, item));
1786                     }
1787                 }
1788                 return new _AttachedListStateWrapper(lst);
1789             }
1790             else
1791             {
1792                 List<Object> lst = new ArrayList<Object>(((Collection<?>) attachedObject).size());
1793                 for (Object item : (Collection<?>) attachedObject)
1794                 {
1795                     if (item != null)
1796                     {
1797                         lst.add(saveAttachedState(context, item));
1798                     }
1799                 }
1800                 return new _AttachedCollectionStateWrapper(attachedObject.getClass(), lst);
1801             }
1802         }
1803         else if (attachedObject instanceof Serializable)
1804         {
1805             return attachedObject;
1806         }
1807         else
1808         {
1809             return new _AttachedStateWrapper(attachedObject.getClass(), null);
1810         }
1811     }
1812 
1813     public static Object restoreAttachedState(FacesContext context, Object stateObj) throws IllegalStateException
1814     {
1815         if (context == null)
1816         {
1817             throw new NullPointerException("context");
1818         }
1819         if (stateObj == null)
1820         {
1821             return null;
1822         }
1823         if (stateObj instanceof _AttachedListStateWrapper)
1824         {
1825             // perf: getWrappedStateList in _AttachedListStateWrapper is always ArrayList: see saveAttachedState
1826             ArrayList<Object> lst = (ArrayList<Object>) ((_AttachedListStateWrapper) stateObj).getWrappedStateList();
1827             List<Object> restoredList = new ArrayList<Object>(lst.size());
1828             for (int i = 0, size = lst.size(); i < size; i++)
1829             {
1830                 Object item = lst.get(i);
1831                 restoredList.add(restoreAttachedState(context, item));
1832             }
1833             return restoredList;
1834         }
1835         else if (stateObj instanceof _AttachedCollectionStateWrapper)
1836         {
1837             _AttachedCollectionStateWrapper wrappedState = (_AttachedCollectionStateWrapper) stateObj; 
1838             Class<?> clazz = wrappedState.getClazz();
1839             List<Object> lst = wrappedState.getWrappedStateList();
1840             Collection restoredList;
1841             try
1842             {
1843                 restoredList = (Collection) clazz.newInstance();
1844             }
1845             catch (InstantiationException e)
1846             {
1847                 throw new RuntimeException("Could not restore StateHolder of type " + clazz.getName()
1848                         + " (missing no-args constructor?)", e);
1849             }
1850             catch (IllegalAccessException e)
1851             {
1852                 throw new RuntimeException(e);
1853             }
1854 
1855             for (Object item : lst)
1856             {
1857                 restoredList.add(restoreAttachedState(context, item));
1858             }
1859             return restoredList;
1860 
1861         }
1862         else if (stateObj instanceof _AttachedStateWrapper)
1863         {
1864             Class<?> clazz = ((_AttachedStateWrapper) stateObj).getClazz();
1865             Object restoredObject;
1866             try
1867             {
1868                 restoredObject = clazz.newInstance();
1869             }
1870             catch (InstantiationException e)
1871             {
1872                 throw new RuntimeException("Could not restore StateHolder of type " + clazz.getName()
1873                         + " (missing no-args constructor?)", e);
1874             }
1875             catch (IllegalAccessException e)
1876             {
1877                 throw new RuntimeException(e);
1878             }
1879             if (restoredObject instanceof StateHolder)
1880             {
1881                 _AttachedStateWrapper wrapper = (_AttachedStateWrapper) stateObj;
1882                 Object wrappedState = wrapper.getWrappedStateObject();
1883 
1884                 StateHolder holder = (StateHolder) restoredObject;
1885                 holder.restoreState(context, wrappedState);
1886             }
1887             return restoredObject;
1888         }
1889         else
1890         {
1891             return stateObj;
1892         }
1893     }
1894 
1895     /**
1896      * Invoked after the render phase has completed, this method returns an object which can be passed to the
1897      * restoreState of some other instance of UIComponentBase to reset that object's state to the same values as this
1898      * object currently has.
1899      */
1900     public Object saveState(FacesContext context)
1901     {
1902         if (context == null)
1903         {
1904             throw new NullPointerException ("context");
1905         }
1906         
1907         if (initialStateMarked())
1908         {
1909             //Delta
1910             //_id and _clientId was already restored from template
1911             //and never changes during component life.
1912             Object facesListenersSaved = saveFacesListenersList(context);
1913             Object behaviorsMapSaved = saveBehaviorsMap(context);
1914             Object systemEventListenerClassMapSaved = saveSystemEventListenerClassMap(context);
1915             Object stateHelperSaved = null;
1916             StateHelper stateHelper = getStateHelper(false);
1917             if (stateHelper != null)
1918             {
1919                 stateHelperSaved = stateHelper.saveState(context);
1920             }
1921             
1922             if (facesListenersSaved == null && stateHelperSaved == null && 
1923                 behaviorsMapSaved == null && systemEventListenerClassMapSaved == null &&
1924                !_isRendererTypeSet)
1925             {
1926                 return null;
1927             }
1928             
1929             if (_isRendererTypeSet)
1930             {
1931                 return new Object[] {facesListenersSaved, stateHelperSaved, behaviorsMapSaved,
1932                                     systemEventListenerClassMapSaved, 
1933                                     _rendererType};
1934             }
1935             else
1936             {
1937                 return new Object[] {facesListenersSaved, stateHelperSaved, behaviorsMapSaved,
1938                     systemEventListenerClassMapSaved};
1939             }
1940         }
1941         else
1942         {
1943             //Full
1944             Object values[] = new Object[11];
1945             values[0] = saveFacesListenersList(context);
1946             StateHelper stateHelper = getStateHelper(false);
1947             if (stateHelper != null)
1948             {
1949                 values[1] = stateHelper.saveState(context);
1950             }
1951             values[2] = saveBehaviorsMap(context);
1952             values[3] = saveSystemEventListenerClassMap(context);
1953             values[4] = _id;
1954             values[5] = _clientId;
1955             values[6] = _markCreated;
1956             values[7] = _rendererType;
1957             values[8] = _isRendererTypeSet;
1958             values[9] = _addedByHandler;
1959             values[10] = _facetCreatedUIPanel;
1960 
1961             return values;
1962         }
1963     }
1964 
1965     /**
1966      * Invoked in the "restore view" phase, this initialises this object's members from the values saved previously into
1967      * the provided state object.
1968      * <p>
1969      * 
1970      * @param state
1971      *            is an object previously returned by the saveState method of this class.
1972      */
1973     @SuppressWarnings("unchecked")
1974     public void restoreState(FacesContext context, Object state)
1975     {
1976         if (context == null)
1977         {
1978             throw new NullPointerException ("context");
1979         }
1980         
1981         if (state == null)
1982         {
1983             //Only happens if initialStateMarked return true
1984             
1985             if (initialStateMarked())
1986             {
1987                 return;
1988             }
1989             
1990             throw new NullPointerException ("state");
1991         }
1992         
1993         Object values[] = (Object[]) state;
1994         
1995         if ( values.length == 11 && initialStateMarked())
1996         {
1997             //Delta mode is active, but we are restoring a full state.
1998             //we need to clear the initial state, to restore state without
1999             //take into account delta.
2000             clearInitialState();
2001         }
2002         
2003         if (values[0] instanceof _AttachedDeltaWrapper)
2004         {
2005             //Delta: check for null is not necessary since _facesListener field
2006             //is only set once and never reset
2007             //if (_facesListeners != null)
2008             //{
2009                 ((StateHolder)_facesListeners).restoreState(context,
2010                         ((_AttachedDeltaWrapper) values[0]).getWrappedStateObject());
2011             //}
2012         }
2013         else if (values[0] != null || (values.length == 11))
2014         {
2015             //Full
2016             _facesListeners = (_DeltaList<FacesListener>)
2017                 restoreAttachedState(context,values[0]);
2018         }
2019         // Note that if values[0] == null && initialStateMarked(),
2020         // means delta is null, not that _facesListeners == null. 
2021         // We can do this here because _facesListeners instance once
2022         // is created is never replaced or set to null.
2023         
2024         getStateHelper().restoreState(context, values[1]);
2025         
2026         if (values.length == 11)
2027         {
2028             _id = (String) values[4];
2029             _clientId = (String) values[5];
2030             _markCreated = (String) values[6];
2031             _rendererType = (String) values[7];
2032             _isRendererTypeSet = (Boolean) values[8];
2033             _addedByHandler = (Boolean) values[9];
2034             _facetCreatedUIPanel = (Boolean) values[10];
2035         }
2036         else if (values.length == 5)
2037         {
2038             _rendererType = (String) values[4];
2039             _isRendererTypeSet = true;
2040         }
2041 
2042         // rendererType needs to be restored before SystemEventListener,
2043         // otherwise UIComponent.getCurrentComponent(context).getRenderer(context)
2044         // will not work correctly
2045         if (values.length == 11)
2046         {
2047             //Full restore
2048             restoreFullBehaviorsMap(context, values[2]);
2049             restoreFullSystemEventListenerClassMap(context, values[3]);
2050         }
2051         else
2052         {
2053             //Delta restore
2054             restoreDeltaBehaviorsMap(context, values[2]);
2055             restoreDeltaSystemEventListenerClassMap(context, values[3]);
2056         }
2057     }
2058     
2059     private Object saveFacesListenersList(FacesContext facesContext)
2060     {
2061         PartialStateHolder holder = (PartialStateHolder) _facesListeners;
2062         if (initialStateMarked() && _facesListeners != null && holder.initialStateMarked())
2063         {                
2064             Object attachedState = holder.saveState(facesContext);
2065             if (attachedState != null)
2066             {
2067                 return new _AttachedDeltaWrapper(_facesListeners.getClass(),
2068                         attachedState);
2069             }
2070             //_facesListeners instances once is created never changes, we can return null
2071             return null;
2072         }
2073         else
2074         {
2075             return saveAttachedState(facesContext,_facesListeners);
2076         }            
2077     }
2078 
2079     @SuppressWarnings("unchecked")
2080     private void restoreFullBehaviorsMap(FacesContext facesContext, Object stateObj)
2081     {
2082         if (stateObj != null)
2083         {
2084             Map<String, Object> stateMap = (Map<String, Object>) stateObj;
2085             int initCapacity = (stateMap.size() * 4 + 3) / 3;
2086             _behaviorsMap = new HashMap<String,  List<ClientBehavior> >(initCapacity);
2087             _unmodifiableBehaviorsMap = null;
2088             for (Map.Entry<String, Object> entry : stateMap.entrySet())
2089             {
2090                 _behaviorsMap.put(entry.getKey(),
2091                                   (List<ClientBehavior>) restoreAttachedState(facesContext, entry.getValue()));
2092             }
2093         }
2094         else
2095         {
2096             _behaviorsMap = null;
2097             _unmodifiableBehaviorsMap = null;
2098         }        
2099     }
2100     
2101     @SuppressWarnings("unchecked")
2102     private void restoreDeltaBehaviorsMap(FacesContext facesContext, Object stateObj)
2103     {
2104         if (stateObj != null)
2105         {
2106             _unmodifiableBehaviorsMap = null;
2107             Map<String, Object> stateMap = (Map<String, Object>) stateObj;
2108             int initCapacity = (stateMap.size() * 4 + 3) / 3;
2109             if (_behaviorsMap == null)
2110             {
2111                 _behaviorsMap = new HashMap<String,  List<ClientBehavior> >(initCapacity);
2112             }
2113             for (Map.Entry<String, Object> entry : stateMap.entrySet())
2114             {
2115                 Object savedObject = entry.getValue(); 
2116                 if (savedObject instanceof _AttachedDeltaWrapper)
2117                 {
2118                     StateHolder holderList = (StateHolder) _behaviorsMap.get(entry.getKey());
2119                     holderList.restoreState(facesContext,
2120                                             ((_AttachedDeltaWrapper) savedObject).getWrappedStateObject());
2121                 }
2122                 else
2123                 {
2124                     _behaviorsMap.put(entry.getKey(),
2125                                       (List<ClientBehavior>) restoreAttachedState(facesContext, savedObject));
2126                 }
2127             }
2128         }
2129     }
2130     
2131     private Object saveBehaviorsMap(FacesContext facesContext)
2132     {
2133         if (_behaviorsMap != null)
2134         {
2135             if (initialStateMarked())
2136             {
2137                 HashMap<String, Object> stateMap = new HashMap<String, Object>(_behaviorsMap.size(), 1);
2138                 boolean nullDelta = true;
2139                 for (Map.Entry<String, List<ClientBehavior> > entry : _behaviorsMap.entrySet())
2140                 {
2141                     // The list is always an instance of _DeltaList so we can cast to
2142                     // PartialStateHolder 
2143                     PartialStateHolder holder = (PartialStateHolder) entry.getValue();
2144                     if (holder.initialStateMarked())
2145                     {
2146                         Object attachedState = holder.saveState(facesContext);
2147                         if (attachedState != null)
2148                         {
2149                             stateMap.put(entry.getKey(), new _AttachedDeltaWrapper(_behaviorsMap.getClass(),
2150                                     attachedState));
2151                             nullDelta = false;
2152                         }
2153                     }
2154                     else
2155                     {
2156                         stateMap.put(entry.getKey(), saveAttachedState(facesContext, holder));
2157                         nullDelta = false;
2158                     }
2159                 }
2160                 if (nullDelta)
2161                 {
2162                     return null;
2163                 }
2164                 return stateMap;
2165             }
2166             else
2167             {
2168                 //Save it in the traditional way
2169                 HashMap<String, Object> stateMap = 
2170                     new HashMap<String, Object>(_behaviorsMap.size(), 1);
2171                 for (Map.Entry<String, List<ClientBehavior> > entry : _behaviorsMap.entrySet())
2172                 {
2173                     stateMap.put(entry.getKey(), saveAttachedState(facesContext, entry.getValue()));
2174                 }
2175                 return stateMap;
2176             }
2177         }
2178         else
2179         {
2180             return null;
2181         }
2182     }
2183     
2184     @SuppressWarnings("unchecked")
2185     private void restoreFullSystemEventListenerClassMap(FacesContext facesContext, Object stateObj)
2186     {
2187         if (stateObj != null)
2188         {
2189             Map<Class<? extends SystemEvent>, Object> stateMap = (Map<Class<? extends SystemEvent>, Object>) stateObj;
2190             int initCapacity = (stateMap.size() * 4 + 3) / 3;
2191             _systemEventListenerClassMap
2192                     = new HashMap<Class<? extends SystemEvent>, List<SystemEventListener>>(initCapacity);
2193             for (Map.Entry<Class<? extends SystemEvent>, Object> entry : stateMap.entrySet())
2194             {
2195                 _systemEventListenerClassMap.put(entry.getKey(),
2196                         (List<SystemEventListener>) restoreAttachedState(facesContext, entry.getValue()));
2197             }
2198         }
2199         else
2200         {
2201             _systemEventListenerClassMap = null;
2202         }        
2203     }
2204     
2205     @SuppressWarnings("unchecked")
2206     private void restoreDeltaSystemEventListenerClassMap(FacesContext facesContext, Object stateObj)
2207     {
2208         if (stateObj != null)
2209         {
2210             Map<Class<? extends SystemEvent>, Object> stateMap = (Map<Class<? extends SystemEvent>, Object>) stateObj;
2211             int initCapacity = (stateMap.size() * 4 + 3) / 3;
2212             if (_systemEventListenerClassMap == null)
2213             {
2214                 _systemEventListenerClassMap
2215                         = new HashMap<Class<? extends SystemEvent>, List<SystemEventListener>>(initCapacity);
2216             }
2217             for (Map.Entry<Class<? extends SystemEvent>, Object> entry : stateMap.entrySet())
2218             {
2219                 Object savedObject = entry.getValue(); 
2220                 if (savedObject instanceof _AttachedDeltaWrapper)
2221                 {
2222                     StateHolder holderList = (StateHolder) _systemEventListenerClassMap.get(entry.getKey());
2223                     holderList.restoreState(facesContext,
2224                                             ((_AttachedDeltaWrapper) savedObject).getWrappedStateObject());
2225                 }
2226                 else
2227                 {
2228                     _systemEventListenerClassMap.put(entry.getKey(),
2229                             (List<SystemEventListener>) restoreAttachedState(facesContext, savedObject));
2230                 }
2231             }
2232         }
2233     }
2234     
2235     private Object saveSystemEventListenerClassMap(FacesContext facesContext)
2236     {
2237         if (_systemEventListenerClassMap != null)
2238         {
2239             if (initialStateMarked())
2240             {
2241                 HashMap<Class<? extends SystemEvent>, Object> stateMap
2242                         = new HashMap<Class<? extends SystemEvent>, Object>(_systemEventListenerClassMap.size(), 1);
2243                 boolean nullDelta = true;
2244                 for (Map.Entry<Class<? extends SystemEvent>, List<SystemEventListener> > entry
2245                         : _systemEventListenerClassMap.entrySet())
2246                 {
2247                     // The list is always an instance of _DeltaList so we can cast to
2248                     // PartialStateHolder 
2249                     PartialStateHolder holder = (PartialStateHolder) entry.getValue();
2250                     if (holder.initialStateMarked())
2251                     {
2252                         Object attachedState = holder.saveState(facesContext);
2253                         if (attachedState != null)
2254                         {
2255                             stateMap.put(entry.getKey(),
2256                                     new _AttachedDeltaWrapper(_systemEventListenerClassMap.getClass(), attachedState));
2257                             nullDelta = false;
2258                         }
2259                     }
2260                     else
2261                     {
2262                         stateMap.put(entry.getKey(), saveAttachedState(facesContext, holder));
2263                         nullDelta = false;
2264                     }
2265                 }
2266                 if (nullDelta)
2267                 {
2268                     return null;
2269                 }
2270                 return stateMap;
2271             }
2272             else
2273             {
2274                 //Save it in the traditional way
2275                 HashMap<Class<? extends SystemEvent>, Object> stateMap = 
2276                     new HashMap<Class<? extends SystemEvent>, Object>(_systemEventListenerClassMap.size(), 1);
2277                 for (Map.Entry<Class<? extends SystemEvent>, List<SystemEventListener> > entry
2278                         : _systemEventListenerClassMap.entrySet())
2279                 {
2280                     stateMap.put(entry.getKey(), saveAttachedState(facesContext, entry.getValue()));
2281                 }
2282                 return stateMap;
2283             }
2284         }
2285         else
2286         {
2287             return null;
2288         }
2289     }
2290     
2291     /*
2292     private Object saveBindings(FacesContext context)
2293     {
2294         if (bindings != null)
2295         {
2296             HashMap<String, Object> stateMap = new HashMap<String, Object>(bindings.size(), 1);
2297             for (Iterator<Entry<String, ValueExpression>> it = bindings.entrySet().iterator(); it.hasNext();)
2298             {
2299                 Entry<String, ValueExpression> entry = it.next();
2300                 stateMap.put(entry.getKey(), saveAttachedState(context, entry.getValue()));
2301             }
2302             return stateMap;
2303         }
2304 
2305         return null;
2306     }
2307 
2308     @SuppressWarnings("unchecked")
2309     private void restoreValueExpressionMap(FacesContext context, Object stateObj)
2310     {
2311         if (stateObj != null)
2312         {
2313             Map<String, Object> stateMap = (Map<String, Object>) stateObj;
2314             int initCapacity = (stateMap.size() * 4 + 3) / 3;
2315             bindings = new HashMap<String, ValueExpression>(initCapacity);
2316             for (Map.Entry<String, Object> entry : stateMap.entrySet())
2317             {
2318                 bindings.put(entry.getKey(), (ValueExpression) restoreAttachedState(context, entry.getValue()));
2319             }
2320         }
2321         else
2322         {
2323             bindings = null;
2324         }
2325     }*/
2326 
2327     /**
2328      * @param string
2329      *            the component id, that should be a vaild one.
2330      */
2331     private void isIdValid(String string)
2332     {
2333 
2334         // is there any component identifier ?
2335         if (string == null)
2336         {
2337             return;
2338         }
2339 
2340         // Component identifiers must obey the following syntax restrictions:
2341         // 1. Must not be a zero-length String.
2342         if (string.length() == 0)
2343         {
2344             throw new IllegalArgumentException("component identifier must not be a zero-length String");
2345         }
2346 
2347         // If new id is the same as old it must be valid
2348         if (string.equals(_id))
2349         {
2350             return;
2351         }
2352 
2353         // 2. First character must be a letter or an underscore ('_').
2354         if (!Character.isLetter(string.charAt(0)) && string.charAt(0) != '_')
2355         {
2356             throw new IllegalArgumentException("component identifier's first character must be a letter "
2357                                                + "or an underscore ('_')! But it is \""
2358                                                + string.charAt(0) + "\"");
2359         }
2360         for (int i = 1; i < string.length(); i++)
2361         {
2362             char c = string.charAt(i);
2363             // 3. Subsequent characters must be a letter, a digit, an underscore ('_'), or a dash ('-').
2364             if (!Character.isLetterOrDigit(c) && c != '-' && c != '_')
2365             {
2366                 throw new IllegalArgumentException("Subsequent characters of component identifier must be a letter, "
2367                                                    + "a digit, an underscore ('_'), or a dash ('-')! "
2368                                                    + "But component identifier contains \""
2369                                                    + c + "\"");
2370             }
2371         }
2372     }
2373 
2374     private boolean _isPhaseExecutable(FacesContext context)
2375     {
2376         if (context == null)
2377         {
2378             throw new NullPointerException("context");
2379         }
2380 
2381         // If the rendered property of this UIComponent is false, skip further processing.
2382         return isRendered();
2383     }
2384 
2385     boolean isCachedFacesContext()
2386     {
2387         return _facesContext != null;
2388     }
2389     
2390     void setCachedFacesContext(FacesContext facesContext)
2391     {
2392         _facesContext = facesContext;
2393     }
2394     
2395     Renderer getCachedRenderer()
2396     {
2397         return _cachedRenderer;
2398     }
2399     
2400     void setCachedRenderer(Renderer renderer)
2401     {
2402         _cachedRenderer = renderer;
2403     }
2404 
2405     Boolean isCachedIsRendered()
2406     {
2407         return _cachedIsRendered;
2408     }
2409     
2410     void setCachedIsRendered(Boolean rendered)
2411     {
2412        _cachedIsRendered = rendered;
2413     }
2414     
2415     <T> T getExpressionValue(String attribute, T explizitValue, T defaultValueIfExpressionNull)
2416     {
2417         return _ComponentUtils.getExpressionValue(this, attribute, explizitValue, defaultValueIfExpressionNull);
2418     }
2419 
2420     void setOamVfMarkCreated(String markCreated)
2421     {
2422         _markCreated = markCreated;
2423     }
2424     
2425     String getOamVfMarkCreated()
2426     {
2427         return _markCreated;
2428     }
2429     
2430     String getOamVfFacetName()
2431     {
2432         return _facetName;
2433     }
2434     
2435     void setOamVfFacetName(String facetName)
2436     {
2437         _facetName = facetName;
2438     }
2439     
2440     boolean isOamVfAddedByHandler()
2441     {
2442         return _addedByHandler;
2443     }
2444     
2445     void setOamVfAddedByHandler(boolean addedByHandler)
2446     {
2447         _addedByHandler = addedByHandler;
2448     }
2449     
2450     boolean isOamVfFacetCreatedUIPanel()
2451     {
2452         return _facetCreatedUIPanel;
2453     }
2454     
2455     void setOamVfFacetCreatedUIPanel(boolean facetCreatedUIPanel)
2456     {
2457         _facetCreatedUIPanel = facetCreatedUIPanel;
2458     }
2459 
2460 /**
2461      * <p>
2462      * This gets a single FacesContext-local shared stringbuilder instance, each time you call
2463      * __getSharedStringBuilder it sets the length of the stringBuilder instance to 0.
2464      * </p><p>
2465      * This allows you to use the same StringBuilder instance over and over.
2466      * You must call toString on the instance before calling __getSharedStringBuilder again.
2467      * </p>
2468      * Example that works
2469      * <pre><code>
2470      * StringBuilder sb1 = __getSharedStringBuilder();
2471      * sb1.append(a).append(b);
2472      * String c = sb1.toString();
2473      *
2474      * StringBuilder sb2 = __getSharedStringBuilder();
2475      * sb2.append(b).append(a);
2476      * String d = sb2.toString();
2477      * </code></pre>
2478      * <br><br>
2479      * Example that doesn't work, you must call toString on sb1 before
2480      * calling __getSharedStringBuilder again.
2481      * <pre><code>
2482      * StringBuilder sb1 = __getSharedStringBuilder();
2483      * StringBuilder sb2 = __getSharedStringBuilder();
2484      *
2485      * sb1.append(a).append(b);
2486      * String c = sb1.toString();
2487      *
2488      * sb2.append(b).append(a);
2489      * String d = sb2.toString();
2490      * </code></pre>
2491      *
2492      */
2493     static StringBuilder __getSharedStringBuilder()
2494     {
2495         return __getSharedStringBuilder(FacesContext.getCurrentInstance());
2496     }
2497 
2498     // TODO checkstyle complains; does this have to lead with __ ?
2499     static StringBuilder __getSharedStringBuilder(FacesContext facesContext)
2500     {
2501         Map<Object, Object> attributes = facesContext.getAttributes();
2502 
2503         StringBuilder sb = (StringBuilder) attributes.get(_STRING_BUILDER_KEY);
2504 
2505         if (sb == null)
2506         {
2507             sb = new StringBuilder();
2508             attributes.put(_STRING_BUILDER_KEY, sb);
2509         }
2510         else
2511         {
2512 
2513             // clear out the stringBuilder by setting the length to 0
2514             sb.setLength(0);
2515         }
2516 
2517         return sb;
2518     }
2519 
2520     // ------------------ GENERATED CODE BEGIN (do not modify!) --------------------
2521 
2522     private static final Boolean DEFAULT_RENDERED = Boolean.TRUE;
2523 
2524     @Override
2525     public void setRendered(boolean rendered)
2526     {
2527         getStateHelper().put(PropertyKeys.rendered, rendered );
2528         setCachedIsRendered(null);
2529     }
2530 
2531     @Override
2532     public void setRendererType(String rendererType)
2533     {
2534         this._rendererType = rendererType;
2535         if (initialStateMarked())
2536         {
2537             //This flag just indicates the rendererType 
2538             //should be included on the delta
2539             this._isRendererTypeSet = true;
2540         }
2541         setCachedRenderer(null);
2542     }
2543 
2544     // ------------------ GENERATED CODE END ---------------------------------------
2545 
2546     private Map<String, List<ClientBehavior>> wrapBehaviorsMap()
2547     {
2548         if (_unmodifiableBehaviorsMap == null)
2549         {
2550             _unmodifiableBehaviorsMap = Collections.unmodifiableMap(_behaviorsMap); 
2551         }
2552         return _unmodifiableBehaviorsMap; 
2553     }
2554 }