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.impl;
20  
21  import java.util.ArrayList;
22  import java.util.HashMap;
23  import java.util.Iterator;
24  import java.util.LinkedList;
25  import java.util.List;
26  import java.util.Map;
27  
28  import javax.faces.component.UIComponent;
29  import javax.faces.component.UniqueIdVendor;
30  import javax.faces.context.FacesContext;
31  import javax.faces.view.AttachedObjectHandler;
32  import javax.faces.view.EditableValueHolderAttachedObjectHandler;
33  
34  import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFWebConfigParam;
35  import org.apache.myfaces.shared.config.MyfacesConfig;
36  import org.apache.myfaces.shared.util.WebConfigParamUtils;
37  import org.apache.myfaces.view.facelets.ELExpressionCacheMode;
38  import org.apache.myfaces.view.facelets.FaceletCompositionContext;
39  import org.apache.myfaces.view.facelets.FaceletFactory;
40  import org.apache.myfaces.view.facelets.FaceletViewDeclarationLanguage;
41  import org.apache.myfaces.view.facelets.tag.jsf.ComponentSupport;
42  
43  /**
44   * @since 2.0.1
45   * @author Leonardo Uribe (latest modification by $Author: lu4242 $)
46   * @version $Revision: 1306710 $ $Date: 2012-03-28 23:27:03 -0500 (Wed, 28 Mar 2012) $
47   */
48  public class FaceletCompositionContextImpl extends FaceletCompositionContext
49  {
50      /**
51       * Indicates if expressions generated by facelets should be cached or not.
52       * Default is noCache. There there are four modes:
53       * 
54       * <ul>
55       * <li>always: Only does not cache when expressions are inside user tags or the e
56       * xpression contains a variable resolved using VariableMapper</li>
57       * <li>allowCset: Like always, but does not allow cache when ui:param
58       * was used on the current template context</li>
59       * <li>strict: Like allowCset, but does not allow cache when c:set with
60       * var and value properties only is used on the current page context</li>
61       * <li>noCache: All expression are created each time the view is built</li>
62       * </ul>
63       * 
64       */
65      @JSFWebConfigParam(since="2.0.8", defaultValue="noCache", expectedValues="noCache, strict, allowCset, always",
66                         group="EL", tags="performance")
67      public static final String INIT_PARAM_CACHE_EL_EXPRESSIONS = "org.apache.myfaces.CACHE_EL_EXPRESSIONS";
68      
69      /**
70       * Wrap exception caused by calls to EL expressions, so information like
71       * the location, expression string and tag name can be retrieved by
72       * the ExceptionHandler implementation and used to output meaningful information about itself.
73       * 
74       * <p>Note in some cases this will wrap the original javax.el.ELException,
75       * so the information will not be on the stack trace unless ExceptionHandler
76       * retrieve checking if the exception implements ContextAware interface and calling getWrapped() method.
77       * </p>
78       * 
79       */
80      @JSFWebConfigParam(since="2.0.9, 2.1.3" , defaultValue="true", expectedValues="true, false")
81      public static final String INIT_PARAM_WRAP_TAG_EXCEPTIONS_AS_CONTEXT_AWARE
82              = "org.apache.myfaces.WRAP_TAG_EXCEPTIONS_AS_CONTEXT_AWARE";
83      
84      private FacesContext _facesContext;
85      
86      private FaceletFactory _factory;
87  
88      private LinkedList<UIComponent> _compositeComponentStack;
89      
90      private LinkedList<UniqueIdVendor> _uniqueIdVendorStack;
91      
92      private LinkedList<String> _validationGroupsStack; 
93      
94      private LinkedList<String> _excludedValidatorIdsStack;
95      
96      private LinkedList<Map.Entry<String, EditableValueHolderAttachedObjectHandler>> _enclosingValidatorIdsStack;
97      
98      private Boolean _isRefreshingTransientBuild;
99      
100     private Boolean _isMarkInitialState;
101     
102     private Boolean _isBuildingViewMetadata;
103     
104     private Boolean _refreshTransientBuildOnPSS;
105     
106     private Boolean _refreshTransientBuildOnPSSPreserveState;
107     
108     private Boolean _usingPSSOnThisView;
109     
110     private ELExpressionCacheMode _elExpressionCacheMode;
111     
112     private Boolean _isWrapTagExceptionsAsContextAware;
113 
114     private List<Map<String, UIComponent>> _componentsMarkedForDeletion;
115     
116     private int _deletionLevel;
117     
118     private Map<UIComponent, List<AttachedObjectHandler>> _attachedObjectHandlers;
119     
120     private Map<UIComponent, Map<String, Object> > _methodExpressionsTargeted;
121     
122     private Map<UIComponent, Map<String, Boolean> > _compositeComponentAttributesMarked;
123 
124     private static final String VIEWROOT_FACELET_ID = "oam.VIEW_ROOT";
125     
126     private SectionUniqueIdCounter _sectionUniqueIdCounter;
127     
128     private SectionUniqueIdCounter _sectionUniqueComponentIdCounter;
129     
130     private List<String> _uniqueIdsList;
131     private Iterator<String> _uniqueIdsIterator;
132     private int _level;
133     
134     private int _isInMetadataSection;
135     private SectionUniqueIdCounter _sectionUniqueMetadataIdCounter;
136     private SectionUniqueIdCounter _sectionUniqueNormalIdCounter;
137     private SectionUniqueIdCounter _sectionUniqueComponentMetadataIdCounter;
138     private SectionUniqueIdCounter _sectionUniqueComponentNormalIdCounter;
139     
140     private StringBuilder _sharedStringBuilder;
141     
142     public FaceletCompositionContextImpl(FaceletFactory factory, FacesContext facesContext)
143     {
144         super();
145         _factory = factory;
146         _facesContext = facesContext;
147         _componentsMarkedForDeletion = new ArrayList<Map<String,UIComponent>>();
148         _deletionLevel = -1;
149         _sectionUniqueIdCounter = new SectionUniqueIdCounter();
150         //Cached at facelet view
151         MyfacesConfig myfacesConfig = MyfacesConfig.getCurrentInstance(
152                 facesContext.getExternalContext());
153         if (myfacesConfig.getComponentUniqueIdsCacheSize() > 0)
154         {
155             String[] componentIdsCache = (String [])facesContext.getExternalContext().
156                     getApplicationMap().get(FaceletViewDeclarationLanguage.CACHED_COMPONENT_IDS);
157             if (componentIdsCache != null)
158             {
159                 _sectionUniqueComponentIdCounter = new SectionUniqueIdCounter("_", 
160                         componentIdsCache);
161             }
162             else
163             {
164                 _sectionUniqueComponentIdCounter = new SectionUniqueIdCounter("_");
165             }
166         }
167         else
168         {
169             _sectionUniqueComponentIdCounter = new SectionUniqueIdCounter("_");
170         }
171         _sectionUniqueNormalIdCounter = _sectionUniqueIdCounter;
172         _sectionUniqueComponentNormalIdCounter = _sectionUniqueComponentIdCounter;
173         _uniqueIdsList = null;
174         _uniqueIdsIterator = null;
175         _level = 0;
176         _isInMetadataSection = 0;
177         _sharedStringBuilder = null;
178     }
179     
180     @Override
181     public void setUniqueIdsIterator(Iterator<String> uniqueIdsIterator)
182     {
183         _uniqueIdsList = null;
184         _uniqueIdsIterator = uniqueIdsIterator;
185     }
186     
187     @Override
188     public void initUniqueIdRecording()
189     {
190         _uniqueIdsList = new LinkedList<String>();
191         _uniqueIdsIterator = null;
192     }
193     
194     @Override
195     public void addUniqueId(String uniqueId)
196     {
197         if (_uniqueIdsList != null && _level == 0 && !(_isInMetadataSection > 0))
198         {
199             _uniqueIdsList.add(uniqueId);
200         }
201     }
202     
203     @Override
204     public String getUniqueIdFromIterator()
205     {
206         if (_uniqueIdsIterator != null && _uniqueIdsIterator.hasNext() && 
207                 _level == 0 && !(_isInMetadataSection > 0))
208         {
209             return _uniqueIdsIterator.next();
210         }
211         return null;
212     }
213     
214     @Override
215     public List<String> getUniqueIdList()
216     {
217         return _uniqueIdsList;
218     }
219 
220     public FaceletFactory getFaceletFactory()
221     {
222         return _factory;
223     }
224     
225     @Override
226     public void release(FacesContext facesContext)
227     {
228         super.release(facesContext);
229         _factory = null;
230         _facesContext = null;
231         _compositeComponentStack = null;
232         _enclosingValidatorIdsStack = null;
233         _excludedValidatorIdsStack = null;
234         _uniqueIdVendorStack = null;
235         _validationGroupsStack = null;
236         _componentsMarkedForDeletion = null;
237         _sectionUniqueIdCounter = null;
238         _sectionUniqueNormalIdCounter = null;
239         _sectionUniqueMetadataIdCounter = null;
240         _sectionUniqueComponentIdCounter = null;
241         _sectionUniqueComponentNormalIdCounter = null;
242         _sectionUniqueComponentMetadataIdCounter = null;
243         _sharedStringBuilder = null;
244     }
245    
246     @Override
247     public UIComponent getCompositeComponentFromStack()
248     {
249         if (_compositeComponentStack != null && !_compositeComponentStack.isEmpty())
250         {
251             return _compositeComponentStack.peek();
252         }
253         return null;
254     }
255 
256     @Override
257     public void pushCompositeComponentToStack(UIComponent parent)
258     {
259         if (_compositeComponentStack == null)
260         {
261             _compositeComponentStack = new LinkedList<UIComponent>();
262         }
263         _compositeComponentStack.addFirst(parent);
264     }
265 
266     @Override
267     public void popCompositeComponentToStack()
268     {
269         if (_compositeComponentStack != null && !_compositeComponentStack.isEmpty())
270         {
271             _compositeComponentStack.removeFirst();
272         }
273     }
274 
275     @Override
276     public UniqueIdVendor getUniqueIdVendorFromStack()
277     {
278         if (_uniqueIdVendorStack != null && !_uniqueIdVendorStack.isEmpty())
279         {
280             return _uniqueIdVendorStack.peek();
281         }
282         return null;
283     }
284 
285     @Override
286     public void popUniqueIdVendorToStack()
287     {
288         if (_uniqueIdVendorStack != null && !_uniqueIdVendorStack.isEmpty())
289         {
290             _uniqueIdVendorStack.removeFirst();
291         }
292     }
293 
294     @Override
295     public void pushUniqueIdVendorToStack(UniqueIdVendor parent)
296     {
297         if (_uniqueIdVendorStack == null)
298         {
299             _uniqueIdVendorStack = new LinkedList<UniqueIdVendor>();
300         }
301         _uniqueIdVendorStack.addFirst(parent);
302     }
303     
304     /**
305      * Gets the top of the validationGroups stack.
306      * @return
307      * @since 2.0
308      */
309     @Override
310     public String getFirstValidationGroupFromStack()
311     {
312         if (_validationGroupsStack != null && !_validationGroupsStack.isEmpty())
313         {
314             return _validationGroupsStack.getFirst(); // top-of-stack
315         }
316         return null;
317     }
318     
319     /**
320      * Removes top of stack.
321      * @since 2.0
322      */
323     @Override
324     public void popValidationGroupsToStack()
325     {
326         if (_validationGroupsStack != null && !_validationGroupsStack.isEmpty())
327         {
328             _validationGroupsStack.removeFirst();
329         }
330     }
331     
332     /**
333      * Pushes validationGroups to the stack.
334      * @param validationGroups
335      * @since 2.0
336      */
337     @Override
338     public void pushValidationGroupsToStack(String validationGroups)
339     {
340         if (_validationGroupsStack == null)
341         {
342             _validationGroupsStack = new LinkedList<String>();
343         }
344 
345         _validationGroupsStack.addFirst(validationGroups);
346     }
347     
348     /**
349      * Gets all validationIds on the stack.
350      * @return
351      * @since 2.0
352      */
353     @Override
354     public Iterator<String> getExcludedValidatorIds()
355     {
356         if (_excludedValidatorIdsStack != null && !_excludedValidatorIdsStack.isEmpty())
357         {
358             return _excludedValidatorIdsStack.iterator();
359         }
360         return null;
361     }
362     
363     /**
364      * Removes top of stack.
365      * @since 2.0
366      */
367     @Override
368     public void popExcludedValidatorIdToStack()
369     {
370         if (_excludedValidatorIdsStack != null && !_excludedValidatorIdsStack.isEmpty())
371         {
372             _excludedValidatorIdsStack.removeFirst();
373         }
374     }
375     
376     /**
377      * Pushes validatorId to the stack of excluded validatorIds.
378      * @param validatorId
379      * @since 2.0
380      */
381     @Override
382     public void pushExcludedValidatorIdToStack(String validatorId)
383     {
384         if (_excludedValidatorIdsStack == null)
385         {
386             _excludedValidatorIdsStack = new LinkedList<String>();
387         }
388 
389         _excludedValidatorIdsStack.addFirst(validatorId);
390     }
391     
392     /**
393      * Gets all validationIds on the stack.
394      * @return
395      * @since 2.0
396      */
397     @Override
398     public Iterator<String> getEnclosingValidatorIds()
399     {
400         if (_enclosingValidatorIdsStack != null && !_enclosingValidatorIdsStack.isEmpty())
401         {
402             return new KeyEntryIterator<String, EditableValueHolderAttachedObjectHandler>
403                 (_enclosingValidatorIdsStack.iterator()); 
404         }
405         return null;
406     }
407     
408     /**
409      * Removes top of stack.
410      * @since 2.0
411      */
412     @Override
413     public void popEnclosingValidatorIdToStack()
414     {
415         if (_enclosingValidatorIdsStack != null && !_enclosingValidatorIdsStack.isEmpty())
416         {
417             _enclosingValidatorIdsStack.removeFirst();
418         }
419     }
420     
421     /**
422      * Pushes validatorId to the stack of all enclosing validatorIds.
423      * @param validatorId
424      * @since 2.0
425      */
426     @Override
427     public void pushEnclosingValidatorIdToStack(String validatorId)
428     {
429         pushEnclosingValidatorIdToStack(validatorId, null);
430     }
431     
432     @Override
433     public void pushEnclosingValidatorIdToStack(String validatorId, 
434             EditableValueHolderAttachedObjectHandler attachedObjectHandler)
435     {
436         if (_enclosingValidatorIdsStack == null)
437         {
438             _enclosingValidatorIdsStack = 
439                 new LinkedList<Map.Entry<String, EditableValueHolderAttachedObjectHandler>>();
440         }
441 
442         _enclosingValidatorIdsStack.addFirst(
443                 new SimpleEntry<String, EditableValueHolderAttachedObjectHandler>
444                     (validatorId, attachedObjectHandler));
445     }
446 
447     public Iterator<Map.Entry<String, EditableValueHolderAttachedObjectHandler>> getEnclosingValidatorIdsAndHandlers()
448     {
449         if (_enclosingValidatorIdsStack != null && !_enclosingValidatorIdsStack.isEmpty())
450         {
451             return _enclosingValidatorIdsStack.iterator(); 
452         }
453         return null;
454     }
455     
456     public boolean containsEnclosingValidatorId(String id)
457     {
458         if (_enclosingValidatorIdsStack != null && !_enclosingValidatorIdsStack.isEmpty())
459         {
460             for (Map.Entry<String, EditableValueHolderAttachedObjectHandler> entry : _enclosingValidatorIdsStack)
461             {
462                 if (entry.getKey().equals(id))
463                 {
464                     return true;
465                 }
466             }
467         }
468         return false;
469     }
470 
471     @Override
472     public boolean isRefreshingTransientBuild()
473     {
474         if (_isRefreshingTransientBuild == null)
475         {
476             _isRefreshingTransientBuild = FaceletViewDeclarationLanguage.
477                 isRefreshingTransientBuild(_facesContext);
478         }
479         return _isRefreshingTransientBuild;
480     }
481 
482     @Override
483     public boolean isMarkInitialState()
484     {
485         if (_isMarkInitialState == null)
486         {
487             _isMarkInitialState = FaceletViewDeclarationLanguage.
488                 isMarkInitialState(_facesContext);
489         }
490         return _isMarkInitialState;
491     }
492 
493     @Override
494     public void setMarkInitialState(boolean value)
495     {
496         _isMarkInitialState = value;
497     }
498 
499     @Override
500     public boolean isRefreshTransientBuildOnPSS()
501     {
502         if (_refreshTransientBuildOnPSS == null)
503         {
504             _refreshTransientBuildOnPSS = FaceletViewDeclarationLanguage.
505                 isRefreshTransientBuildOnPSS(_facesContext);
506         }
507         return _refreshTransientBuildOnPSS;
508     }
509     
510     public boolean isRefreshTransientBuildOnPSSPreserveState()
511     {
512         if (_refreshTransientBuildOnPSSPreserveState == null)
513         {
514             _refreshTransientBuildOnPSSPreserveState = MyfacesConfig.getCurrentInstance(
515                     _facesContext.getExternalContext()).isRefreshTransientBuildOnPSSPreserveState();
516         }
517         return _refreshTransientBuildOnPSSPreserveState;
518     }
519     
520     @Override
521     public boolean isBuildingViewMetadata()
522     {
523         if (_isBuildingViewMetadata == null)
524         {
525             _isBuildingViewMetadata = FaceletViewDeclarationLanguage.
526                     isBuildingViewMetadata(_facesContext);
527         }
528         return _isBuildingViewMetadata;
529     }
530 
531     @Override
532     public boolean isUsingPSSOnThisView()
533     {
534         if (_usingPSSOnThisView == null)
535         {
536             _usingPSSOnThisView = FaceletViewDeclarationLanguage.
537                 isUsingPSSOnThisView(_facesContext);
538         }
539         return _usingPSSOnThisView;
540     }
541     
542     public boolean isMarkInitialStateAndIsRefreshTransientBuildOnPSS()
543     {
544         return isMarkInitialState() && isRefreshTransientBuildOnPSS();
545     }
546 
547     @Override
548     public ELExpressionCacheMode getELExpressionCacheMode()
549     {
550         if (_elExpressionCacheMode == null)
551         {
552             String value = WebConfigParamUtils.getStringInitParameter(
553                     _facesContext.getExternalContext(),
554                     INIT_PARAM_CACHE_EL_EXPRESSIONS, ELExpressionCacheMode.noCache.name());
555             
556             _elExpressionCacheMode = Enum.valueOf(ELExpressionCacheMode.class, value); 
557         }
558         return _elExpressionCacheMode;
559     }
560 
561     @Override
562     public boolean isWrapTagExceptionsAsContextAware()
563     {
564         if (_isWrapTagExceptionsAsContextAware == null)
565         {
566             _isWrapTagExceptionsAsContextAware
567                     = WebConfigParamUtils.getBooleanInitParameter(_facesContext.getExternalContext(),
568                     INIT_PARAM_WRAP_TAG_EXCEPTIONS_AS_CONTEXT_AWARE, true);
569         }
570         return _isWrapTagExceptionsAsContextAware;
571     }
572 
573     @Override
574     public void addAttachedObjectHandler(UIComponent compositeComponentParent, AttachedObjectHandler handler)
575     {
576         List<AttachedObjectHandler> list = null;
577         if (_attachedObjectHandlers == null)
578         {
579             _attachedObjectHandlers = new HashMap<UIComponent, List<AttachedObjectHandler>>();
580         }
581         else
582         {
583             list = _attachedObjectHandlers.get(compositeComponentParent);
584         }
585 
586         if (list == null)
587         {
588             list = new ArrayList<AttachedObjectHandler>();
589             _attachedObjectHandlers.put(compositeComponentParent, list);
590         }
591 
592         list.add(handler);
593     }
594 
595     @Override
596     public void removeAttachedObjectHandlers(UIComponent compositeComponentParent)
597     {
598         if (_attachedObjectHandlers == null)
599         {
600             return;
601         }
602         _attachedObjectHandlers.remove(compositeComponentParent);
603     }
604 
605     @Override
606     public List<AttachedObjectHandler> getAttachedObjectHandlers(UIComponent compositeComponentParent)
607     {
608         if (_attachedObjectHandlers == null)
609         {
610             return null;
611         }
612         return _attachedObjectHandlers.get(compositeComponentParent);
613     }
614     
615     @Override
616     public void addMethodExpressionTargeted(UIComponent targetedComponent, String attributeName, Object backingValue)
617     {
618         Map<String, Object> map = null;
619         if (_methodExpressionsTargeted == null)
620         {
621             _methodExpressionsTargeted = new HashMap<UIComponent, Map<String, Object>>();
622         }
623         else
624         {
625             map = _methodExpressionsTargeted.get(targetedComponent);
626         }
627 
628         if (map == null)
629         {
630             map = new HashMap<String, Object>(8);
631             _methodExpressionsTargeted.put(targetedComponent, map);
632         }
633 
634         map.put(attributeName, backingValue);
635     }
636 
637     public boolean isMethodExpressionAttributeApplied(UIComponent compositeComponentParent, String attributeName)
638     {
639         if (_compositeComponentAttributesMarked == null)
640         {
641             return false;
642         }
643         Map<String, Boolean> map = _compositeComponentAttributesMarked.get(compositeComponentParent);
644         if (map == null)
645         {
646             return false;
647         }
648         Boolean v = map.get(attributeName);
649         return v == null ? false : v.booleanValue();
650     }
651     
652     public void markMethodExpressionAttribute(UIComponent compositeComponentParent, String attributeName)
653     {
654         Map<String, Boolean> map = null;
655         if (_compositeComponentAttributesMarked == null)
656         {
657             _compositeComponentAttributesMarked = new HashMap<UIComponent, Map<String, Boolean>>(); 
658         }
659         else
660         {
661             map = _compositeComponentAttributesMarked.get(compositeComponentParent);
662         }
663         
664         if (map == null)
665         {
666             map = new HashMap<String, Boolean>(8);
667             _compositeComponentAttributesMarked.put(compositeComponentParent, map);
668         }
669         map.put(attributeName, Boolean.TRUE);
670         
671     }
672     
673     public void clearMethodExpressionAttribute(UIComponent compositeComponentParent, String attributeName)
674     {
675         if (_compositeComponentAttributesMarked == null)
676         {
677             return;
678         }
679         Map<String, Boolean> map = _compositeComponentAttributesMarked.get(compositeComponentParent);
680         if (map == null)
681         {
682             //No map, so just return
683             return;
684         }
685         map.put(attributeName, Boolean.FALSE);
686     }
687     
688     
689     @Override
690     public Object removeMethodExpressionTargeted(UIComponent targetedComponent, String attributeName)
691     {
692         if (_methodExpressionsTargeted == null)
693         {
694             return null;
695         }
696         Map<String, Object> map = _methodExpressionsTargeted.get(targetedComponent);
697         if (map != null)
698         {
699             return map.remove(attributeName);
700         }
701         return null;
702     }
703 
704     /**
705      * Add a level of components marked for deletion.
706      */
707     private void increaseComponentLevelMarkedForDeletion()
708     {
709         _deletionLevel++;
710         if (_componentsMarkedForDeletion.size() <= _deletionLevel)
711         {
712             _componentsMarkedForDeletion.add(new HashMap<String, UIComponent>());
713             
714         }
715     }
716 
717     /**
718      * Remove the last component level from the components marked to be deleted. The components are removed
719      * from this list because they are deleted from the tree. This is done in ComponentSupport.finalizeForDeletion.
720      *
721      * @return the array of components that are removed.
722      */
723     private void decreaseComponentLevelMarkedForDeletion()
724     {
725         //The common case is this co
726         if (!_componentsMarkedForDeletion.get(_deletionLevel).isEmpty())
727         {
728             _componentsMarkedForDeletion.get(_deletionLevel).clear();
729         }
730         _deletionLevel--;
731     }
732 
733     /** Mark a component to be deleted from the tree. The component to be deleted is addded on the
734      * current level. This is done from ComponentSupport.markForDeletion
735      *
736      * @param id
737      * @param component the component marked for deletion.
738      */
739     private void markComponentForDeletion(String id , UIComponent component)
740     {
741         _componentsMarkedForDeletion.get(_deletionLevel).put(id, component);
742     }
743 
744     /**
745      * Remove a component from the last level of components marked to be deleted.
746      *
747      * @param id
748      */
749     private UIComponent removeComponentForDeletion(String id)
750     {
751         UIComponent removedComponent = _componentsMarkedForDeletion.get(_deletionLevel).remove(id); 
752         if (removedComponent != null && _deletionLevel > 0)
753         {
754             _componentsMarkedForDeletion.get(_deletionLevel-1).remove(id);
755         }
756         return removedComponent;
757     }
758     
759     public void markForDeletion(UIComponent component)
760     {
761         increaseComponentLevelMarkedForDeletion();
762         
763         String id = (String) component.getAttributes().get(ComponentSupport.MARK_CREATED);
764         id = (id == null) ? VIEWROOT_FACELET_ID : id;
765         markComponentForDeletion(id, component);
766         
767         
768         if (component.getFacetCount() > 0)
769         {
770             for (UIComponent fc: component.getFacets().values())
771             {
772                 id = (String) fc.getAttributes().get(ComponentSupport.MARK_CREATED);
773                 if (id != null)
774                 {
775                     markComponentForDeletion(id, fc);
776                 }
777                 else if (Boolean.TRUE.equals(fc.getAttributes().get(ComponentSupport.FACET_CREATED_UIPANEL_MARKER)))
778                 {
779                     //Mark its children, but do not mark itself.
780                     int childCount = fc.getChildCount();
781                     if (childCount > 0)
782                     {
783                         for (int i = 0; i < childCount; i++)
784                         {
785                             UIComponent child = fc.getChildren().get(i);
786                             id = (String) child.getAttributes().get(ComponentSupport.MARK_CREATED);
787                             if (id != null)
788                             {
789                                 markComponentForDeletion(id, child);
790                             }
791                         }
792                     }
793                 }
794             }
795         }
796                 
797         int childCount = component.getChildCount();
798         if (childCount > 0)
799         {
800             for (int i = 0; i < childCount; i++)
801             {
802                 UIComponent child = component.getChildren().get(i);
803                 id = (String) child.getAttributes().get(ComponentSupport.MARK_CREATED);
804                 if (id != null)
805                 {
806                     markComponentForDeletion(id, child);
807                 }
808             }
809         }
810     }
811     
812     public void finalizeForDeletion(UIComponent component)
813     {
814         String id = (String) component.getAttributes().get(ComponentSupport.MARK_CREATED);
815         id = (id == null) ? VIEWROOT_FACELET_ID : id;
816         // remove any existing marks of deletion
817         removeComponentForDeletion(id);
818         
819         // finally remove any children marked as deleted
820         int childCount = component.getChildCount();
821         if (childCount > 0)
822         {
823             for (int i = 0; i < childCount; i ++)
824             {
825                 UIComponent child = component.getChildren().get(i);
826                 id = (String) child.getAttributes().get(ComponentSupport.MARK_CREATED); 
827                 if (id != null && removeComponentForDeletion(id) != null)
828                 {
829                     component.getChildren().remove(i);
830                     i--;
831                     childCount--;
832                 }
833             }
834         }
835 
836         // remove any facets marked as deleted
837         
838         if (component.getFacetCount() > 0)
839         {
840             Map<String, UIComponent> facets = component.getFacets();
841             for (Iterator<UIComponent> itr = facets.values().iterator(); itr.hasNext();)
842             {
843                 UIComponent fc = itr.next();
844                 id = (String) fc.getAttributes().get(ComponentSupport.MARK_CREATED);
845                 if (id != null && removeComponentForDeletion(id) != null)
846                 {
847                     itr.remove();
848                 }
849                 else if (id == null
850                          && Boolean.TRUE.equals(fc.getAttributes().get(ComponentSupport.FACET_CREATED_UIPANEL_MARKER)))
851                 {
852                     if (fc.getChildCount() > 0)
853                     {
854                         for (int i = 0, size = fc.getChildCount(); i < size; i++)
855                         {
856                             UIComponent child = fc.getChildren().get(i);
857                             id = (String) child.getAttributes().get(ComponentSupport.MARK_CREATED);
858                             if (id != null && removeComponentForDeletion(id) != null)
859                             {
860                                 fc.getChildren().remove(i);
861                                 i--;
862                                 size--;
863                             }
864                         }
865                     }
866                     if (fc.getChildCount() == 0)
867                     {
868                         itr.remove();
869                     }
870                 }
871             }
872         }
873         
874         decreaseComponentLevelMarkedForDeletion();
875     }
876     
877     public String startComponentUniqueIdSection()
878     {
879         _level++;
880         _sectionUniqueComponentIdCounter.startUniqueIdSection();
881         return _sectionUniqueIdCounter.startUniqueIdSection();
882     }
883 
884     @Override
885     public void incrementUniqueId()
886     {
887         _sectionUniqueIdCounter.incrementUniqueId();
888     }
889     
890     public String generateUniqueId()
891     {
892         return _sectionUniqueIdCounter.generateUniqueId();
893     }
894     
895     public void generateUniqueId(StringBuilder builderToAdd)
896     {
897         _sectionUniqueIdCounter.generateUniqueId(builderToAdd);
898     }
899 
900     public String generateUniqueComponentId()
901     {
902         return _sectionUniqueComponentIdCounter.generateUniqueId();
903     }
904     
905     public void endComponentUniqueIdSection()
906     {
907         _level--;
908         _sectionUniqueIdCounter.endUniqueIdSection();
909         _sectionUniqueComponentIdCounter.endUniqueIdSection();
910     }
911     
912     @Override
913     public void startMetadataSection()
914     {
915         if (_isInMetadataSection == 0)
916         {
917             if (_sectionUniqueMetadataIdCounter == null)
918             {
919                 _sectionUniqueMetadataIdCounter = new SectionUniqueIdCounter("__md_");
920             }
921             if (_sectionUniqueComponentMetadataIdCounter == null)
922             {
923                 _sectionUniqueComponentMetadataIdCounter = new SectionUniqueIdCounter("__md_");
924             }
925             //Replace the counter with metadata counter
926             _sectionUniqueIdCounter = _sectionUniqueMetadataIdCounter;
927             _sectionUniqueComponentIdCounter = _sectionUniqueComponentMetadataIdCounter;
928         }
929         _isInMetadataSection++;
930     }
931     
932     @Override
933     public void endMetadataSection()
934     {
935         _isInMetadataSection--;
936         if (_isInMetadataSection == 0)
937         {
938             //Use normal id counter again
939             _sectionUniqueIdCounter = _sectionUniqueNormalIdCounter;
940             _sectionUniqueComponentIdCounter = _sectionUniqueComponentNormalIdCounter;
941         }
942     }
943     
944     @Override
945     public boolean isInMetadataSection()
946     {
947        return _isInMetadataSection > 0;
948     }
949     
950     @Override
951     public boolean isRefreshingSection()
952     {
953        return isRefreshingTransientBuild() ||  (!isBuildingViewMetadata() && isInMetadataSection());
954     }
955     
956     @Override
957     public StringBuilder getSharedStringBuilder()
958     {
959         if (_sharedStringBuilder == null)
960         {
961             _sharedStringBuilder = new StringBuilder();
962         }
963         else
964         {
965             _sharedStringBuilder.setLength(0);
966         }
967         return _sharedStringBuilder;
968     }
969     
970     private static class KeyEntryIterator<K, V> implements Iterator<K>
971     {
972         private Iterator<Map.Entry<K, V>> _delegateIterator;
973         
974         public KeyEntryIterator(Iterator<Map.Entry<K, V>> delegate)
975         {
976             _delegateIterator = delegate;
977         }
978         
979         public boolean hasNext()
980         {
981             if (_delegateIterator != null)
982             {
983                 return _delegateIterator.hasNext();
984             }
985             return false;
986         }
987 
988         public K next()
989         {
990             if (_delegateIterator != null)
991             {
992                 return _delegateIterator.next().getKey();
993             }
994             return null;
995         }
996 
997         public void remove()
998         {
999             if (_delegateIterator != null)
1000             {
1001                 _delegateIterator.remove();
1002             }
1003         }
1004         
1005     }
1006     
1007     private static class SimpleEntry<K, V> implements Map.Entry<K, V>
1008     {
1009         private final K _key;
1010         private final V _value;
1011 
1012         public SimpleEntry(K key, V value)
1013         {
1014             _key = key;
1015             _value = value;
1016         }
1017         
1018         public K getKey()
1019         {
1020             return _key;
1021         }
1022 
1023         public V getValue()
1024         {
1025             return _value;
1026         }
1027 
1028         @Override
1029         public int hashCode()
1030         {
1031             final int prime = 31;
1032             int result = 1;
1033             result = prime * result + ((_key == null) ? 0 : _key.hashCode());
1034             result = prime * result + ((_value == null) ? 0 : _value.hashCode());
1035             return result;
1036         }
1037 
1038         @SuppressWarnings("unchecked")
1039         @Override
1040         public boolean equals(Object obj)
1041         {
1042             if (this == obj)
1043             {
1044                 return true;
1045             }
1046             if (obj == null)
1047             {
1048                 return false;
1049             }
1050             if (getClass() != obj.getClass())
1051             {
1052                 return false;
1053             }
1054             SimpleEntry other = (SimpleEntry) obj;
1055             if (_key == null)
1056             {
1057                 if (other._key != null)
1058                 {
1059                     return false;
1060                 }
1061             }
1062             else if (!_key.equals(other._key))
1063             {
1064                 return false;
1065             }
1066             
1067             if (_value == null)
1068             {
1069                 if (other._value != null)
1070                 {
1071                     return false;
1072                 }
1073             }
1074             else if (!_value.equals(other._value))
1075             {
1076                 return false;
1077             }
1078             return true;
1079         }
1080 
1081         public V setValue(V value)
1082         {
1083             throw new UnsupportedOperationException();
1084         }
1085     }
1086 }