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.composite;
20  
21  import java.beans.BeanDescriptor;
22  import java.beans.BeanInfo;
23  import java.beans.PropertyDescriptor;
24  import java.io.IOException;
25  import java.util.ArrayList;
26  import java.util.Collection;
27  import java.util.HashMap;
28  import java.util.Iterator;
29  import java.util.List;
30  import java.util.Map;
31  
32  import javax.el.ELException;
33  import javax.el.ValueExpression;
34  import javax.el.VariableMapper;
35  import javax.faces.FacesException;
36  import javax.faces.application.ProjectStage;
37  import javax.faces.application.Resource;
38  import javax.faces.component.ActionSource;
39  import javax.faces.component.EditableValueHolder;
40  import javax.faces.component.UIComponent;
41  import javax.faces.component.UIPanel;
42  import javax.faces.component.UniqueIdVendor;
43  import javax.faces.component.ValueHolder;
44  import javax.faces.context.FacesContext;
45  import javax.faces.event.PhaseId;
46  import javax.faces.view.AttachedObjectHandler;
47  import javax.faces.view.ViewDeclarationLanguage;
48  import javax.faces.view.facelets.ComponentConfig;
49  import javax.faces.view.facelets.ComponentHandler;
50  import javax.faces.view.facelets.FaceletContext;
51  import javax.faces.view.facelets.FaceletException;
52  import javax.faces.view.facelets.FaceletHandler;
53  import javax.faces.view.facelets.MetaRuleset;
54  import javax.faces.view.facelets.Metadata;
55  import javax.faces.view.facelets.TagException;
56  import javax.faces.view.facelets.TextHandler;
57  
58  import org.apache.myfaces.view.facelets.AbstractFaceletContext;
59  import org.apache.myfaces.view.facelets.FaceletCompositionContext;
60  import org.apache.myfaces.view.facelets.TemplateClient;
61  import org.apache.myfaces.view.facelets.TemplateContext;
62  import org.apache.myfaces.view.facelets.el.VariableMapperWrapper;
63  import org.apache.myfaces.view.facelets.tag.ComponentContainerHandler;
64  import org.apache.myfaces.view.facelets.tag.TagHandlerUtils;
65  import org.apache.myfaces.view.facelets.tag.jsf.ActionSourceRule;
66  import org.apache.myfaces.view.facelets.tag.jsf.ClearBindingValueExpressionListener;
67  import org.apache.myfaces.view.facelets.tag.jsf.ComponentBuilderHandler;
68  import org.apache.myfaces.view.facelets.tag.jsf.ComponentSupport;
69  import org.apache.myfaces.view.facelets.tag.jsf.EditableValueHolderRule;
70  import org.apache.myfaces.view.facelets.tag.jsf.PreDisposeViewEvent;
71  import org.apache.myfaces.view.facelets.tag.jsf.ValueHolderRule;
72  import org.apache.myfaces.view.facelets.tag.jsf.core.AjaxHandler;
73  
74  /**
75   * This handler is responsible for apply composite components. It
76   * is created by CompositeResourceLibrary class when a composite component
77   * is found.
78   * 
79   * @author Leonardo Uribe (latest modification by $Author$)
80   * @version $Revision$ $Date$
81   */
82  public class CompositeComponentResourceTagHandler extends ComponentHandler
83      implements ComponentBuilderHandler, TemplateClient
84  {
85      public static final String CREATE_CC_ON_POST_ADD_TO_VIEW = "oamf.cc.CREATE_CC_POST_ADD_TO_VIEW";
86      
87      private final Resource _resource;
88      
89      private Metadata _mapper;
90      
91      private Class<?> _lastType = Object.class;
92      
93      protected volatile Map<String, FaceletHandler> _facetHandlersMap;
94      
95      protected final Collection<FaceletHandler> _componentHandlers;
96      
97      protected final Collection<FaceletHandler> _facetHandlers;
98      
99      private boolean _dynamicCompositeComponent;
100     
101     public CompositeComponentResourceTagHandler(ComponentConfig config, Resource resource)
102     {
103         super(config);
104         _resource = resource;
105         _facetHandlers = TagHandlerUtils.findNextByType(nextHandler, javax.faces.view.facelets.FacetHandler.class,
106                                                         InsertFacetHandler.class);
107         _componentHandlers = TagHandlerUtils.findNextByType(nextHandler,
108                 javax.faces.view.facelets.ComponentHandler.class,
109                 ComponentContainerHandler.class, TextHandler.class);
110         _dynamicCompositeComponent = false;
111     }
112 
113     public UIComponent createComponent(FaceletContext ctx)
114     {
115         FacesContext facesContext = ctx.getFacesContext();
116         UIComponent component = facesContext.getApplication().createComponent(facesContext, _resource);
117         
118         if (getBinding() != null)
119         {
120             ValueExpression bindingVE = getBinding().getValueExpression(ctx, Object.class);
121             component.setValueExpression("binding", bindingVE);
122             
123             if (!bindingVE.isReadOnly(facesContext.getELContext()))
124             {
125                 if (PhaseId.RESTORE_VIEW.equals(facesContext.getCurrentPhaseId()))
126                 {
127                     bindingVE.setValue(ctx, component);
128                 }
129                 
130                 ComponentSupport.getViewRoot(ctx, component)
131                         .getAttributes().put("oam.CALL_PRE_DISPOSE_VIEW", Boolean.TRUE);
132                 component.subscribeToEvent(PreDisposeViewEvent.class, new ClearBindingValueExpressionListener());
133             }
134         }
135         
136         // Check required attributes if the app is not on production stage. 
137         // Unfortunately, we can't check it on constructor because we need to call
138         // ViewDeclarationLanguage.getComponentMetadata() and on that point it is possible to not
139         // have a viewId.
140         if (!facesContext.isProjectStage(ProjectStage.Production))
141         {
142             BeanInfo beanInfo = (BeanInfo) component.getAttributes().get(UIComponent.BEANINFO_KEY);
143             for (PropertyDescriptor propertyDescriptor : beanInfo.getPropertyDescriptors())
144             {
145                 ValueExpression ve = (ValueExpression) propertyDescriptor.getValue("required");
146                 if (ve != null)
147                 {
148                     Object value = ve.getValue (facesContext.getELContext());
149                     Boolean required = null;
150                     if (value instanceof Boolean)
151                     {
152                         required = (Boolean) value;
153                     }
154                     else
155                     {
156                         required = Boolean.valueOf(value.toString());
157                     } 
158                     
159                     if (required != null && required.booleanValue())
160                     {
161                         Object attrValue = this.tag.getAttributes().get (propertyDescriptor.getName());
162                         
163                         if (attrValue == null)
164                         {
165                             throw new TagException(this.tag, "Attribute '" + propertyDescriptor.getName()
166                                                              + "' is required");
167                         }
168                     }
169                 }
170             }
171         }
172         return component;
173     }
174 
175     @SuppressWarnings("unchecked")
176     @Override
177     public void applyNextHandler(FaceletContext ctx, UIComponent c)
178             throws IOException
179     {
180         //super.applyNextHandler(ctx, c);
181         FaceletCompositionContext mctx = FaceletCompositionContext.getCurrentInstance(ctx);
182         
183         // Since JSF 2.2, there are two cases here:
184         // 
185         // 1. The composite component content is defined as facelet content like usual.
186         // 2. The composite component content will be defined programatically. That means,
187         // once the component instance is created, the user will be responsible to add
188         // children / facets and the code that process the composite component take effect
189         // when the composite component is added to the view. 
190         if (mctx.isDynamicCompositeComponentHandler())
191         {
192             _dynamicCompositeComponent = true;
193             try
194             {
195                 mctx.setDynamicCompositeComponentHandler(false);
196                 // If the composite component needs to be created dynamically
197                 // 
198                 Integer step = (Integer) c.getAttributes().get(CREATE_CC_ON_POST_ADD_TO_VIEW); 
199                 if (step == null)
200                 {
201                     // The flag is not found, so we are creating the component right now.
202                     // Add the flag and return.
203                     c.getAttributes().put(CREATE_CC_ON_POST_ADD_TO_VIEW, 0);
204                 }
205                 else if (step.intValue() == 0)
206                 {
207                     // Should not happen, stop processing
208                 }
209                 else if (step.intValue() == 1)
210                 {
211                     // The component was created, and the listener attached to PostAddToViewEvent
212                     // is executing right now. Do the necessary steps to process the 
213                     // composite component dynamically.
214                     applyNextHandlerIfNotAppliedDynamically(ctx, c);
215 
216                     applyCompositeComponentFacelet(ctx,c);
217 
218                     applyFinalInitializationSteps(ctx, mctx, c);
219 
220                     c.getAttributes().put(CREATE_CC_ON_POST_ADD_TO_VIEW, 2);
221                 }
222                 else
223                 {
224                     // Refresh over dynamic composite component        
225                     applyCompositeComponentFacelet(ctx,c);
226                 }
227             }
228             finally
229             {
230                 mctx.setDynamicCompositeComponentHandler(true);
231             }
232         }
233         else
234         {
235             applyNextHandlerIfNotApplied(ctx, c);
236 
237             applyCompositeComponentFacelet(ctx,c);
238 
239             if (ComponentHandler.isNew(c))
240             {
241                 applyFinalInitializationSteps(ctx, mctx, c);
242             }
243         }
244     }
245     
246     protected void applyFinalInitializationSteps(FaceletContext ctx, FaceletCompositionContext mctx, UIComponent c)
247     {
248         FacesContext facesContext = ctx.getFacesContext();
249 
250         ViewDeclarationLanguage vdl = facesContext.getApplication().getViewHandler().
251             getViewDeclarationLanguage(facesContext, facesContext.getViewRoot().getViewId());
252 
253         List<AttachedObjectHandler> handlers = mctx.getAttachedObjectHandlers(c);
254 
255         if (handlers != null)
256         {
257             vdl.retargetAttachedObjects(facesContext, c, handlers);
258 
259             // remove the list of handlers, as it is no longer necessary
260             mctx.removeAttachedObjectHandlers(c);
261         }
262 
263         vdl.retargetMethodExpressions(facesContext, c);
264 
265         if ( FaceletCompositionContext.getCurrentInstance(ctx).isMarkInitialState())
266         {
267             // Call it only if we are using partial state saving
268             c.markInitialState();
269             // Call it to other components created not bound by a tag handler
270             c.getFacet(UIComponent.COMPOSITE_FACET_NAME).markInitialState();
271         }
272     }
273     
274     @SuppressWarnings("unchecked")
275     protected void applyNextHandlerIfNotApplied(FaceletContext ctx, UIComponent c)
276         throws IOException
277     {
278         //Apply all facelets not applied yet.
279         
280         CompositeComponentBeanInfo beanInfo = 
281             (CompositeComponentBeanInfo) c.getAttributes().get(UIComponent.BEANINFO_KEY);
282         
283         BeanDescriptor beanDescriptor = beanInfo.getBeanDescriptor();
284 
285         boolean insertChildrenUsed = (beanDescriptor.getValue(InsertChildrenHandler.INSERT_CHILDREN_USED) != null);
286         
287         List<String> insertFacetList = (List<String>) beanDescriptor.getValue(InsertFacetHandler.INSERT_FACET_USED);
288         
289         if (nextHandler instanceof javax.faces.view.facelets.CompositeFaceletHandler)
290         {
291             for (FaceletHandler handler :
292                     ((javax.faces.view.facelets.CompositeFaceletHandler)nextHandler).getHandlers())
293             {
294                 if (handler instanceof javax.faces.view.facelets.FacetHandler)
295                 {
296                     if (insertFacetList == null ||
297                         !insertFacetList.contains(((javax.faces.view.facelets.FacetHandler)handler).getFacetName(ctx)))
298                     {
299                         handler.apply(ctx, c);
300                     }
301                 }
302                 else if (handler instanceof InsertFacetHandler)
303                 {
304                     if (insertFacetList == null ||
305                         !insertFacetList.contains( ((InsertFacetHandler)handler).getFacetName(ctx)))
306                     {
307                         handler.apply(ctx, c);
308                     }
309                 }
310                 else if (insertChildrenUsed)
311                 {
312                     if (!(handler instanceof javax.faces.view.facelets.ComponentHandler ||
313                             handler instanceof ComponentContainerHandler ||
314                             handler instanceof TextHandler))
315                     {
316                         handler.apply(ctx, c);
317                     }
318                 }
319                 else
320                 {
321                     handler.apply(ctx, c);
322                 }
323             }
324         }
325         else
326         {
327             if (nextHandler instanceof javax.faces.view.facelets.FacetHandler)
328             {
329                 if (insertFacetList == null ||
330                     !insertFacetList.contains(((javax.faces.view.facelets.FacetHandler)nextHandler).getFacetName(ctx)))
331                 {
332                     nextHandler.apply(ctx, c);
333                 }
334             }
335             else if (nextHandler instanceof InsertFacetHandler)
336             {
337                 if (insertFacetList == null ||
338                     !insertFacetList.contains( ((InsertFacetHandler)nextHandler).getFacetName(ctx)) )
339                 {
340                     nextHandler.apply(ctx, c);
341                 }
342             }
343             else if (insertChildrenUsed)
344             {
345                 if (!(nextHandler instanceof javax.faces.view.facelets.ComponentHandler ||
346                       nextHandler instanceof ComponentContainerHandler ||
347                       nextHandler instanceof TextHandler))
348                 {
349                     nextHandler.apply(ctx, c);
350                 }
351             }
352             else
353             {
354                 nextHandler.apply(ctx, c);
355             }
356         }
357         
358         //Check for required facets
359         Map<String, PropertyDescriptor> facetPropertyDescriptorMap = (Map<String, PropertyDescriptor>)
360             beanDescriptor.getValue(UIComponent.FACETS_KEY);
361         
362         if (facetPropertyDescriptorMap != null)
363         {
364             List<String> facetsRequiredNotFound = null;
365             for (Map.Entry<String, PropertyDescriptor> entry : facetPropertyDescriptorMap.entrySet())
366             {
367                 ValueExpression requiredExpr = (ValueExpression) entry.getValue().getValue("required");
368                 if (requiredExpr != null)
369                 {
370                     Boolean required = (Boolean) requiredExpr.getValue(ctx.getFacesContext().getELContext());
371                     if (Boolean.TRUE.equals(required))
372                     {
373                         initFacetHandlersMap(ctx);
374                         if (!_facetHandlersMap.containsKey(entry.getKey()))
375                         {
376                             if (facetsRequiredNotFound == null)
377                             {
378                                 facetsRequiredNotFound = new ArrayList(facetPropertyDescriptorMap.size());
379                             }
380                             facetsRequiredNotFound.add(entry.getKey());
381                         }
382                         
383                     }
384                 }
385             }
386             if (facetsRequiredNotFound != null && !facetsRequiredNotFound.isEmpty())
387             {
388                 throw new TagException(getTag(), "The following facets are required by the component: "
389                                                  + facetsRequiredNotFound);
390             }
391         }
392     }
393     
394     protected void applyCompositeComponentFacelet(FaceletContext faceletContext, UIComponent compositeComponentBase) 
395         throws IOException
396     {
397         FaceletCompositionContext mctx = FaceletCompositionContext.getCurrentInstance(faceletContext);
398         AbstractFaceletContext actx = (AbstractFaceletContext) faceletContext;
399         UIPanel compositeFacetPanel
400                 = (UIPanel) compositeComponentBase.getFacets().get(UIComponent.COMPOSITE_FACET_NAME);
401         if (compositeFacetPanel == null)
402         {
403             compositeFacetPanel = (UIPanel)
404                 faceletContext.getFacesContext().getApplication().createComponent(
405                     faceletContext.getFacesContext(), UIPanel.COMPONENT_TYPE, null);
406             compositeFacetPanel.getAttributes().put(ComponentSupport.COMPONENT_ADDED_BY_HANDLER_MARKER,
407                     Boolean.TRUE);
408             compositeComponentBase.getFacets().put(UIComponent.COMPOSITE_FACET_NAME, compositeFacetPanel);
409             
410             // Set an id to the created facet component, to prevent id generation and make
411             // partial state saving work without problem.
412             UniqueIdVendor uniqueIdVendor = mctx.getUniqueIdVendorFromStack();
413             if (uniqueIdVendor == null)
414             {
415                 uniqueIdVendor = ComponentSupport.getViewRoot(faceletContext, compositeComponentBase);
416             }
417             if (uniqueIdVendor != null)
418             {
419                 // UIViewRoot implements UniqueIdVendor, so there is no need to cast to UIViewRoot
420                 // and call createUniqueId()
421                 String uid = uniqueIdVendor.createUniqueId(faceletContext.getFacesContext(),
422                         mctx.getSharedStringBuilder()
423                         .append(compositeComponentBase.getId())
424                         .append("__f_")
425                         .append("cc_facet").toString());
426                 compositeFacetPanel.setId(uid);
427             }            
428         }
429         
430         // Before call applyCompositeComponent we need to add ajax behaviors
431         // to the current compositeComponentBase. Note that super.applyNextHandler()
432         // has already been called, but this point is before vdl.retargetAttachedObjects,
433         // so we can't but this on ComponentTagHandlerDelegate, if we want this to be
434         // applied correctly.
435         Iterator<AjaxHandler> it = ((AbstractFaceletContext) faceletContext).getAjaxHandlers();
436         if (it != null)
437         {
438             while(it.hasNext())
439             {
440                 mctx.addAttachedObjectHandler(
441                         compositeComponentBase, it.next());
442             }
443         }    
444         
445         VariableMapper orig = faceletContext.getVariableMapper();
446         try
447         {
448             faceletContext.setVariableMapper(new VariableMapperWrapper(orig));
449             actx.pushCompositeComponentClient(this);
450             Resource resourceForCurrentView = faceletContext.getFacesContext().getApplication().
451                 getResourceHandler().createResource(_resource.getResourceName(), _resource.getLibraryName());
452             if (resourceForCurrentView != null)
453             {
454                 //Wrap it for serialization.
455                 resourceForCurrentView = new CompositeResouceWrapper(resourceForCurrentView);
456             }
457             else
458             {
459                 //If a resource cannot be resolved it means a default for the current 
460                 //composite component does not exists.
461                 throw new TagException(getTag(), "Composite Component " + getTag().getQName() 
462                         + " requires a default instance that can be found by the installed ResourceHandler.");
463             }
464             actx.applyCompositeComponent(compositeFacetPanel, resourceForCurrentView);
465         }
466         finally
467         {
468             actx.popCompositeComponentClient();
469             faceletContext.setVariableMapper(orig);
470         }
471     }
472 
473     @Override
474     public void setAttributes(FaceletContext ctx, Object instance)
475     {
476         if (instance != null)
477         {
478             UIComponent component = (UIComponent) instance;
479 
480             Class<?> type = instance.getClass();
481             if (_mapper == null || !_lastType.equals(type))
482             {
483                 _lastType = type;
484                 BeanInfo beanInfo = (BeanInfo)component.getAttributes().get(UIComponent.BEANINFO_KEY);
485                 _mapper = createMetaRuleset(type , beanInfo).finish();
486             }
487             
488             _mapper.applyMetadata(ctx, instance);
489         }        
490     }
491 
492     protected MetaRuleset createMetaRuleset(Class<?> type, BeanInfo beanInfo)
493     {
494         MetaRuleset m = new CompositeMetaRulesetImpl(this.getTag(), type, beanInfo);
495         // ignore standard component attributes
496         m.ignore("binding").ignore("id");
497 
498         // add auto wiring for attributes
499         m.addRule(CompositeComponentRule.INSTANCE);
500         
501         // add retarget method expression rules
502         m.addRule(RetargetMethodExpressionRule.INSTANCE);
503         
504         if (ActionSource.class.isAssignableFrom(type))
505         {
506             m.addRule(ActionSourceRule.INSTANCE);
507         }
508 
509         if (ValueHolder.class.isAssignableFrom(type))
510         {
511             m.addRule(ValueHolderRule.INSTANCE);
512 
513             if (EditableValueHolder.class.isAssignableFrom(type))
514             {
515                 m.ignore("submittedValue");
516                 m.ignore("valid");
517                 m.addRule(EditableValueHolderRule.INSTANCE);
518             }
519         }
520         
521         return m;
522     }
523     
524     private void initFacetHandlersMap(FaceletContext ctx)
525     {
526         if (_facetHandlersMap == null)
527         {
528             Map<String, FaceletHandler> map = new HashMap<String, FaceletHandler>();
529             
530             for (FaceletHandler handler : _facetHandlers)
531             {
532                 if (handler instanceof javax.faces.view.facelets.FacetHandler )
533                 {
534                     map.put( ((javax.faces.view.facelets.FacetHandler)handler).getFacetName(ctx), handler);
535                 }
536                 else if (handler instanceof InsertFacetHandler)
537                 {
538                     map.put( ((InsertFacetHandler)handler).getFacetName(ctx), handler);
539                 }
540             }
541             _facetHandlersMap = map;
542         }
543     }
544     
545     public boolean apply(FaceletContext ctx, UIComponent parent, String name)
546             throws IOException, FacesException, FaceletException, ELException
547     {
548         if (_dynamicCompositeComponent)
549         {
550             AbstractFaceletContext actx = (AbstractFaceletContext) ctx;
551             FaceletCompositionContext fcc = actx.getFaceletCompositionContext(); 
552             UIComponent innerCompositeComponent = fcc.getCompositeComponentFromStack();
553             
554             // In a programatical addition, the code that process the composite component only takes effect
555             // when the composite component is added to the view.
556             Integer step = (Integer) innerCompositeComponent.getAttributes().get(CREATE_CC_ON_POST_ADD_TO_VIEW);
557             if (step != null && step.intValue() == 1)
558             {
559                 if (name != null)
560                 {
561                     //1. Initialize map used to retrieve facets
562                     if (innerCompositeComponent.getFacetCount() == 0)
563                     {
564                         checkFacetRequired(ctx, name);
565                         return true;
566                     }
567                     UIComponent facet = innerCompositeComponent.getFacet(name);
568                     if (facet != null)
569                     {
570                         // Insert facet
571                         innerCompositeComponent.getFacets().remove(name);
572                         parent.getFacets().put(name, facet);
573                         return true;
574                     }
575                     else
576                     {
577                         checkFacetRequired(ctx, name);
578                         return true;
579                     }
580                 }
581                 else
582                 {
583                     if (innerCompositeComponent.getChildCount() > 0)
584                     {
585                         String facetName = (String) parent.getAttributes().get(
586                                 org.apache.myfaces.view.facelets.tag.jsf.core.FacetHandler.KEY);
587                         // Insert children
588                         List<UIComponent> children = new ArrayList<UIComponent>(
589                             innerCompositeComponent.getChildCount());
590                         while (innerCompositeComponent.getChildCount() > 0)
591                         {
592                             children.add(innerCompositeComponent.getChildren().remove(0));
593                         }
594                         while (children.size() > 0)
595                         {
596                             UIComponent child = children.remove(0);
597                             child.getAttributes().put(InsertChildrenHandler.INSERT_CHILDREN_USED,
598                                     Boolean.TRUE);
599                             if (facetName != null)
600                             {
601                                 ComponentSupport.addFacet(ctx, parent, child, facetName);
602                             }
603                             else
604                             { 
605                                 parent.getChildren().add(child);
606                             }
607                         }
608                     }
609                     return true;
610                 }
611             }
612             else if (step != null && step.intValue() > 1)
613             {
614                 // refresh case, in facet case it is not necessary to remove/add the facet, because there
615                 // is no relative order (it is always on the same spot).
616                 if (name == null)
617                 {
618                     String facetName = (String) parent.getAttributes().get(
619                             org.apache.myfaces.view.facelets.tag.jsf.core.FacetHandler.KEY);
620                     // refresh case, remember the inserted children does not have any
621                     // associated tag handler, so in this case we just need to remove and add them in the same order 
622                     // we found them
623                     List<UIComponent> children = null;
624                     if (facetName == null)
625                     {
626                         children = new ArrayList<UIComponent>(parent.getChildCount());
627                         int i = 0;
628                         while (parent.getChildCount()-i > 0)
629                         {
630                             UIComponent child = parent.getChildren().get(i);
631                             if (Boolean.TRUE.equals(child.getAttributes().get(
632                                     InsertChildrenHandler.INSERT_CHILDREN_USED)))
633                             {
634                                 children.add(parent.getChildren().remove(i));
635                             }
636                             else
637                             {
638                                 i++;
639                             }
640                         }
641                     }
642                     else
643                     {
644                         children = new ArrayList<UIComponent>();
645                         UIComponent child = parent.getFacet(facetName);
646                         if (Boolean.TRUE.equals(child.getAttributes().get(
647                                     InsertChildrenHandler.INSERT_CHILDREN_USED)))
648                         {
649                             parent.getFacets().remove(facetName);
650                             children.add(child);
651                         }
652                         else
653                         {
654                             UIComponent parentToApply = child;
655                             int i = 0;
656                             while (parentToApply.getChildCount()-i > 0)
657                             {
658                                 child = parentToApply.getChildren().get(i);
659                                 if (Boolean.TRUE.equals(child.getAttributes().get(
660                                         InsertChildrenHandler.INSERT_CHILDREN_USED)))
661                                 {
662                                     children.add(parentToApply.getChildren().remove(i));
663                                 }
664                                 else
665                                 {
666                                     i++;
667                                 }
668                             }
669                         }
670                     }
671                     while (children.size() > 0)
672                     {
673                         UIComponent child = children.remove(0);
674                         if (facetName != null)
675                         {
676                             ComponentSupport.addFacet(ctx, parent, child, facetName);
677                         }
678                         else
679                         { 
680                             parent.getChildren().add(child);
681                         }
682                     }
683                 }
684             }
685             return true;
686         }
687         if (name != null)
688         {
689             //1. Initialize map used to retrieve facets
690             if (_facetHandlers == null || _facetHandlers.isEmpty())
691             {
692                 checkFacetRequired(ctx, name);
693                 return true;
694             }
695 
696             initFacetHandlersMap(ctx);
697 
698             FaceletHandler handler = _facetHandlersMap.get(name);
699 
700             if (handler != null)
701             {
702                 AbstractFaceletContext actx = (AbstractFaceletContext) ctx;
703                 // Pop the current composite component on stack, so #{cc} references
704                 // can be resolved correctly, because they are relative to the page 
705                 // that define it.
706                 FaceletCompositionContext fcc = actx.getFaceletCompositionContext(); 
707                 UIComponent innerCompositeComponent = fcc.getCompositeComponentFromStack(); 
708                 fcc.popCompositeComponentToStack();
709                 // Pop the template context, so ui:xx tags and nested composite component
710                 // cases could work correctly 
711                 TemplateContext itc = actx.popTemplateContext();
712                 try
713                 {
714                     handler.apply(ctx, parent);
715                 }
716                 finally
717                 {
718                     actx.pushTemplateContext(itc);
719                     fcc.pushCompositeComponentToStack(innerCompositeComponent);
720                 }
721                 return true;
722                 
723             }
724             else
725             {
726                 checkFacetRequired(ctx, name);
727                 return true;
728             }
729         }
730         else
731         {
732             AbstractFaceletContext actx = (AbstractFaceletContext) ctx;
733             // Pop the current composite component on stack, so #{cc} references
734             // can be resolved correctly, because they are relative to the page 
735             // that define it.
736             FaceletCompositionContext fcc = actx.getFaceletCompositionContext(); 
737             UIComponent innerCompositeComponent = fcc.getCompositeComponentFromStack(); 
738             fcc.popCompositeComponentToStack();
739             // Pop the template context, so ui:xx tags and nested composite component
740             // cases could work correctly 
741             TemplateContext itc = actx.popTemplateContext();
742             try
743             {
744                 for (FaceletHandler handler : _componentHandlers)
745                 {
746                     handler.apply(ctx, parent);
747                 }
748             }
749             finally
750             {
751                 actx.pushTemplateContext(itc);
752                 fcc.pushCompositeComponentToStack(innerCompositeComponent);
753             }
754             return true;
755         }
756     }
757     
758     private void checkFacetRequired(FaceletContext ctx, String name)
759     {
760         AbstractFaceletContext actx = (AbstractFaceletContext) ctx;
761         FaceletCompositionContext fcc = actx.getFaceletCompositionContext(); 
762         UIComponent innerCompositeComponent = fcc.getCompositeComponentFromStack();
763         
764         CompositeComponentBeanInfo beanInfo = 
765             (CompositeComponentBeanInfo) innerCompositeComponent.getAttributes()
766             .get(UIComponent.BEANINFO_KEY);
767         
768         BeanDescriptor beanDescriptor = beanInfo.getBeanDescriptor();
769         
770         Map<String, PropertyDescriptor> insertFacetPropertyDescriptorMap = (Map<String, PropertyDescriptor>)
771             beanDescriptor.getValue(InsertFacetHandler.INSERT_FACET_KEYS);
772 
773         if (insertFacetPropertyDescriptorMap != null && insertFacetPropertyDescriptorMap.containsKey(name))
774         {
775             ValueExpression requiredExpr
776                     = (ValueExpression) insertFacetPropertyDescriptorMap.get(name).getValue("required");
777             
778             if (requiredExpr != null &&
779                 Boolean.TRUE.equals(requiredExpr.getValue(ctx.getFacesContext().getELContext())))
780             {
781                 //Insert facet associated is required, but it was not applied.
782                 throw new TagException(this.tag, "Cannot find facet with name '"+name+"' in composite component");
783             }
784         }
785     }
786     
787     @SuppressWarnings("unchecked")
788     protected void applyNextHandlerIfNotAppliedDynamically(FaceletContext ctx, UIComponent c)
789         throws IOException
790     {
791         CompositeComponentBeanInfo beanInfo = 
792             (CompositeComponentBeanInfo) c.getAttributes().get(UIComponent.BEANINFO_KEY);
793         
794         BeanDescriptor beanDescriptor = beanInfo.getBeanDescriptor();
795 
796         // Since the children / facet were added programatically, there is no handler or facelets to apply.
797         
798         //Check for required facets
799         Map<String, PropertyDescriptor> facetPropertyDescriptorMap = (Map<String, PropertyDescriptor>)
800             beanDescriptor.getValue(UIComponent.FACETS_KEY);
801         
802         if (facetPropertyDescriptorMap != null)
803         {
804             List<String> facetsRequiredNotFound = null;
805             for (Map.Entry<String, PropertyDescriptor> entry : facetPropertyDescriptorMap.entrySet())
806             {
807                 ValueExpression requiredExpr = (ValueExpression) entry.getValue().getValue("required");
808                 if (requiredExpr != null)
809                 {
810                     Boolean required = (Boolean) requiredExpr.getValue(ctx.getFacesContext().getELContext());
811                     if (Boolean.TRUE.equals(required))
812                     {
813                         if (c.getFacet(entry.getKey()) == null)
814                         {
815                             if (facetsRequiredNotFound == null)
816                             {
817                                 facetsRequiredNotFound = new ArrayList(facetPropertyDescriptorMap.size());
818                             }
819                             facetsRequiredNotFound.add(entry.getKey());
820                         }
821                     }
822                 }
823             }
824             if (facetsRequiredNotFound != null && !facetsRequiredNotFound.isEmpty())
825             {
826                 throw new TagException(getTag(), "The following facets are required by the component: "
827                                                  + facetsRequiredNotFound);
828             }
829         }
830     }
831 }