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