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