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