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