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 org.apache.myfaces.view.facelets.tag.jsf;
20  
21  import java.io.IOException;
22  import java.lang.reflect.InvocationTargetException;
23  import java.lang.reflect.Method;
24  import java.util.Collection;
25  import java.util.Iterator;
26  import java.util.Locale;
27  import java.util.Map;
28  
29  import javax.faces.FacesException;
30  import javax.faces.component.NamingContainer;
31  import javax.faces.component.UIComponent;
32  import javax.faces.component.UIPanel;
33  import javax.faces.component.UIViewRoot;
34  import javax.faces.component.UniqueIdVendor;
35  import javax.faces.context.FacesContext;
36  import javax.faces.view.facelets.FaceletContext;
37  import javax.faces.view.facelets.TagAttribute;
38  import javax.faces.view.facelets.TagAttributeException;
39  
40  import org.apache.myfaces.shared.config.MyfacesConfig;
41  import org.apache.myfaces.view.facelets.ComponentState;
42  import org.apache.myfaces.view.facelets.DefaultFaceletsStateManagementStrategy;
43  import org.apache.myfaces.view.facelets.FaceletCompositionContext;
44  import org.apache.myfaces.view.facelets.FaceletViewDeclarationLanguage;
45  import org.apache.myfaces.view.facelets.FaceletViewDeclarationLanguageBase;
46  
47  /**
48   * 
49   * @author Jacob Hookom
50   * @version $Id$
51   */
52  public final class ComponentSupport
53  {
54      private static final Method SET_CACHED_FACES_CONTEXT;
55          
56      static
57      {
58          Method method = null;
59          try
60          {
61              // The trick here is define this method in UIComponent as a class scoped method
62              // and get it from there. Even if the real implementation is in UIComponentBase,
63              // the jvm will always call the right one and in case of a instance not extending
64              // from UIComponentBase it will call a dummy method.
65              method = UIComponent.class.getDeclaredMethod("setCachedFacesContext", FacesContext.class);
66              method.setAccessible(true);
67          }
68          catch (NoSuchMethodException ex)
69          {
70              method = null;
71          }
72          catch (SecurityException ex)
73          {
74              method = null;
75          }
76          SET_CACHED_FACES_CONTEXT = method;
77      }
78  
79      private final static String MARK_DELETED = "oam.vf.MARK_DELETED";
80      public final static String MARK_CREATED = "oam.vf.MARK_ID";
81      
82      /**
83       * The UIPanel components, which are dynamically generated to serve as a container for
84       * facets with multiple non panel children, are marked with this attribute.
85       * This constant is duplicate in javax.faces.webapp.UIComponentClassicTagBase
86       */
87      public final static String FACET_CREATED_UIPANEL_MARKER = "oam.vf.createdUIPanel";
88  
89      /**
90       * Special myfaces core marker to indicate the component is handled by a facelet tag handler,
91       * so its creation is not handled by user programatically and PSS remove listener should
92       * not register it when a remove happens.
93       */
94      public final static String COMPONENT_ADDED_BY_HANDLER_MARKER = "oam.vf.addedByHandler";
95  
96      /**
97       * The key under the facelet state map is stored
98       */
99      public final static String FACELET_STATE_INSTANCE = "oam.FACELET_STATE_INSTANCE";
100 
101     /**
102      * Used in conjunction with markForDeletion where any UIComponent marked will be removed.
103      * 
104      * @deprecated use FaceletCompositionContext.finalizeForDeletion
105      * @param component
106      *            UIComponent to finalize
107      */
108     @Deprecated
109     public static void finalizeForDeletion(UIComponent component)
110     {
111         // remove any existing marks of deletion
112         component.getAttributes().remove(MARK_DELETED);
113 
114         // finally remove any children marked as deleted
115         if (component.getChildCount() > 0)
116         {
117             for (Iterator<UIComponent> iter = component.getChildren().iterator(); iter.hasNext();)
118             {
119                 UIComponent child = iter.next();
120                 if (child.getAttributes().containsKey(MARK_DELETED))
121                 {
122                     iter.remove();
123                 }
124             }
125         }
126 
127         // remove any facets marked as deleted
128         if (component.getFacetCount() > 0)
129         {
130             Map<String, UIComponent> facets = component.getFacets();
131             Collection<UIComponent> col = facets.values();
132             for (Iterator<UIComponent> itr = col.iterator(); itr.hasNext();)
133             {
134                 UIComponent fc = itr.next();
135                 if (fc.getAttributes().containsKey(MARK_DELETED))
136                 {
137                     itr.remove();
138                 }
139             }
140         }
141     }
142 
143     /**
144      * A lighter-weight version of UIComponent's findChild.
145      * 
146      * @param parent
147      *            parent to start searching from
148      * @param id
149      *            to match to
150      * @return UIComponent found or null
151      */
152     public static UIComponent findChild(UIComponent parent, String id)
153     {
154         int childCount = parent.getChildCount();
155         if (childCount > 0)
156         {
157             for (int i = 0; i < childCount; i++)
158             {
159                 UIComponent child = parent.getChildren().get(i);
160                 if (id.equals(child.getId()))
161                 {
162                     return child;
163                 }
164             }
165         }
166         return null;
167     }
168     
169     public static String findFacetNameByComponentInstance(
170         UIComponent parent, UIComponent instance)
171     {
172         if (parent.getFacetCount() > 0)
173         {
174             for (Map.Entry<String, UIComponent> entry : parent.getFacets().entrySet())
175             {
176                 UIComponent facet = entry.getValue();
177                 // check if this is a dynamically generated UIPanel
178                 if (Boolean.TRUE.equals(facet.getAttributes()
179                              .get(FACET_CREATED_UIPANEL_MARKER)))
180                 {
181                     // only check the children and facets of the panel
182                     if (facet.getChildCount() > 0)
183                     {
184                         for (int i = 0, childCount = facet.getChildCount(); i < childCount; i ++)
185                         {
186                             UIComponent child = facet.getChildren().get(i);
187                             if (instance.equals(child))
188                             {
189                                 return entry.getKey();
190                             }
191                         }
192                     }
193                     if (facet.getFacetCount() > 0)
194                     {
195                         Iterator<UIComponent> itr2 = facet.getFacets().values().iterator();
196                         while (itr2.hasNext())
197                         {
198                             UIComponent child = itr2.next();
199                             if (instance.equals(child))
200                             {
201                                 return entry.getKey();
202                             }
203                         }
204                     }
205                 }
206                 else if (instance.equals(facet))
207                 {
208                     return entry.getKey();
209                 }
210             }
211             return null;
212         }
213         return null;
214     }
215 
216     public static UIComponent findChildInFacetByTagId(
217         UIComponent parent, String id, String facetName)
218     {
219         if (parent.getFacetCount() > 0)
220         {
221             UIComponent facet = parent.getFacet(facetName);
222             if (facet != null)
223             {
224                 // check if this is a dynamically generated UIPanel
225                 if (Boolean.TRUE.equals(facet.getAttributes()
226                              .get(FACET_CREATED_UIPANEL_MARKER)))
227                 {
228                     // only check the children and facets of the panel
229                     if (facet.getChildCount() > 0)
230                     {
231                         for (int i = 0, childCount = facet.getChildCount(); i < childCount; i ++)
232                         {
233                             UIComponent child = facet.getChildren().get(i);
234                             if (id.equals(child.getAttributes().get(MARK_CREATED)))
235                             {
236                                 return child;
237                             }
238                         }
239                     }
240                     if (facet.getFacetCount() > 0)
241                     {
242                         Iterator<UIComponent> itr2 = facet.getFacets().values().iterator();
243                         while (itr2.hasNext())
244                         {
245                             UIComponent child = itr2.next();
246                             if (id.equals(child.getAttributes().get(MARK_CREATED)))
247                             {
248                                 return child;
249                             }
250                         }
251                     }
252                 }
253                 else if (id.equals(facet.getAttributes().get(MARK_CREATED)))
254                 {
255                     return facet;
256                 }
257             }
258         }
259         return null;
260     }
261     
262     public static UIComponent findChildInChildrenByTagId(
263         UIComponent parent, String id)
264     {
265         if (parent.getChildCount() > 0)
266         {
267             for (int i = 0, childCount = parent.getChildCount(); i < childCount; i ++)
268             {
269                 UIComponent child = parent.getChildren().get(i);
270                 if (id.equals(child.getAttributes().get(MARK_CREATED)))
271                 {
272                     return child;
273                 }
274             }
275         }
276         return null;
277     }
278     
279     /**
280      * By TagId, find Child
281      * 
282      * @param parent
283      * @param id
284      * @return
285      */
286     public static UIComponent findChildByTagId(UIComponent parent, String id)
287     {
288         Iterator<UIComponent> itr = null;
289         if (parent.getChildCount() > 0)
290         {
291             for (int i = 0, childCount = parent.getChildCount(); i < childCount; i ++)
292             {
293                 UIComponent child = parent.getChildren().get(i);
294                 if (id.equals(child.getAttributes().get(MARK_CREATED)))
295                 {
296                     return child;
297                 }
298             }
299         }
300         if (parent.getFacetCount() > 0)
301         {
302             itr = parent.getFacets().values().iterator();
303             while (itr.hasNext())
304             {
305                 UIComponent facet = itr.next();
306                 // check if this is a dynamically generated UIPanel
307                 if (Boolean.TRUE.equals(facet.getAttributes()
308                              .get(FACET_CREATED_UIPANEL_MARKER)))
309                 {
310                     // only check the children and facets of the panel
311                     if (facet.getChildCount() > 0)
312                     {
313                         for (int i = 0, childCount = facet.getChildCount(); i < childCount; i ++)
314                         {
315                             UIComponent child = facet.getChildren().get(i);
316                             if (id.equals(child.getAttributes().get(MARK_CREATED)))
317                             {
318                                 return child;
319                             }
320                         }
321                     }
322                     if (facet.getFacetCount() > 0)
323                     {
324                         Iterator<UIComponent> itr2 = facet.getFacets().values().iterator();
325                         while (itr2.hasNext())
326                         {
327                             UIComponent child = itr2.next();
328                             if (id.equals(child.getAttributes().get(MARK_CREATED)))
329                             {
330                                 return child;
331                             }
332                         }
333                     }
334                 }
335                 else if (id.equals(facet.getAttributes().get(MARK_CREATED)))
336                 {
337                     return facet;
338                 }
339             }
340         }
341 
342         return null;
343     }
344     
345     public static String findChildInFacetsByTagId(UIComponent parent, String id)
346     {
347         Iterator<Map.Entry<String, UIComponent>> itr = null;
348         if (parent.getFacetCount() > 0)
349         {
350             itr = parent.getFacets().entrySet().iterator();
351             while (itr.hasNext())
352             {
353                 Map.Entry<String, UIComponent> entry = itr.next();
354                 UIComponent facet = entry.getValue();
355                 // check if this is a dynamically generated UIPanel
356                 if (Boolean.TRUE.equals(facet.getAttributes()
357                              .get(FACET_CREATED_UIPANEL_MARKER)))
358                 {
359                     // only check the children and facets of the panel
360                     if (facet.getChildCount() > 0)
361                     {
362                         for (int i = 0, childCount = facet.getChildCount(); i < childCount; i ++)
363                         {
364                             UIComponent child = facet.getChildren().get(i);
365                             if (id.equals(child.getAttributes().get(MARK_CREATED)))
366                             {
367                                 return entry.getKey();
368                             }
369                         }
370                     }
371                     if (facet.getFacetCount() > 0)
372                     {
373                         Iterator<UIComponent> itr2 = facet.getFacets().values().iterator();
374                         while (itr2.hasNext())
375                         {
376                             UIComponent child = itr2.next();
377                             if (id.equals(child.getAttributes().get(MARK_CREATED)))
378                             {
379                                 return entry.getKey();
380                             }
381                         }
382                     }
383                 }
384                 else if (id.equals(facet.getAttributes().get(MARK_CREATED)))
385                 {
386                     return entry.getKey();
387                 }
388             }
389         }
390         return null;
391     }
392 
393     /**
394      * According to JSF 1.2 tag specs, this helper method will use the TagAttribute passed in determining the Locale
395      * intended.
396      * 
397      * @param ctx
398      *            FaceletContext to evaluate from
399      * @param attr
400      *            TagAttribute representing a Locale
401      * @return Locale found
402      * @throws TagAttributeException
403      *             if the Locale cannot be determined
404      */
405     public static Locale getLocale(FaceletContext ctx, TagAttribute attr) throws TagAttributeException
406     {
407         Object obj = attr.getObject(ctx);
408         if (obj instanceof Locale)
409         {
410             return (Locale) obj;
411         }
412         if (obj instanceof String)
413         {
414             String s = (String) obj;
415             if (s.length() == 2)
416             {
417                 return new Locale(s);
418             }
419 
420             if (s.length() == 5)
421             {
422                 return new Locale(s.substring(0, 2), s.substring(3, 5).toUpperCase());
423             }
424 
425             if (s.length() >= 7)
426             {
427                 return new Locale(s.substring(0, 2), s.substring(3, 5).toUpperCase(), s.substring(6, s.length()));
428             }
429 
430             throw new TagAttributeException(attr, "Invalid Locale Specified: " + s);
431         }
432         else
433         {
434             throw new TagAttributeException(attr, "Attribute did not evaluate to a String or Locale: " + obj);
435         }
436     }
437 
438     /**
439      * Tries to walk up the parent to find the UIViewRoot, if not found, then go to FaceletContext's FacesContext for
440      * the view root.
441      * 
442      * @param ctx
443      *            FaceletContext
444      * @param parent
445      *            UIComponent to search from
446      * @return UIViewRoot instance for this evaluation
447      */
448     public static UIViewRoot getViewRoot(FaceletContext ctx, UIComponent parent)
449     {
450         UIComponent c = parent;
451         do
452         {
453             if (c instanceof UIViewRoot)
454             {
455                 return (UIViewRoot) c;
456             }
457             else
458             {
459                 c = c.getParent();
460             }
461         } while (c != null);
462 
463         UIViewRoot root = ctx.getFacesContext().getViewRoot();
464         if (root == null)
465         {
466             root = FaceletCompositionContext.getCurrentInstance(ctx).getViewRoot(ctx.getFacesContext());
467         }
468         return root;
469     }
470     
471     /**
472      * Marks all direct children and Facets with an attribute for deletion.
473      * 
474      * @deprecated use FaceletCompositionContext.markForDeletion
475      * @see #finalizeForDeletion(UIComponent)
476      * @param component
477      *            UIComponent to mark
478      */
479     @Deprecated
480     public static void markForDeletion(UIComponent component)
481     {
482         // flag this component as deleted
483         component.getAttributes().put(MARK_DELETED, Boolean.TRUE);
484 
485         Iterator<UIComponent> iter = component.getFacetsAndChildren();
486         while (iter.hasNext())
487         {
488             UIComponent child = iter.next();
489             if (child.getAttributes().containsKey(MARK_CREATED))
490             {
491                 child.getAttributes().put(MARK_DELETED, Boolean.TRUE);
492             }
493         }
494     }
495 
496     public static void encodeRecursive(FacesContext context, UIComponent toRender) throws IOException, FacesException
497     {
498         if (toRender.isRendered())
499         {
500             toRender.encodeBegin(context);
501             
502             if (toRender.getRendersChildren())
503             {
504                 toRender.encodeChildren(context);
505             }
506             else if (toRender.getChildCount() > 0)
507             {
508                 for (int i = 0, childCount = toRender.getChildCount(); i < childCount; i++)
509                 {
510                     UIComponent child = toRender.getChildren().get(i);
511                     encodeRecursive(context, child);
512                 }
513             }
514             
515             toRender.encodeEnd(context);
516         }
517     }
518 
519     public static void removeTransient(UIComponent component)
520     {
521         if (component.getChildCount() > 0)
522         {
523             for (Iterator<UIComponent> itr = component.getChildren().iterator(); itr.hasNext();)
524             {
525                 UIComponent child = itr.next();
526                 if (child.isTransient())
527                 {
528                     itr.remove();
529                 }
530                 else
531                 {
532                     removeTransient(child);
533                 }
534             }
535         }
536         
537         if (component.getFacetCount() > 0)
538         {
539             Map<String, UIComponent> facets = component.getFacets();
540             for (Iterator<UIComponent> itr = facets.values().iterator(); itr.hasNext();)
541             {
542                 UIComponent facet = itr.next();
543                 if (facet.isTransient())
544                 {
545                     itr.remove();
546                 }
547                 else
548                 {
549                     removeTransient(facet);
550                 }
551             }
552         }
553     }
554 
555     /**
556      * Determine if the passed component is not null and if it's new to the tree. This operation can be used for
557      * determining if attributes should be wired to the component.
558      * 
559      * @deprecated use ComponentHandler.isNew
560      * @param component
561      *            the component you wish to modify
562      * @return true if it's new
563      */
564     @Deprecated
565     public static boolean isNew(UIComponent component)
566     {
567         return component != null && component.getParent() == null;
568     }
569     
570     /**
571      * Create a new UIPanel for the use as a dynamically 
572      * created container for multiple children in a facet.
573      * Duplicate in javax.faces.webapp.UIComponentClassicTagBase.
574      * @param facesContext
575      * @return
576      */
577     private static UIComponent createFacetUIPanel(FaceletContext ctx, UIComponent parent, String facetName)
578     {
579         FacesContext facesContext = ctx.getFacesContext();
580         UIComponent panel = facesContext.getApplication().createComponent(facesContext, UIPanel.COMPONENT_TYPE, null);
581         
582         // The panel created by this method is special. To be restored properly and do not
583         // create duplicate ids or any other unwanted conflicts, it requires an unique id.
584         // This code is usually called when more than one component is added to a facet and
585         // it is necessary to create a shared container.
586         // Use FaceletCompositionContext.generateUniqueComponentId() is not possible, because
587         // <c:if> blocks inside a facet will make component ids unstable. Use UniqueIdVendor
588         // is feasible but also will be affected by <c:if> blocks inside a facet.
589         // The only solution that will generate real unique ids is use the parent id and the
590         // facet name and derive an unique id that cannot be generated by SectionUniqueIdCounter,
591         // doing the same trick as with metadata: use a double __ and add a prefix (f).
592         // Note this id will never be printed into the response, because this is just a container.
593         FaceletCompositionContext mctx = FaceletCompositionContext.getCurrentInstance(ctx);
594         UniqueIdVendor uniqueIdVendor = mctx.getUniqueIdVendorFromStack();
595         if (uniqueIdVendor == null)
596         {
597             uniqueIdVendor = ComponentSupport.getViewRoot(ctx, parent);
598         }
599         if (uniqueIdVendor != null)
600         {
601             // UIViewRoot implements UniqueIdVendor, so there is no need to cast to UIViewRoot
602             // and call createUniqueId(). See ComponentTagHandlerDelegate
603             int index = facetName.indexOf('.');
604             String cleanFacetName = facetName;
605             if (index >= 0)
606             {
607                 cleanFacetName = facetName.replace('.', '_');
608             }
609             panel.setId(uniqueIdVendor.createUniqueId(facesContext, 
610                     mctx.getSharedStringBuilder()
611                       .append(parent.getId())
612                       .append("__f_")
613                       .append(cleanFacetName).toString()));
614         }
615         panel.getAttributes().put(FACET_CREATED_UIPANEL_MARKER, Boolean.TRUE);
616         panel.getAttributes().put(ComponentSupport.COMPONENT_ADDED_BY_HANDLER_MARKER, Boolean.TRUE);
617         return panel;
618     }
619     
620     public static void addFacet(FaceletContext ctx, UIComponent parent, UIComponent c, String facetName)
621     {
622         // facets now can have multiple children and the direct
623         // child of a facet is always an UIPanel (since 2.0)
624         UIComponent facet = parent.getFacets().get(facetName);
625         if (facet == null)
626         {
627             //Just set it directly like  before
628             parent.getFacets().put(facetName, c);
629         }
630         else if (!(facet instanceof UIPanel))
631         {
632             // there is a facet, but it is not an instance of UIPanel
633             UIComponent child = facet;
634             facet = createFacetUIPanel(ctx, parent, facetName);
635             facet.getChildren().add(child);
636             facet.getChildren().add(c);
637             parent.getFacets().put(facetName, facet);
638         }
639         else
640         {
641             // we have a facet, which is an instance of UIPanel at this point
642             // check if it is a facet marked UIPanel
643             if (Boolean.TRUE.equals(facet.getAttributes().get(FACET_CREATED_UIPANEL_MARKER)))
644             {
645                 facet.getChildren().add(c);
646             }
647             else
648             {
649                 // the facet is an instance of UIPanel, but it is not marked,
650                 // so we have to create a new UIPanel and store this one in it
651                 UIComponent oldPanel = facet;
652                 facet = createFacetUIPanel(ctx, parent, facetName);
653                 facet.getChildren().add(oldPanel);
654                 facet.getChildren().add(c);
655                 parent.getFacets().put(facetName, facet);
656             }
657         }
658     }
659     
660     public static void removeFacet(FaceletContext ctx, UIComponent parent, UIComponent c, String facetName)
661     {
662         UIComponent facet = parent.getFacet(facetName);
663         if (Boolean.TRUE.equals(facet.getAttributes().get(FACET_CREATED_UIPANEL_MARKER)))
664         {
665             facet.getChildren().remove(c);
666         }
667         else
668         {
669             parent.getFacets().remove(facetName);
670         }
671     }
672 
673     public static void markComponentToRestoreFully(FacesContext context, UIComponent component)
674     {
675         if (MyfacesConfig.getCurrentInstance(context.getExternalContext()).isRefreshTransientBuildOnPSSPreserveState())
676         {
677             component.getAttributes().put(DefaultFaceletsStateManagementStrategy.COMPONENT_ADDED_AFTER_BUILD_VIEW,
678                                           ComponentState.REMOVE_ADD);
679         }
680         //component.subscribeToEvent(PostAddToViewEvent.class, new RestoreComponentFullyListener());
681         if (FaceletViewDeclarationLanguage.isRefreshTransientBuildOnPSSAuto(context))
682         {
683             FaceletViewDeclarationLanguage.cleanTransientBuildOnRestore(context);
684         }
685     }
686     
687     public static void markComponentToRefreshDynamically(FacesContext context, UIComponent component)
688     {
689         FaceletViewDeclarationLanguageBase.dynamicComponentNeedsRefresh(context);
690     }
691     
692     public static UIComponent findComponentChildOrFacetFrom(FacesContext facesContext, UIComponent parent, String expr)
693     {
694         final char separatorChar = facesContext.getNamingContainerSeparatorChar();
695         int separator = expr.indexOf(separatorChar);
696         if (separator == -1)
697         {
698             return ComponentSupport.findComponentChildOrFacetFrom(
699                     parent, expr, null);
700         }
701         else
702         {
703             return ComponentSupport.findComponentChildOrFacetFrom(
704                     parent, expr.substring(0,separator), expr);
705         }
706     }
707     
708     public static UIComponent findComponentChildOrFacetFrom(UIComponent parent, String id, String innerExpr)
709     {
710         if (parent.getFacetCount() > 0)
711         {
712             for (UIComponent facet : parent.getFacets().values())
713             {
714                 if (id.equals(facet.getId()))
715                 {
716                     if (innerExpr == null)
717                     {
718                         return facet;
719                     }
720                     else if (facet instanceof NamingContainer)
721                     {
722                         UIComponent find = facet.findComponent(innerExpr);
723                         if (find != null)
724                         {
725                             return find;
726                         }
727                     }
728                 }
729                 else if (!(facet instanceof NamingContainer))
730                 {
731                     UIComponent find = findComponentChildOrFacetFrom(facet, id, innerExpr);
732                     if (find != null)
733                     {
734                         return find;
735                     }
736                 }
737             }
738         }
739         if (parent.getChildCount() > 0)
740         {
741             for (int i = 0, childCount = parent.getChildCount(); i < childCount; i++)
742             {
743                 UIComponent child = parent.getChildren().get(i);
744                 if (id.equals(child.getId()))
745                 {
746                     if (innerExpr == null)
747                     {
748                         return child;
749                     }
750                     else if (child instanceof NamingContainer)
751                     {
752                         UIComponent find = child.findComponent(innerExpr);
753                         if (find != null)
754                         {
755                             return find;
756                         }
757                     }
758                 }
759                 else if (!(child instanceof NamingContainer))
760                 {
761                     UIComponent find = findComponentChildOrFacetFrom(child, id, innerExpr);
762                     if (find != null)
763                     {
764                         return find;
765                     }
766                 }
767             }
768         }
769         return null;
770     }
771     
772     public static String getFindComponentExpression(FacesContext facesContext, UIComponent component)
773     {
774         char separatorChar = facesContext.getNamingContainerSeparatorChar();
775         UIComponent parent = component.getParent();
776         StringBuilder sb = new StringBuilder();
777         sb.append(component.getId());
778         while (parent != null)
779         {
780             if (parent instanceof NamingContainer)
781             {
782                 sb.insert(0, separatorChar);
783                 sb.insert(0, parent.getId());
784             }
785             parent = parent.getParent();
786         }
787         return sb.toString();
788     }
789     
790     public static Object restoreInitialTagState(FaceletContext ctx, FaceletCompositionContext fcc,
791                                                 UIComponent parent, String uniqueId)
792     {
793         Object value = null;
794         //if (fcc.isUsingPSSOnThisView() &&
795         //    PhaseId.RESTORE_VIEW.equals(ctx.getFacesContext().getCurrentPhaseId()) &&
796         //    !MyfacesConfig.getCurrentInstance(
797         //            ctx.getFacesContext().getExternalContext()).isRefreshTransientBuildOnPSSPreserveState())
798         if (fcc.isUsingPSSOnThisView() && !fcc.isRefreshTransientBuildOnPSSPreserveState())
799         {
800             UIViewRoot root = getViewRoot(ctx, parent);
801             FaceletState map = (FaceletState) root.getAttributes().get(FACELET_STATE_INSTANCE);
802             if (map == null)
803             {
804                 value = null;
805             }
806             else
807             {
808                 value = map.getState(uniqueId);
809             }
810         }
811         return value;
812     }
813     
814     public static void saveInitialTagState(FaceletContext ctx, FaceletCompositionContext fcc,
815                                            UIComponent parent, String uniqueId, Object value)
816     {
817         // Only save the value when the view was built the first time, to ensure PSS algorithm 
818         // work correctly. If preserve state is enabled, just ignore it, because this tag will
819         // force full restore over the parent
820         //if (fcc.isUsingPSSOnThisView()) {
821         //    if (!fcc.isRefreshingTransientBuild() && !ctx.getFacesContext().isPostback()
822         //        && !MyfacesConfig.getCurrentInstance(
823         //            ctx.getFacesContext().getExternalContext()).isRefreshTransientBuildOnPSSPreserveState())
824         
825         // If we save the value each time the view is updated, we can use PSS on the dynamic parts,
826         // just calling markInitialState() on the required components, simplifying the algorithm.
827         if (fcc.isUsingPSSOnThisView() && !fcc.isRefreshTransientBuildOnPSSPreserveState())
828         {
829             UIViewRoot root = getViewRoot(ctx, parent);
830             FaceletState map = (FaceletState) root.getAttributes().get(FACELET_STATE_INSTANCE);
831             if (map == null)
832             {
833                 map = new FaceletState();
834                 root.getAttributes().put(FACELET_STATE_INSTANCE, map);
835             }
836             map.putState(uniqueId, value);
837         }
838     }
839     
840     public static FaceletState getFaceletState(FaceletContext ctx, UIComponent parent, boolean create)
841     {
842         UIViewRoot root = getViewRoot(ctx, parent);
843         FaceletState map = (FaceletState) root.getAttributes().get(FACELET_STATE_INSTANCE);
844         if (map == null && create)
845         {
846             map = new FaceletState();
847             root.getAttributes().put(FACELET_STATE_INSTANCE, map);
848         }
849         return map;
850     }
851     
852     public static void setCachedFacesContext(UIComponent component,
853         FacesContext context)
854     {
855         if (SET_CACHED_FACES_CONTEXT != null)
856         {
857             try
858             {
859                 SET_CACHED_FACES_CONTEXT.invoke(component, context);
860             }
861             catch (IllegalAccessException ex)
862             {
863             }
864             catch (IllegalArgumentException ex)
865             {
866             }
867             catch (InvocationTargetException ex)
868             {
869             }
870         }
871     }
872 }