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