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 javax.faces.component;
20  
21  import java.io.IOException;
22  import java.lang.reflect.Method;
23  import java.util.ArrayList;
24  import java.util.Arrays;
25  import java.util.Collection;
26  import java.util.Collections;
27  import java.util.HashMap;
28  import java.util.Iterator;
29  import java.util.LinkedList;
30  import java.util.List;
31  import java.util.Locale;
32  import java.util.Map;
33  import java.util.logging.Level;
34  import java.util.logging.Logger;
35  
36  import javax.el.MethodExpression;
37  import javax.el.ValueExpression;
38  import javax.faces.FactoryFinder;
39  import javax.faces.application.ProjectStage;
40  import javax.faces.application.StateManager;
41  import javax.faces.component.visit.VisitCallback;
42  import javax.faces.component.visit.VisitContext;
43  import javax.faces.component.visit.VisitResult;
44  import javax.faces.context.ExternalContext;
45  import javax.faces.context.FacesContext;
46  import javax.faces.context.PartialViewContext;
47  import javax.faces.event.AbortProcessingException;
48  import javax.faces.event.ExceptionQueuedEvent;
49  import javax.faces.event.ExceptionQueuedEventContext;
50  import javax.faces.event.FacesEvent;
51  import javax.faces.event.PhaseEvent;
52  import javax.faces.event.PhaseId;
53  import javax.faces.event.PhaseListener;
54  import javax.faces.event.PostConstructViewMapEvent;
55  import javax.faces.event.PreDestroyViewMapEvent;
56  import javax.faces.event.SystemEvent;
57  import javax.faces.event.SystemEventListener;
58  import javax.faces.lifecycle.Lifecycle;
59  import javax.faces.lifecycle.LifecycleFactory;
60  import javax.faces.view.ViewDeclarationLanguage;
61  import javax.faces.view.ViewMetadata;
62  import javax.faces.webapp.FacesServlet;
63  
64  import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFComponent;
65  import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFJspProperty;
66  import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFProperty;
67  import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFWebConfigParam;
68  
69  /**
70   * Creates a JSF View, which is a container that holds all of the components that are part of the view.
71   * <p>
72   * Unless otherwise specified, all attributes accept static values or EL expressions.
73   * </p>
74   * <p>
75   * See the javadoc for this class in the <a href="http://java.sun.com/j2ee/javaserverfaces/1.2/docs/api/index.html">JSF
76   * Specification</a> for further details.
77   * </p>
78   */
79  @JSFComponent(name = "f:view", bodyContent = "JSP", tagClass = "org.apache.myfaces.taglib.core.ViewTag")
80  @JSFJspProperty(name = "binding", returnType = "java.lang.String", tagExcluded = true)
81  public class UIViewRoot extends UIComponentBase implements UniqueIdVendor
82  {
83      public static final String COMPONENT_FAMILY = "javax.faces.ViewRoot";
84      public static final String COMPONENT_TYPE = "javax.faces.ViewRoot";
85      public static final String METADATA_FACET_NAME = "javax_faces_metadata";
86      public static final String UNIQUE_ID_PREFIX = "j_id";
87      public static final String VIEW_PARAMETERS_KEY = "javax.faces.component.VIEW_PARAMETERS_KEY";
88      
89      /**
90       * @since 2.3
91       */
92      @JSFWebConfigParam(defaultValue="false", expectedValues="true, false", since="2.3")
93      public static final String VIEWROOT_PHASE_LISTENER_QUEUES_EXCEPTIONS_PARAM_NAME
94              = "javax.faces.VIEWROOT_PHASE_LISTENER_QUEUES_EXCEPTIONS";
95  
96      private transient Logger logger = null;
97  
98      private static final PhaseProcessor APPLY_REQUEST_VALUES_PROCESSOR = new ApplyRequestValuesPhaseProcessor();
99      private static final PhaseProcessor PROCESS_VALIDATORS_PROCESSOR = new ProcessValidatorPhaseProcessor();
100     private static final PhaseProcessor UPDATE_MODEL_PROCESSOR = new UpdateModelPhaseProcessor();
101 
102     private static final VisitCallback RESET_VALUES_CALLBACK = new ResetValuesCallback();
103     
104     /**
105      * Class that is used to create the view scope map. This strategy
106      * allows change the implementation of view scope map to use cdi or
107      * whatever without change UIViewRoot implementation.
108      */
109     private static Class<?> VIEW_SCOPE_PROXY_MAP_CLASS = null;
110     
111     private static Class<?> REQUEST_VIEW_CONTEXT_CLASS = null;
112     private static Method REQUEST_VIEW_CONTEXT_GET_INSTANCE = null;
113     private static Method REQUEST_VIEW_CONTEXT_SET_RENDER_TARGET = null;
114 
115     static
116     {
117         try
118         {
119             VIEW_SCOPE_PROXY_MAP_CLASS
120                     = _ClassUtils.classForName("org.apache.myfaces.view.ViewScopeProxyMap");
121         }
122         catch (Exception e)
123         {
124             // no op
125         }
126         
127         try
128         {
129             REQUEST_VIEW_CONTEXT_CLASS
130                     = _ClassUtils.classForName("org.apache.myfaces.context.RequestViewContext");
131             REQUEST_VIEW_CONTEXT_GET_INSTANCE = REQUEST_VIEW_CONTEXT_CLASS.getMethod("getCurrentInstance",
132                     new Class[] { FacesContext.class });
133             REQUEST_VIEW_CONTEXT_SET_RENDER_TARGET = REQUEST_VIEW_CONTEXT_CLASS.getMethod("setRenderTarget",
134                     new Class[] { String.class, boolean.class, UIComponent.class });
135         }
136         catch (Exception e)
137         {
138             // no op
139         }
140     }
141 
142     /**
143      * The counter which will ensure a unique component id for every component instance in the tree that doesn't have an
144      * id attribute set.
145      */
146     //private long _uniqueIdCounter = 0;
147 
148     // todo: is it right to save the state of _events and _phaseListeners?
149     private List<FacesEvent> _events;
150 
151     /**
152      * Map containing view scope objects. 
153      * 
154      * It is not expected this map hold PartialStateHolder instances,
155      * so we can use saveAttachedState and restoreAttachedState methods.
156      */
157     private Map<String, Object> _viewScope;
158     private transient boolean _restoreViewScopeStateCalled = false;
159 
160     private transient Lifecycle _lifecycle = null;
161     
162     private HashMap<Class<? extends SystemEvent>, List<SystemEventListener>> _systemEventListeners;
163     
164     // Tracks success in the beforePhase. Listeners that threw an exception
165     // in beforePhase or were never called, because a previous listener threw
166     // an exception, should not have their afterPhase method called
167     private transient Map<PhaseId, boolean[]> listenerSuccessMap;
168     
169     private static final String JAVAX_FACES_LOCATION_PREFIX = "javax_faces_location_";
170     private static final String JAVAX_FACES_LOCATION_HEAD = "javax_faces_location_head";
171     private static final String JAVAX_FACES_LOCATION_BODY = "javax_faces_location_body";
172     private static final String JAVAX_FACES_LOCATION_FORM = "javax_faces_location_form";
173     
174     private static final String SKIP_VIEW_MAP_SAVE_STATE = "oam.viewPool.SKIP_VIEW_MAP_SAVE_STATE";
175     
176     private transient int _resetSaveStateMode = 0;
177     private transient boolean _resourceDependencyUniqueId;
178     private transient Map<String,Object> _attributesMap;
179     
180     /**
181      * Construct an instance of the UIViewRoot.
182      */
183     public UIViewRoot()
184     {
185         setRendererType(null);
186     }
187 
188     /**
189      * @since 2.0
190      */
191     public void addComponentResource(FacesContext context, UIComponent componentResource)
192     {
193         addComponentResource(context, componentResource, null);
194     }
195 
196     /**
197      * @since 2.0
198      */
199     public void addComponentResource(FacesContext context, UIComponent componentResource, String target)
200     {
201         // If the target argument is null
202         if (target == null)
203         {
204             // Look for a target attribute on the component
205             target = (String)componentResource.getAttributes().get("target");
206 
207             // If there is no target attribute, set target to be the default value head
208             if (target == null)
209             {
210                 target = "head";
211             }
212         }
213 
214         // Call getComponentResources to obtain the child list for the given target
215         List<UIComponent> componentResources = _getComponentResources(context, target);
216 
217         // If the component ID of componentResource matches the ID of a resource
218         // that has already been added, remove the old resource.
219         String componentId = componentResource.getId();
220         
221         if (componentId == null)
222         {
223             // componentResource can have no id - calling createUniqueId makes us sure that component will have one
224             // https://issues.apache.org/jira/browse/MYFACES-2775
225             componentId = createUniqueId(context, null);
226             componentResource.setId(componentId);
227         }
228         
229         // This var helps to handle the case when we try to add a component that already is
230         // on the resource list, because PostAddToViewEvent also is sent to components 
231         // backing resources. The problem start when a component is already inside
232         // componentResources list and we try to relocate it again. This leads to a StackOverflowException
233         // so we need to check if a component is and prevent remove and add it again. Note
234         // that remove and then add a component trigger another PostAddToViewEvent. The right
235         // point to prevent this StackOverflowException is here, because this method is 
236         // responsible to traverse the componentResources list and add when necessary.
237         boolean alreadyAdded = false;
238 
239         //The check is only necessary if the component resource is part of the tree.
240         if (componentResource.isInView())
241         {
242             if (componentResource.getParent() != null &&
243                 componentResource.getParent().getId() != null &&
244                 componentResource.getParent().getId().equals(JAVAX_FACES_LOCATION_PREFIX + target))
245             {
246                 // We can assume safely that the component is in place, because there is no way to 
247                 // put a component resource on a component resource container without call addComponentResource
248                 // so relocation here will not happen.
249                 alreadyAdded = true;
250             }
251             else if (componentId != null)
252             {
253                 for(Iterator<UIComponent> it = componentResources.iterator(); it.hasNext();)
254                 {
255                     UIComponent component = it.next();
256                     if(componentId.equals(component.getId()) && componentResource != component)
257                     {
258                         if (!component.isCachedFacesContext())
259                         {
260                             try
261                             {
262                                 component.setCachedFacesContext(context);
263                                 it.remove();
264                             }
265                             finally
266                             {
267                                 component.setCachedFacesContext(null);
268                             }
269                         }
270                         else
271                         {
272                             it.remove();
273                         }
274                     }
275                     else if (componentResource == component)
276                     {
277                         alreadyAdded = true;
278                     }
279                 }
280             }
281         }
282         else if (componentId != null)
283         {
284             for(Iterator<UIComponent> it = componentResources.iterator(); it.hasNext();)
285             {
286                 UIComponent component = it.next();
287                 if(componentId.equals(component.getId()) && componentResource != component)
288                 {
289                     if (!component.isCachedFacesContext())
290                     {
291                         try
292                         {
293                             component.setCachedFacesContext(context);
294                             it.remove();
295                         }
296                         finally
297                         {
298                             component.setCachedFacesContext(null);
299                         }
300                     }
301                     else
302                     {
303                         it.remove();
304                     }
305                 }
306                 else if (componentResource == component)
307                 {
308                     alreadyAdded = true;
309                 }
310             }
311         }
312         
313         // Add the component resource to the list
314         if (!alreadyAdded)
315         {
316             if (!componentResource.isCachedFacesContext())
317             {
318                 try
319                 {
320                     componentResource.setCachedFacesContext(context);
321                     componentResources.add(componentResource);
322                 }
323                 finally
324                 {
325                     componentResource.setCachedFacesContext(context);
326                 }
327             }
328             else
329             {
330                 componentResources.add(componentResource);
331             }
332 
333             // this is required to make dynamic resource loading possible since JSF 2.3
334             if (context.getPartialViewContext().isAjaxRequest())
335             {
336                 boolean isBuildingInitialState
337                         = context.getAttributes().containsKey(StateManager.IS_BUILDING_INITIAL_STATE);
338                 
339                 // FaceletViewDeclarationLanguage.isRefreshingTransientBuild(context)
340                 boolean isRefreshTransientBuild
341                         = context.getAttributes().containsKey("org.apache.myfaces.REFRESHING_TRANSIENT_BUILD");
342                 
343                 boolean isPostAddToViewEventAfterBuildInitialState =
344                         !isBuildingInitialState || (isBuildingInitialState && isRefreshTransientBuild);
345                 if (isPostAddToViewEventAfterBuildInitialState)
346                 {
347                     try
348                     {
349                         // RequestViewContext requestViewContext = RequestViewContext.getInstance(context);
350                         // requestViewContext.setRenderTarget("head", true, componentResource);
351                         Object requestViewContext = REQUEST_VIEW_CONTEXT_GET_INSTANCE.invoke(null, context);
352                         REQUEST_VIEW_CONTEXT_SET_RENDER_TARGET.invoke(requestViewContext, "head", true, componentResource);
353                     }
354                     catch (Exception e)
355                     {
356                         _getLogger().log(Level.SEVERE, "Could not access RequestViewContext", e);
357                     }
358                 }
359             }
360         }
361     }
362 
363     /**
364      * Adds a The phaseListeners attached to ViewRoot.
365      */
366     public void addPhaseListener(PhaseListener phaseListener)
367     {
368         if (phaseListener == null)
369         {
370             throw new NullPointerException("phaseListener");
371         }
372         
373         getStateHelper().add(PropertyKeys.phaseListeners, phaseListener);
374     }
375 
376     /**
377      * @since 2.0
378      */
379     public void broadcastEvents(FacesContext context, PhaseId phaseId)
380     {
381         if (_events == null)
382         {
383             return;
384         }
385         
386         Events events = _getEvents(phaseId);
387         
388         // Spec. 3.4.2.6 Event Broadcasting:
389         // Queue one or more additional events, from the same source
390         // component or a different one, for processing during the
391         // current lifecycle phase.
392         
393         // Unfortunately with that requirement it is easy to create infinite loop in processing. One example can be:
394         //
395         // public processAction(ActionEvent actionEvent)
396         // {
397         // actionEvent  = new ActionEvent(actionEvent.getComponent());
398         // actionEvent.queue();
399         // }
400         // 
401         // Thus we iterate here only 15x. If iteration overreachs 15 we output a warning  
402         
403         int loops = 0;
404         int maxLoops = 15;
405         Collection<FacesEvent> eventsAborted = new LinkedList<FacesEvent>(); 
406         do
407         {
408             // First broadcast events that have been queued for PhaseId.ANY_PHASE.
409             boolean noUnexpectedException = _broadcastAll(context, events.getAnyPhase(), eventsAborted);
410             if (!noUnexpectedException)
411             {
412                 return;
413             }
414             List<FacesEvent> eventsOnPhase = events.getOnPhase();
415             if (!eventsAborted.isEmpty())
416             {
417                 eventsOnPhase.removeAll(eventsAborted);
418                 eventsAborted.clear();
419             }
420             noUnexpectedException = _broadcastAll(context, eventsOnPhase, eventsAborted);
421             if (!noUnexpectedException)
422             {
423                 return;
424             }
425 
426             events = _getEvents(phaseId);
427             loops++;
428             
429         } while (events.hasMoreEvents() && loops < maxLoops);
430         
431         if (loops == maxLoops && events.hasMoreEvents())
432         {
433             // broadcast reach maxLoops - probably a infinitive recursion:
434             boolean production = getFacesContext().isProjectStage(ProjectStage.Production);
435             Level level = production ? Level.FINE : Level.WARNING;
436             if (_getLogger().isLoggable(level))
437             {
438                 List<String> name = new ArrayList<String>(events.getAnyPhase().size() + events.getOnPhase().size());
439                 for (FacesEvent facesEvent : events.getAnyPhase())
440                 {
441                     String clientId = facesEvent.getComponent().getClientId(getFacesContext());
442                     name.add(clientId);
443                 }
444                 for (FacesEvent facesEvent : events.getOnPhase())
445                 {
446                     String clientId = facesEvent.getComponent().getClientId(getFacesContext());
447                     name.add(clientId);
448                 }
449                 _getLogger().log(level,
450                         "Event broadcating for PhaseId {0} at UIViewRoot {1} reaches maximal limit, please check " +
451                         "listeners for infinite recursion. Component id: {2}",
452                         new Object [] {phaseId, getViewId(), name});
453             }
454         }
455     }
456 
457 
458     /**
459      * Provides a unique id for this component instance.
460      */
461     public String createUniqueId()
462     {
463         return createUniqueId(getFacesContext(), null);
464     }
465 
466     /**
467      * 
468      * {@inheritDoc}
469      * 
470      * @since 2.0
471      */
472     public String createUniqueId(FacesContext context, String seed)
473     {
474 
475         // Generate an identifier for a component. The identifier will be prefixed with
476         // UNIQUE_ID_PREFIX, and will be unique within this UIViewRoot.
477         if(seed==null)
478         {
479             if (isResourceDependencyUniqueId())
480             {
481                 Integer uniqueIdCounter = (Integer) getStateHelper().get(
482                     PropertyKeys.resourceDependencyUniqueIdCounter);
483                 uniqueIdCounter = (uniqueIdCounter == null) ? 0 : uniqueIdCounter;
484                 getStateHelper().put(PropertyKeys.resourceDependencyUniqueIdCounter, (uniqueIdCounter+1));
485                 if (uniqueIdCounter >= _ComponentUtils.UNIQUE_COMPONENT_RD_IDS_SIZE)
486                 {
487                     StringBuilder bld = _getSharedStringBuilder(context);
488                     return bld.append(UNIQUE_ID_PREFIX).append(
489                         _ComponentUtils.RD_ID_PREFIX).append(uniqueIdCounter).toString();
490                 }
491                 else
492                 {
493                     return _ComponentUtils.UNIQUE_COMPONENT_RD_IDS[uniqueIdCounter];
494                 }
495             }
496             else
497             {
498                 Integer uniqueIdCounter = (Integer) getStateHelper().get(PropertyKeys.uniqueIdCounter);
499                 uniqueIdCounter = (uniqueIdCounter == null) ? 0 : uniqueIdCounter;
500                 getStateHelper().put(PropertyKeys.uniqueIdCounter, (uniqueIdCounter+1));
501                 if (uniqueIdCounter >= _ComponentUtils.UNIQUE_COMPONENT_V_IDS_SIZE)
502                 {
503                     StringBuilder bld = _getSharedStringBuilder(context);
504                     return bld.append(UNIQUE_ID_PREFIX).append(
505                         _ComponentUtils.V_ID_PREFIX).append(uniqueIdCounter).toString();
506                 }
507                 else
508                 {
509                     return _ComponentUtils.UNIQUE_COMPONENT_V_IDS[uniqueIdCounter];
510                 }
511             }
512         }
513         // Optionally, a unique seed value can be supplied by component creators which
514         // should be included in the generated unique id.
515         else
516         {
517             StringBuilder bld = _getSharedStringBuilder(context);
518             return bld.append(UNIQUE_ID_PREFIX).append(seed).toString();
519         }
520     }
521 
522     @Override
523     public void encodeBegin(FacesContext context) throws IOException
524     {
525         checkNull(context, "context");
526 
527         boolean skipPhase = false;
528 
529         try
530         {
531             skipPhase = notifyListeners(context, PhaseId.RENDER_RESPONSE, getBeforePhaseListener(), true);
532         }
533         catch (Exception e)
534         {
535             // following the spec we have to swallow the exception
536             _getLogger().log(Level.SEVERE, "Exception while processing phase listener: " + e.getMessage(), e);
537         }
538 
539         if (!skipPhase)
540         {
541             //prerendering happens, we now publish the prerender view event
542             //the specs states that the viewroot as source is about to be rendered
543             //hence we issue the event immediately before publish, if the phase is not skipped
544             //context.getApplication().publishEvent(context, PreRenderViewEvent.class, this);
545             //then the view rendering is about to begin
546             super.encodeBegin(context);
547         }
548         else
549         {
550             pushComponentToEL(context, this);
551         }
552     }
553 
554     /**
555      * @since 2.0
556      */
557     @Override
558     public void encodeChildren(FacesContext context) throws IOException
559     {
560         if (context.getResponseComplete())
561         {
562             return;
563         }
564         PartialViewContext pContext = context.getPartialViewContext();
565         
566         // If PartialViewContext.isAjaxRequest() returns true
567         if (pContext.isAjaxRequest())
568         {
569             // Perform partial rendering by calling PartialViewContext.processPartial() with PhaseId.RENDER_RESPONSE.
570             //sectin 13.4.3 of the jsf2 specification
571             pContext.processPartial(PhaseId.RENDER_RESPONSE);
572         }
573         else
574         {
575             // If PartialViewContext.isAjaxRequest() returns false
576             // delegate to super.encodeChildren(javax.faces.context.FacesContext) method.
577             super.encodeChildren(context);
578         }
579     }
580 
581     @Override
582     public void encodeEnd(FacesContext context) throws IOException
583     {
584         checkNull(context, "context");
585 
586         if (!context.getResponseComplete())
587         {
588             super.encodeEnd(context);
589             
590             // the call to encodeAll() on every UIViewParameter here is only necessary
591             // if the current request is _not_ an AJAX request, because if it was an
592             // AJAX request, the call would already have happened in PartialViewContextImpl and
593             // would anyway be too late here, because the state would already have been generated
594             PartialViewContext partialContext = context.getPartialViewContext();
595             if (!partialContext.isAjaxRequest())
596             {
597                 ViewDeclarationLanguage vdl
598                         = context.getApplication().getViewHandler().getViewDeclarationLanguage(context, getViewId());
599                 if (vdl != null)
600                 {
601                     // If the current view has view parameters, as indicated by a non-empty
602                     // and non-UnsupportedOperationException throwing
603                     // return from ViewDeclarationLanguage.getViewMetadata(javax.faces.context.FacesContext, String)
604                     ViewMetadata metadata = null;
605                     try
606                     {
607                         metadata = vdl.getViewMetadata(context, getViewId());    
608                     }
609                     catch(UnsupportedOperationException e)
610                     {
611                         _getLogger().log(Level.SEVERE, "Exception while obtaining the view metadata: " +
612                                 e.getMessage(), e);
613                     }
614                     
615                     if (metadata != null)
616                     {
617                         try
618                         {
619                             Collection<UIViewParameter> viewParams = ViewMetadata.getViewParameters(this);    
620                             if(!viewParams.isEmpty())
621                             {
622                                 // call UIViewParameter.encodeAll(javax.faces.context.FacesContext) on each parameter.
623                                 for(UIViewParameter param : viewParams)
624                                 {
625                                     param.encodeAll(context);
626                                 }
627                             }
628                         }
629                         catch(UnsupportedOperationException e)
630                         {
631                             // If calling getViewParameters() causes UnsupportedOperationException
632                             // to be thrown, the exception must be silently swallowed.
633                         }
634                     }
635                 }
636             }
637         }
638         
639         try
640         {
641             notifyListeners(context, PhaseId.RENDER_RESPONSE, getAfterPhaseListener(), false);
642         }
643         catch (Exception e)
644         {
645             // following the spec we have to swallow the exception
646             _getLogger().log(Level.SEVERE, "Exception while processing phase listener: " + e.getMessage(), e);
647         }
648     }
649 
650     /**
651      * MethodBinding pointing to a method that takes a javax.faces.event.PhaseEvent and returns void, called after every
652      * phase except for restore view.
653      *
654      * @return the new afterPhaseListener value
655      */
656     @JSFProperty(returnSignature = "void", methodSignature = "javax.faces.event.PhaseEvent",
657                  jspName = "afterPhase", stateHolder=true)
658     public MethodExpression getAfterPhaseListener()
659     {
660         return (MethodExpression) getStateHelper().eval(PropertyKeys.afterPhaseListener);
661     }
662 
663     /**
664      * MethodBinding pointing to a method that takes a javax.faces.event.PhaseEvent and returns void, called before
665      * every phase except for restore view.
666      *
667      * @return the new beforePhaseListener value
668      */
669     @JSFProperty(returnSignature = "void", methodSignature = "javax.faces.event.PhaseEvent",
670                  jspName = "beforePhase", stateHolder=true)
671     public MethodExpression getBeforePhaseListener()
672     {
673         return (MethodExpression) getStateHelper().eval(PropertyKeys.beforePhaseListener);
674     }
675 
676     /**
677      * @since 2.0
678      */
679     public List<UIComponent> getComponentResources(FacesContext context, String target)
680     {
681         if (target == null)
682         {
683             throw new NullPointerException("target");
684         }
685         // Locate the facet for the component by calling getFacet() using target as the argument
686         UIComponent facet = getFacet(target);
687 
688         /*
689         // If the facet is not found,
690         if (facet == null)
691         {
692             // create the facet by calling context.getApplication().createComponent()
693             // using javax.faces.Panel as the argument
694             facet = context.getApplication().createComponent("javax.faces.Panel");
695 
696             // Set the id of the facet to be target
697             facet.setId(target);
698 
699             // Add the facet to the facets Map using target as the key
700             getFacets().put(target, facet);
701         }
702 
703         // Return the children of the facet
704         // The API doc indicates that this method should "Return an unmodifiable
705         // List of UIComponents for the provided target argument."
706         // and also that "If no children are found for the facet, return Collections.emptyList()."
707         List<UIComponent> children = facet.getChildren();
708         return ( children == null ? Collections.<UIComponent>emptyList() : Collections.unmodifiableList(children) );
709         */
710         if (facet != null)
711         {
712             if (facet.getChildCount() > 0)
713             {
714                 return Collections.unmodifiableList(facet.getChildren());
715             }
716             else
717             {
718                 return Collections.<UIComponent>emptyList();
719             }
720         }
721         return Collections.<UIComponent>emptyList();
722     }
723     
724     private List<UIComponent> _getComponentResources(FacesContext context, String target)
725     {
726         // Locate the facet for the component by calling getFacet() using target as the argument
727         UIComponent facet = getFacet(target);
728 
729         // If the facet is not found,
730         if (facet == null)
731         {
732             // create the facet by calling context.getApplication().createComponent()
733             // using javax.faces.Panel as the argument
734             facet = context.getApplication().createComponent(context,
735                 "javax.faces.ComponentResourceContainer", null);
736 
737             // Set the id of the facet to be target
738             if (target.equals("head"))
739             {
740                 facet.setId(JAVAX_FACES_LOCATION_HEAD);
741             }
742             else if (target.equals("body"))
743             {
744                 facet.setId(JAVAX_FACES_LOCATION_BODY);
745             }
746             else if (target.equals("form"))
747             {
748                 facet.setId(JAVAX_FACES_LOCATION_FORM);
749             }
750             else
751             {
752                 facet.setId(JAVAX_FACES_LOCATION_PREFIX + target);
753             }
754             
755             // From jsr-314-open list it was made clear this facet is transient,
756             // because all component resources does not change its inner state between
757             // requests
758             //
759             // MYFACES-3047 It was found that resources added using ResourceDependency annotation
760             // requires to be saved and restored, so it is not possible to mark this facets
761             // as transient. The previous statement is true only for PSS.
762             //facet.setTransient(true);
763 
764             // Add the facet to the facets Map using target as the key
765             getFacets().put(target, facet);
766         }
767         return facet.getChildren();
768     }
769     
770     /**
771      * @since 2.3
772      * @param context
773      * @return 
774      */
775     public List<UIComponent> getComponentResources(FacesContext context)
776     {
777         List<UIComponent> componentResources = new ArrayList<UIComponent>();
778         
779         componentResources.addAll(_getComponentResources(context, "head"));
780         componentResources.addAll(_getComponentResources(context, "body"));
781         componentResources.addAll(_getComponentResources(context, "form"));
782         
783         return Collections.unmodifiableList(componentResources);
784     }
785 
786     @Override
787     public String getFamily()
788     {
789         return COMPONENT_FAMILY;
790     }
791 
792     /**
793      * The locale for this view.
794      * <p>
795      * Defaults to the default locale specified in the faces configuration file.
796      * </p>
797      */
798     @JSFProperty
799     public Locale getLocale()
800     {
801         Object locale = getStateHelper().get(PropertyKeys.locale);
802         if (locale != null)
803         {
804             return (Locale)locale;
805         }
806         ValueExpression expression = getValueExpression(PropertyKeys.locale.toString());
807         if (expression != null)
808         {
809             Object veLocale = expression.getValue(getFacesContext().getELContext());
810             if (veLocale instanceof Locale)
811             {
812                 return (Locale) veLocale;
813             }
814             else
815             {
816                 return (Locale) _LocaleUtils.toLocale(veLocale.toString());
817             }
818         }
819         else
820         {
821             locale = getFacesContext().getApplication().getViewHandler().calculateLocale(getFacesContext());
822 
823             if (locale instanceof Locale)
824             {
825                 return (Locale)locale;
826             }
827             else if (locale instanceof String)
828             {
829                 return _LocaleUtils.toLocale((String)locale);
830             }
831         }
832 
833         return getFacesContext().getApplication().getViewHandler().calculateLocale(getFacesContext());
834     }
835 
836     /**
837      * @since 2.0
838      */
839     public List<PhaseListener> getPhaseListeners()
840     {
841         List<PhaseListener> listeners = (List<PhaseListener>) getStateHelper().get(PropertyKeys.phaseListeners);
842         if (listeners == null)
843         {
844             listeners = Collections.emptyList();
845         }
846         else
847         {
848             listeners = Collections.unmodifiableList(listeners);
849         }
850 
851         return listeners;
852     }
853 
854     /**
855      * Defines what renderkit should be used to render this view.
856      */
857     @JSFProperty
858     public String getRenderKitId()
859     {
860         return (String) getStateHelper().eval(PropertyKeys.renderKitId);
861     }
862 
863     /**
864      * @since 2.0
865      */
866     @Override
867     public boolean getRendersChildren()
868     {
869         // Call UIComponentBase.getRendersChildren() 
870         // If PartialViewContext.isAjaxRequest()  returns true this method must return true.
871         PartialViewContext context = getFacesContext().getPartialViewContext();
872 
873         return (context.isAjaxRequest()) ? true : super.getRendersChildren();
874     }
875 
876     /**
877      * A unique identifier for the "template" from which this view was generated.
878      * <p>
879      * Typically this is the filesystem path to the template file, but the exact details are the responsibility of the
880      * current ViewHandler implementation.
881      */
882     @JSFProperty(tagExcluded = true)
883     public String getViewId()
884     {
885         return (String) getStateHelper().get(PropertyKeys.viewId);
886     }
887 
888     /**
889      * @since 2.0
890      */
891     public Map<String, Object> getViewMap()
892     {
893         return this.getViewMap(true);
894     }
895 
896     /**
897      * @since 2.0
898      */
899     public Map<String, Object> getViewMap(boolean create)
900     {
901         if (_viewScope == null && create)
902         {
903             if (VIEW_SCOPE_PROXY_MAP_CLASS != null)
904             {
905                 _viewScope = (Map<String, Object>)
906                     _ClassUtils.newInstance(VIEW_SCOPE_PROXY_MAP_CLASS);
907             }
908             else
909             {
910                 //Default to map for testing purposes
911                 _viewScope = new ViewScope();
912             }
913             FacesContext facesContext = getFacesContext();
914             if (facesContext != null)
915             {
916                 facesContext.getApplication().publishEvent(facesContext, PostConstructViewMapEvent.class, UIViewRoot.class, this);
917             }
918         }
919 
920         return _viewScope;
921     }
922     
923     /**
924      * {@inheritDoc}
925      */
926     @Override
927     public boolean isInView()
928     {
929         return true;
930     }
931 
932     public void processApplication(final FacesContext context)
933     {
934         checkNull(context, "context");
935         _process(context, PhaseId.INVOKE_APPLICATION, null);
936     }
937 
938     @Override
939     public void processDecodes(FacesContext context)
940     {
941         checkNull(context, "context");
942         _process(context, PhaseId.APPLY_REQUEST_VALUES, APPLY_REQUEST_VALUES_PROCESSOR);
943     }
944 
945     /**
946      * @since 2.0
947      */
948     @Override
949     public void processRestoreState(FacesContext context, Object state)
950     {
951         // The default implementation must call UIComponentBase.processRestoreState(javax.faces.context.FacesContext,
952         // java.lang.Object) from within a try block.
953         try
954         {
955             super.processRestoreState(context, state);
956         }
957         finally
958         {
959             // The try block must have a finally block that ensures that no FacesEvents remain in the event queue
960             broadcastEvents(context, PhaseId.RESTORE_VIEW);
961 
962             //visitTree(VisitContext.createVisitContext(context), new RestoreStateCallback());
963         }
964     }
965 
966     @Override
967     public void queueEvent(FacesEvent event)
968     {
969         checkNull(event, "event");
970         if (_events == null)
971         {
972             _events = new ArrayList<FacesEvent>();
973         }
974 
975         _events.add(event);
976     }
977 
978     @Override
979     public void processValidators(FacesContext context)
980     {
981         checkNull(context, "context");
982         _process(context, PhaseId.PROCESS_VALIDATIONS, PROCESS_VALIDATORS_PROCESSOR);
983     }
984 
985     @Override
986     public void processUpdates(FacesContext context)
987     {
988         checkNull(context, "context");
989         _process(context, PhaseId.UPDATE_MODEL_VALUES, UPDATE_MODEL_PROCESSOR);
990     }
991 
992     public void setLocale(Locale locale)
993     {
994         getStateHelper().put(PropertyKeys.locale, locale );
995     }
996 
997     /**
998      * Invoke view-specific phase listeners, plus an optional EL MethodExpression.
999      * <p>
1000      * JSF1.2 adds the ability for PhaseListener objects to be added to a UIViewRoot instance, and for
1001      * "beforePhaseListener" and "afterPhaseListener" EL expressions to be defined on the viewroot. This method is
1002      * expected to be called at appropriate times, and will then execute the relevant listener callbacks.
1003      * <p>
1004      * Parameter "listener" may be null. If not null, then it is an EL expression pointing to a user method that will be
1005      * invoked.
1006      * <p>
1007      * Note that the global PhaseListeners are invoked via the Lifecycle implementation, not from this method here.
1008      * <p>
1009      * These PhaseListeners are processed with the same rules as the globally defined PhaseListeners, except
1010      * that any Exceptions, which may occur during the execution of the PhaseListeners, will only be logged
1011      * and not published to the ExceptionHandler.
1012      */
1013     private boolean notifyListeners(FacesContext context, PhaseId phaseId, MethodExpression listener,
1014                                     boolean beforePhase)
1015     {
1016         List<PhaseListener> phaseListeners = (List<PhaseListener>) getStateHelper().get(PropertyKeys.phaseListeners);
1017         // Check if any listener was called
1018         boolean listenerCalled = false;
1019         if (listener != null || (phaseListeners != null && !phaseListeners.isEmpty()))
1020         {
1021             // how many listeners do we have? (the MethodExpression listener is counted in either way)
1022             // NOTE: beforePhaseSuccess[0] always refers to the MethodExpression listener
1023             int listenerCount = (phaseListeners != null ? phaseListeners.size() + 1 : 1);
1024             
1025             boolean[] beforePhaseSuccess;
1026             if (beforePhase)
1027             {
1028                 beforePhaseSuccess = new boolean[listenerCount];
1029                 _getListenerSuccessMap().put(phaseId, beforePhaseSuccess);
1030             }
1031             else
1032             {
1033                 // afterPhase - get beforePhaseSuccess from the Map
1034                 beforePhaseSuccess = _getListenerSuccessMap().get(phaseId);
1035                 if (beforePhaseSuccess == null)
1036                 {
1037                     // no Map available - assume that everything went well
1038                     beforePhaseSuccess = new boolean[listenerCount];
1039                     Arrays.fill(beforePhaseSuccess, true);
1040                 }
1041             }
1042             
1043             PhaseEvent event = createEvent(context, phaseId);
1044 
1045             // only invoke the listener if we are in beforePhase
1046             // or if the related before PhaseListener finished without an Exception
1047             if (listener != null && (beforePhase || beforePhaseSuccess[0]))
1048             {
1049                 listenerCalled = true;
1050                 try
1051                 {
1052                     listener.invoke(context.getELContext(), new Object[] { event });
1053                     beforePhaseSuccess[0] = true;
1054                 }
1055                 catch (Throwable t) 
1056                 {
1057                     beforePhaseSuccess[0] = false; // redundant - for clarity
1058                     _getLogger().log(Level.SEVERE, "An Exception occured while processing " +
1059                                              listener.getExpressionString() + 
1060                                              " in Phase " + phaseId, t);
1061                     if (beforePhase)
1062                     {
1063                         return context.getResponseComplete() ||
1064                                 (context.getRenderResponse() && !PhaseId.RENDER_RESPONSE.equals(phaseId));
1065                     }
1066                 }
1067             }
1068             else if (beforePhase)
1069             {
1070                 // there is no beforePhase MethodExpression listener
1071                 beforePhaseSuccess[0] = true;
1072             }
1073 
1074             if (phaseListeners != null && !phaseListeners.isEmpty())
1075             {
1076                 if (beforePhase)
1077                 {
1078                     // process listeners in ascending order
1079                     for (int i = 0; i < beforePhaseSuccess.length - 1; i++)
1080                     {
1081                         PhaseListener phaseListener;
1082                         try 
1083                         {
1084                             phaseListener = phaseListeners.get(i);
1085                         }
1086                         catch (IndexOutOfBoundsException e)
1087                         {
1088                             // happens when a PhaseListener removes another PhaseListener 
1089                             // from UIViewRoot in its beforePhase method
1090                             throw new IllegalStateException("A PhaseListener must not remove " +
1091                                     "PhaseListeners from UIViewRoot.");
1092                         }
1093                         PhaseId listenerPhaseId = phaseListener.getPhaseId();
1094                         if (phaseId.equals(listenerPhaseId) || PhaseId.ANY_PHASE.equals(listenerPhaseId))
1095                         {
1096                             listenerCalled = true;
1097                             try
1098                             {
1099                                 phaseListener.beforePhase(event);
1100                                 beforePhaseSuccess[i + 1] = true;
1101                             }
1102                             catch (Throwable t) 
1103                             {
1104                                 beforePhaseSuccess[i + 1] = false; // redundant - for clarity
1105                                 _getLogger().log(Level.SEVERE, "An Exception occured while processing the " +
1106                                                          "beforePhase method of PhaseListener " + phaseListener +
1107                                                          " in Phase " + phaseId, t);
1108                                 if (shouldViewRootPhaseListenerQueuesExceptions(context))
1109                                 {
1110                                     publishException (context, t, phaseId, 
1111                                             ExceptionQueuedEventContext.IN_BEFORE_PHASE_KEY);
1112                                 }
1113                                 return context.getResponseComplete() ||
1114                                         (context.getRenderResponse() && !PhaseId.RENDER_RESPONSE.equals(phaseId));
1115                             }
1116                         }
1117                     }
1118                 }
1119                 else
1120                 {
1121                     // afterPhase
1122                     // process listeners in descending order
1123                     for (int i = beforePhaseSuccess.length - 1; i > 0; i--)
1124                     {
1125                         PhaseListener phaseListener;
1126                         try 
1127                         {
1128                             phaseListener = phaseListeners.get(i - 1);
1129                         }
1130                         catch (IndexOutOfBoundsException e)
1131                         {
1132                             // happens when a PhaseListener removes another PhaseListener 
1133                             // from UIViewRoot in its beforePhase or afterPhase method
1134                             throw new IllegalStateException("A PhaseListener must not remove " +
1135                                     "PhaseListeners from UIViewRoot.");
1136                         }
1137                         PhaseId listenerPhaseId = phaseListener.getPhaseId();
1138                         if ((phaseId.equals(listenerPhaseId) || PhaseId.ANY_PHASE.equals(listenerPhaseId))
1139                                 && beforePhaseSuccess[i])
1140                         {
1141                             listenerCalled = true;
1142                             try
1143                             {
1144                                 phaseListener.afterPhase(event);
1145                             }
1146                             catch (Throwable t) 
1147                             {
1148                                 logger.log(Level.SEVERE, "An Exception occured while processing the " +
1149                                                          "afterPhase method of PhaseListener " + phaseListener +
1150                                                          " in Phase " + phaseId, t);
1151                                 if (shouldViewRootPhaseListenerQueuesExceptions(context))
1152                                 {
1153                                     publishException (context, t, phaseId, 
1154                                             ExceptionQueuedEventContext.IN_AFTER_PHASE_KEY);
1155                                 }
1156                             }
1157                         }
1158                     }
1159                 }
1160             }
1161         }
1162 
1163         // The spec javadoc says "... Upon return from the listener, call FacesContext.getResponseComplete() 
1164         // and FacesContext.getRenderResponse(). If either return true set the internal state flag to true. ..."
1165         // and later it says:
1166         // "... Execute any processing for this phase if the internal state flag was not set. ..."
1167         // But after some testing it seems if the internal state flag is not set, the check is not done and the
1168         // phase is not skipped. The only exception is in render response phase.
1169         if (listenerCalled)
1170         {
1171             if (beforePhase)
1172             {
1173                 return context.getResponseComplete() ||
1174                         (context.getRenderResponse() && !PhaseId.RENDER_RESPONSE.equals(phaseId));
1175             }
1176             else
1177             {
1178                 return context.getResponseComplete() || context.getRenderResponse();
1179             }
1180         }
1181         else
1182         {
1183             if (beforePhase)
1184             {
1185                 if (PhaseId.RENDER_RESPONSE.equals(phaseId))
1186                 {
1187                     return context.getResponseComplete();
1188                 }
1189                 else
1190                 {
1191                     // Don't check and don't skip
1192                     return false;
1193                 }
1194             }
1195             else
1196             {
1197                 // Note if is afterPhase the return value is not relevant.
1198                 return context.getResponseComplete() || context.getRenderResponse();
1199             }
1200         }
1201     }
1202 
1203     private PhaseEvent createEvent(FacesContext context, PhaseId phaseId)
1204     {
1205         if (_lifecycle == null)
1206         {
1207             LifecycleFactory factory = (LifecycleFactory)FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY);
1208             String id = context.getExternalContext().getInitParameter(FacesServlet.LIFECYCLE_ID_ATTR);
1209             if (id == null)
1210             {
1211                 id = LifecycleFactory.DEFAULT_LIFECYCLE;
1212             }
1213             _lifecycle = factory.getLifecycle(id);
1214         }
1215         return new PhaseEvent(context, phaseId, _lifecycle);
1216     }
1217 
1218     /**
1219      * Broadcast all events in the specified collection, stopping the at any time an AbortProcessingException
1220      * is thrown.
1221      *
1222      * @param context the current JSF context
1223      * @param events the events to broadcast
1224      * @return 
1225      *
1226      * @return <code>true</code> if the broadcast was completed without unexpected abortion/exception,
1227      *  <code>false</code> otherwise
1228      */
1229     private boolean _broadcastAll(FacesContext context,
1230                                List<? extends FacesEvent> events,
1231                                Collection<FacesEvent> eventsAborted)
1232     {
1233         assert events != null;
1234 
1235         for (int i = 0; i < events.size(); i++)
1236         {
1237             FacesEvent event = events.get(i);
1238             UIComponent source = event.getComponent();
1239             UIComponent compositeParent = UIComponent.getCompositeComponentParent(source);
1240             if (compositeParent != null)
1241             {
1242                 pushComponentToEL(context, compositeParent);
1243             }
1244             // Push the source as the current component
1245             pushComponentToEL(context, source);
1246 
1247             try
1248             {
1249                 // Actual event broadcasting
1250                 if (!source.isCachedFacesContext())
1251                 {
1252                     try
1253                     {
1254                         source.setCachedFacesContext(context);
1255                         source.broadcast(event);
1256                     }
1257                     finally
1258                     {
1259                         source.setCachedFacesContext(null);
1260                     }
1261                 }
1262                 else
1263                 {
1264                     source.broadcast(event);
1265                 }
1266             }
1267             catch (Exception e)
1268             {
1269 
1270                 Throwable cause = e;
1271                 AbortProcessingException ape = null;
1272                 do
1273                 {
1274                     if (cause != null && cause instanceof AbortProcessingException)
1275                     {
1276                         ape = (AbortProcessingException) cause;
1277                         break;
1278                     }
1279                     cause = cause.getCause();
1280                 }
1281                 while (cause != null);
1282                 
1283                 // for any other exception publish ExceptionQueuedEvent
1284                 // publish the Exception to be handled by the ExceptionHandler
1285                 // to publish or to not publish APE? That is the question : MYFACES-3199. We publish it,
1286                 // because user can handle it in custom exception handler then. 
1287                 if (ape != null)
1288                 {
1289                     e = ape;
1290                 }
1291                 ExceptionQueuedEventContext exceptionContext 
1292                         = new ExceptionQueuedEventContext(context, e, source, context.getCurrentPhaseId());
1293                 context.getApplication().publishEvent(context, ExceptionQueuedEvent.class, exceptionContext);
1294 
1295                 
1296                 if (ape != null)
1297                 {
1298                     // APE found,  abortion for this event only
1299                     eventsAborted.add(event);
1300                 }
1301                 else
1302                 {
1303                     // We can't continue broadcast processing if other exception is thrown:
1304                     return false;
1305                 }
1306             }
1307             finally
1308             {
1309                 // Restore the current component
1310                 source.popComponentFromEL(context);
1311                 if (compositeParent != null)
1312                 {
1313                     compositeParent.popComponentFromEL(context);
1314                 }
1315             }
1316         }
1317         return true;
1318     }
1319 
1320     private void clearEvents()
1321     {
1322         _events = null;
1323     }
1324 
1325     private void checkNull(Object value, String valueLabel)
1326     {
1327         if (value == null)
1328         {
1329             throw new NullPointerException(valueLabel + " is null");
1330         }
1331     }
1332 
1333     public void setRenderKitId(String renderKitId)
1334     {
1335         getStateHelper().put(PropertyKeys.renderKitId, renderKitId );
1336     }
1337 
1338     /**
1339      * DO NOT USE.
1340      * <p>
1341      * This inherited property is disabled. Although this class extends a base-class that defines a read/write rendered
1342      * property, this particular subclass does not support setting it. Yes, this is broken OO design: direct all
1343      * complaints to the JSF spec group.
1344      */
1345     @Override
1346     @JSFProperty(tagExcluded = true)
1347     public void setRendered(boolean state)
1348     {
1349         // Call parent method due to TCK problems
1350         super.setRendered(state);
1351         // throw new UnsupportedOperationException();
1352     }
1353 
1354     @JSFProperty(tagExcluded=true)
1355     @Override
1356     public void setId(String id)
1357     {
1358         super.setId(id);
1359     }
1360     
1361     /**
1362      * {@inheritDoc}
1363      */
1364     @Override
1365     public void setInView(boolean isInView)
1366     {
1367         // no-op view root is always in view
1368     }
1369 
1370     public void removeComponentResource(FacesContext context, UIComponent componentResource)
1371     {
1372         removeComponentResource(context, componentResource, null);
1373     }
1374 
1375     public void removeComponentResource(FacesContext context, UIComponent componentResource, String target)
1376     {
1377         // If the target argument is null
1378         if (target == null)
1379         {
1380             // Look for a target attribute on the component
1381             target = (String)componentResource.getAttributes().get("target");
1382 
1383             // If there is no target attribute
1384             if (target == null)
1385             {
1386                 // Set target to be the default value head
1387                 target = "head";
1388             }
1389         }
1390 
1391 
1392         // Call getComponentResources to obtain the child list for the given target.
1393         //List<UIComponent> componentResources = getComponentResources(context, target);
1394         UIComponent facet = getFacet(target);
1395         if (facet != null)
1396         {
1397             //Only if the facet is found it is possible to remove the resource,
1398             //otherwise nothing should happen (call to getComponentResource trigger
1399             //creation of facet)
1400             // Remove the component resource from the child list
1401             facet.getChildren().remove(componentResource);
1402         }
1403     }
1404 
1405     public void setViewId(String viewId)
1406     {
1407         // It really doesn't make much sense to allow null here.
1408         // However the TCK does not check for it, and sun's implementation
1409         // allows it so here we allow it too.
1410         getStateHelper().put(PropertyKeys.viewId, viewId );
1411     }
1412 
1413     /**
1414      * Removes a The phaseListeners attached to ViewRoot.
1415      */
1416     public void removePhaseListener(PhaseListener phaseListener)
1417     {
1418         if (phaseListener == null)
1419         {
1420             return;
1421         }
1422 
1423         getStateHelper().remove(PropertyKeys.phaseListeners, phaseListener);
1424     }
1425 
1426     /**
1427      * Sets
1428      *
1429      * @param beforePhaseListener
1430      *            the new beforePhaseListener value
1431      */
1432     public void setBeforePhaseListener(MethodExpression beforePhaseListener)
1433     {
1434         getStateHelper().put(PropertyKeys.beforePhaseListener, beforePhaseListener);
1435     }
1436 
1437     /**
1438      * Sets
1439      *
1440      * @param afterPhaseListener
1441      *            the new afterPhaseListener value
1442      */
1443     public void setAfterPhaseListener(MethodExpression afterPhaseListener)
1444     {
1445         getStateHelper().put(PropertyKeys.afterPhaseListener, afterPhaseListener);
1446     }
1447 
1448     /**
1449      * @return the clearTransientMapOnSaveState
1450      */
1451     int getResetSaveStateMode()
1452     {
1453         return _resetSaveStateMode;
1454     }
1455 
1456     /**
1457      * @param clearTransientMapOnSaveState the clearTransientMapOnSaveState to set
1458      */
1459     void setResetSaveStateMode(int clearTransientMapOnSaveState)
1460     {
1461         this._resetSaveStateMode = clearTransientMapOnSaveState;
1462     }
1463 
1464     @Override
1465     public Map<String, Object> getAttributes()
1466     {
1467         if (_attributesMap == null)
1468         {
1469             _attributesMap = new _ViewAttributeMap(this, super.getAttributes());
1470         }
1471         return _attributesMap;
1472     }
1473     
1474     /**
1475      * @since 2.2
1476      * @param context
1477      * @param clientIds 
1478      */
1479     public void resetValues(FacesContext context,
1480                         java.util.Collection<java.lang.String> clientIds)    
1481     {
1482         VisitContext visitContext = (VisitContext) VisitContext.createVisitContext(
1483             context, clientIds, null);
1484         this.visitTree(visitContext, RESET_VALUES_CALLBACK);
1485     }
1486 
1487     /**
1488      * Indicates if the component is created when facelets builds the view and
1489      * is caused by the presence of a ResourceDependency annotation.
1490      * 
1491      * @return the _resourceDependencyUniqueId
1492      */
1493     boolean isResourceDependencyUniqueId()
1494     {
1495         return _resourceDependencyUniqueId;
1496     }
1497 
1498     void setResourceDependencyUniqueId(boolean resourceDependencyUniqueId)
1499     {
1500         this._resourceDependencyUniqueId = resourceDependencyUniqueId;
1501     }
1502     
1503     enum PropertyKeys
1504     {
1505          afterPhaseListener
1506         , beforePhaseListener
1507         , phaseListeners
1508         , locale
1509         , renderKitId
1510         , viewId
1511         , uniqueIdCounter
1512         , resourceDependencyUniqueIdCounter
1513     }
1514     
1515     @Override
1516     public Object saveState(FacesContext facesContext)
1517     {
1518         if (getResetSaveStateMode() == RESET_MODE_SOFT)
1519         {
1520             // Clear view listeners.
1521             if (_systemEventListeners != null)
1522             {
1523                 _systemEventListeners.clear();
1524             }
1525             if (_events != null)
1526             {
1527                 _events.clear();
1528             }
1529             if (listenerSuccessMap != null)
1530             {
1531                 listenerSuccessMap.clear();
1532             }
1533             _restoreViewScopeStateCalled = false;
1534         }
1535         if (getResetSaveStateMode() == RESET_MODE_HARD)
1536         {
1537             // Clear view listeners.
1538             if (_systemEventListeners != null)
1539             {
1540                 _systemEventListeners.clear();
1541             }
1542             if (_events != null)
1543             {
1544                 _events.clear();
1545             }
1546             if (listenerSuccessMap != null)
1547             {
1548                 listenerSuccessMap.clear();
1549             }
1550             if (_viewScope != null)
1551             {
1552                 if (VIEW_SCOPE_PROXY_MAP_CLASS.isInstance(_viewScope))
1553                 {
1554                     _viewScope = null;
1555                 }
1556                 else
1557                 {
1558                     _viewScope.clear();
1559                 }
1560             }
1561             _restoreViewScopeStateCalled = false;
1562         }
1563         
1564         if (initialStateMarked())
1565         {
1566             Object parentSaved = super.saveState(facesContext);
1567             if (_viewScope != null && 
1568                 Boolean.TRUE.equals(facesContext.getAttributes().get(
1569                 SKIP_VIEW_MAP_SAVE_STATE)))
1570             {
1571                 if (parentSaved == null)
1572                 {
1573                     return null;
1574                 }
1575                 return new Object[]{parentSaved, null};
1576             }
1577             
1578             if (parentSaved == null && _viewScope == null)
1579             {
1580                 //No values
1581                 return null;
1582             }
1583             else if (parentSaved == null && _viewScope != null && _viewScope.isEmpty()
1584                 && !(_viewScope instanceof StateHolder) )
1585             {
1586                 //Empty view scope, no values
1587                 return null;
1588             }
1589             
1590             Object[] values = new Object[2];
1591             values[0] = parentSaved;
1592             values[1] = saveAttachedState(facesContext,_viewScope);
1593             return values;
1594         }
1595         else
1596         {
1597             if (_viewScope != null && 
1598                 Boolean.TRUE.equals(facesContext.getAttributes().get(
1599                 SKIP_VIEW_MAP_SAVE_STATE)))
1600             {
1601                 return new Object[]{super.saveState(facesContext), null};
1602             }
1603             Object[] values = new Object[2];
1604             values[0] = super.saveState(facesContext);
1605             values[1] = saveAttachedState(facesContext,_viewScope);
1606             return values;
1607         }
1608     }
1609 
1610     @SuppressWarnings("unchecked")
1611     @Override
1612     public void restoreState(FacesContext facesContext, Object state)
1613     {
1614         if (state == null)
1615         {
1616             return;
1617         }
1618         
1619         Object[] values = (Object[])state;
1620         super.restoreState(facesContext,values[0]);
1621         // JSF 2.2 spec says that restoreViewScopeState can be called but only if
1622         // StateManagementStrategy is used. If that's not the case (JSF 1.2 state saving),
1623         // restoreViewScopeState could not be called, so this code should avoid restore
1624         // the state twice.
1625         if (!_restoreViewScopeStateCalled)
1626         {
1627             _viewScope = (Map<String, Object>) restoreAttachedState(facesContext, values[1]);
1628         }
1629         else
1630         {
1631             _restoreViewScopeStateCalled = false;
1632         }
1633     }
1634     
1635     /**
1636      * @since 2.2
1637      * @param facesContext
1638      * @param state 
1639      */
1640     public void restoreViewScopeState(FacesContext facesContext, Object state)
1641     {
1642         if (state == null)
1643         {
1644             return;
1645         }
1646         //StateManagementStrategy says "... obtain the state of the UIViewRoot from the 
1647         // state Object returned from ResponseStateManager.getState(javax.faces.context.FacesContext,
1648         // java.lang.String) and pass that to UIViewRoot.restoreViewScopeState(
1649         // javax.faces.context.FacesContext, java.lang.Object).
1650         // Note restoreState() will be called later, and it will restore the view. If
1651         // we restore the component state here, later it could be a problem in the later
1652         // restoreState() call, because the initial state will not be the same.
1653         
1654         Object[] values = (Object[])state;
1655         _viewScope = (Map<String, Object>) restoreAttachedState(facesContext, values[1]);
1656         _restoreViewScopeStateCalled = true;
1657     }
1658     
1659     public List<SystemEventListener> getViewListenersForEventClass(Class<? extends SystemEvent> systemEvent)
1660     {
1661         checkNull (systemEvent, "systemEvent");
1662         if (_systemEventListeners == null)
1663         {
1664             return null;
1665         }
1666         return _systemEventListeners.get (systemEvent);
1667     }
1668     
1669     public void subscribeToViewEvent(Class<? extends SystemEvent> systemEvent,
1670             SystemEventListener listener)
1671     {
1672         List<SystemEventListener> listeners;
1673         
1674         checkNull (systemEvent, "systemEvent");
1675         checkNull (listener, "listener");
1676         
1677         if (_systemEventListeners == null)
1678         {
1679             _systemEventListeners = new HashMap<Class<? extends SystemEvent>, List<SystemEventListener>>();
1680         }
1681         
1682         listeners = _systemEventListeners.get (systemEvent);
1683         
1684         if (listeners == null)
1685         {
1686             listeners = new ArrayList<SystemEventListener>();
1687             
1688             _systemEventListeners.put (systemEvent, listeners);
1689         }
1690         
1691         listeners.add (listener);
1692     }
1693     
1694     public void unsubscribeFromViewEvent(Class<? extends SystemEvent> systemEvent,
1695             SystemEventListener listener)
1696     {
1697         List<SystemEventListener> listeners;
1698         
1699         checkNull (systemEvent, "systemEvent");
1700         checkNull (listener, "listener");
1701         
1702         if (_systemEventListeners == null)
1703         {
1704             return;
1705         }
1706         
1707         listeners = _systemEventListeners.get (systemEvent);
1708         
1709         if (listeners != null)
1710         {
1711             listeners.remove (listener);
1712         }
1713     }
1714 
1715     /**
1716      * Process the specified phase by calling PhaseListener.beforePhase for every phase listeners defined on this
1717      * view root, then calling the process method of the processor, broadcasting relevant events and finally
1718      * notifying the afterPhase method of every phase listeners registered on this view root.
1719      *
1720      * @param context
1721      * @param phaseId
1722      * @param processor
1723      * @param broadcast
1724      *
1725      * @return
1726      */
1727     private boolean _process(FacesContext context, PhaseId phaseId, PhaseProcessor processor)
1728     {
1729         RuntimeException processingException = null;
1730         try
1731         {
1732             if (!notifyListeners(context, phaseId, getBeforePhaseListener(), true))
1733             {
1734                 try
1735                 {
1736                     if (processor != null)
1737                     {
1738                         processor.process(context, this);
1739                     }
1740         
1741                     broadcastEvents(context, phaseId);
1742                 }
1743                 catch (RuntimeException re)
1744                 {
1745                     // catch any Exception that occures while processing the phase
1746                     // to ensure invocation of the afterPhase methods
1747                     processingException = re;
1748                 }
1749             }
1750         }
1751         finally
1752         {
1753             if (context.getRenderResponse() || context.getResponseComplete())
1754             {
1755                 clearEvents();
1756             }            
1757         }
1758 
1759         boolean retVal = notifyListeners(context, phaseId, getAfterPhaseListener(), false);
1760         if (processingException == null) 
1761         {
1762             return retVal;   
1763         }
1764         else
1765         {
1766             throw processingException;
1767         }
1768     }
1769 
1770     private void _processDecodesDefault(FacesContext context)
1771     {
1772         super.processDecodes(context);
1773     }
1774 
1775     private void _processUpdatesDefault(FacesContext context)
1776     {
1777         super.processUpdates(context);
1778     }
1779 
1780     private void _processValidatorsDefault(FacesContext context)
1781     {
1782         super.processValidators(context);
1783     }
1784 
1785     /**
1786      * Gathers all event for current and ANY phase
1787      * @param phaseId current phase id
1788      */
1789     private Events _getEvents(PhaseId phaseId)
1790     {
1791         // Gather the events and purge the event list to prevent concurrent modification during broadcasting
1792         int size = _events.size();
1793         List<FacesEvent> anyPhase = new ArrayList<FacesEvent>(size);
1794         List<FacesEvent> onPhase = new ArrayList<FacesEvent>(size);
1795         
1796         for (int i = 0; i < size; i++)
1797         {
1798             FacesEvent event = _events.get(i);
1799             if (event.getPhaseId().equals(PhaseId.ANY_PHASE))
1800             {
1801                 anyPhase.add(event);
1802                 _events.remove(i);
1803                 size--;
1804                 i--;
1805             }
1806             else if (event.getPhaseId().equals(phaseId))
1807             {
1808                 onPhase.add(event);
1809                 _events.remove(i);
1810                 size--;
1811                 i--;
1812             }
1813         }
1814         
1815         return new Events(anyPhase, onPhase);
1816     }
1817     
1818     private Logger _getLogger()
1819     {
1820         if (logger == null)
1821         {
1822             logger = Logger.getLogger(UIViewRoot.class.getName());
1823         }
1824         return logger;
1825     }
1826 
1827     private Map<PhaseId, boolean[]> _getListenerSuccessMap()
1828     {
1829         // lazy init: 
1830         if (listenerSuccessMap == null)
1831         {
1832             listenerSuccessMap = new HashMap<PhaseId, boolean[]>();
1833         }
1834         return listenerSuccessMap;
1835     }
1836 
1837     private static interface PhaseProcessor
1838     {
1839         public void process(FacesContext context, UIViewRoot root);
1840     }
1841 
1842     private static class ApplyRequestValuesPhaseProcessor implements PhaseProcessor
1843     {
1844         public void process(FacesContext context, UIViewRoot root)
1845         {
1846             PartialViewContext pvc = context.getPartialViewContext();
1847             // Perform partial processing by calling PartialViewContext.processPartial(javax.faces.event.PhaseId)
1848             // with PhaseId.UPDATE_MODEL_VALUES if:
1849             //   * PartialViewContext.isPartialRequest() returns true and we don't have a request to process all
1850             // components in the view (PartialViewContext.isExecuteAll() returns false)
1851             //section 13.4.2 from the  JSF2  spec also see https://issues.apache.org/jira/browse/MYFACES-2119
1852             if (pvc.isPartialRequest() && !pvc.isExecuteAll())
1853             {
1854                 pvc.processPartial(PhaseId.APPLY_REQUEST_VALUES);
1855             }
1856             // Perform full processing by calling UIComponentBase.processUpdates(javax.faces.context.FacesContext)
1857             // if one of the following conditions are met:
1858             // *   PartialViewContext.isPartialRequest() returns true and we have a request to process all components
1859             // in the view (PartialViewContext.isExecuteAll() returns true)
1860             // *   PartialViewContext.isPartialRequest() returns false
1861             else
1862             {
1863                 root._processDecodesDefault(context);
1864             }
1865         }
1866     }
1867 
1868     private static class ProcessValidatorPhaseProcessor implements PhaseProcessor
1869     {
1870         public void process(FacesContext context, UIViewRoot root)
1871         {
1872             PartialViewContext pvc = context.getPartialViewContext();
1873             // Perform partial processing by calling PartialViewContext.processPartial(javax.faces.event.PhaseId)
1874             // with PhaseId.UPDATE_MODEL_VALUES if:
1875             // PartialViewContext.isPartialRequest() returns true and we don't have a request to process all components
1876             // in the view (PartialViewContext.isExecuteAll() returns false)
1877             //section 13.4.2 from the  JSF2  spec also see https://issues.apache.org/jira/browse/MYFACES-2119
1878             if (pvc.isPartialRequest() && !pvc.isExecuteAll())
1879             {
1880                 pvc.processPartial(PhaseId.PROCESS_VALIDATIONS);
1881             }
1882             // Perform full processing by calling UIComponentBase.processUpdates(javax.faces.context.FacesContext)
1883             // if one of the following conditions are met:
1884             // *   PartialViewContext.isPartialRequest() returns true and we have a request to process all components
1885             // in the view (PartialViewContext.isExecuteAll() returns true)
1886             // *   PartialViewContext.isPartialRequest() returns false
1887             else
1888             {
1889                 root._processValidatorsDefault(context);
1890             }
1891         }
1892     }
1893 
1894     private static class UpdateModelPhaseProcessor implements PhaseProcessor
1895     {
1896         public void process(FacesContext context, UIViewRoot root)
1897         {
1898             PartialViewContext pvc = context.getPartialViewContext();
1899             // Perform partial processing by calling PartialViewContext.processPartial(javax.faces.event.PhaseId)
1900             // with PhaseId.UPDATE_MODEL_VALUES if:
1901             //   * PartialViewContext.isPartialRequest() returns true and we don't have a request to process
1902             // all components in the view (PartialViewContext.isExecuteAll() returns false)
1903             //section 13.4.2 from the JSF2 spec also see https://issues.apache.org/jira/browse/MYFACES-2119
1904             if (pvc.isPartialRequest() && !pvc.isExecuteAll())
1905             {
1906                 pvc.processPartial(PhaseId.UPDATE_MODEL_VALUES);
1907             }
1908             // Perform full processing by calling UIComponentBase.processUpdates(javax.faces.context.FacesContext)
1909             // if one of the following conditions are met:
1910             // *   PartialViewContext.isPartialRequest() returns true and we have a request to process all components
1911             // in the view (PartialViewContext.isExecuteAll() returns true)
1912             // *   PartialViewContext.isPartialRequest() returns false
1913             else
1914             {
1915                 root._processUpdatesDefault(context);
1916             }
1917         }
1918     }
1919 
1920 /*
1921     private static class RestoreStateCallback implements VisitCallback
1922     {
1923         private PostRestoreStateEvent event;
1924 
1925         public VisitResult visit(VisitContext context, UIComponent target)
1926         {
1927             if (event == null)
1928             {
1929                 event = new PostRestoreStateEvent(target);
1930             }
1931             else
1932             {
1933                 event.setComponent(target);
1934             }
1935 
1936             // call the processEvent method of the current component.
1937             // The argument event must be an instance of AfterRestoreStateEvent whose component
1938             // property is the current component in the traversal.
1939             target.processEvent(event);
1940             
1941             return VisitResult.ACCEPT;
1942         }
1943     }
1944 */
1945 
1946     // we cannot make this class a inner class, because the 
1947     // enclosing class (UIViewRoot) would also have to be serialized.
1948     /**
1949      * @deprecated replaced by org.apache.myfaces.view.ViewScopeProxyMap
1950      */
1951     @Deprecated
1952     private static class ViewScope extends HashMap<String, Object>
1953     {
1954         
1955         private static final long serialVersionUID = -1088893802269478164L;
1956         
1957         @Override
1958         public void clear()
1959         {
1960             /*
1961              * The returned Map must be implemented such that calling clear() on the Map causes
1962              * Application.publishEvent(java.lang.Class, java.lang.Object) to be called, passing
1963              * ViewMapDestroyedEvent.class as the first argument and this UIViewRoot instance as the second argument.
1964              */
1965             FacesContext facesContext = FacesContext.getCurrentInstance();
1966             facesContext.getApplication().publishEvent(facesContext, 
1967                     PreDestroyViewMapEvent.class, facesContext.getViewRoot());
1968             
1969             super.clear();
1970         }
1971         
1972     }
1973 
1974     /**
1975      * Agregates events for ANY_PHASE and current phase 
1976      */
1977     private static class Events
1978     {
1979         
1980         private final List<FacesEvent> _anyPhase;
1981         
1982         private final List<FacesEvent> _onPhase;
1983         
1984         public Events(List<FacesEvent> anyPhase, List<FacesEvent> onPhase)
1985         {
1986             super();
1987             this._anyPhase = anyPhase;
1988             this._onPhase = onPhase;
1989         }
1990 
1991         public boolean hasMoreEvents()
1992         {
1993             return (_anyPhase != null && _anyPhase.size() > 0) || (_onPhase != null && _onPhase.size() > 0); 
1994         }
1995 
1996         public List<FacesEvent> getAnyPhase()
1997         {
1998             return _anyPhase;
1999         }
2000 
2001         public List<FacesEvent> getOnPhase()
2002         {
2003             return _onPhase;
2004         }
2005     }
2006     
2007     private static class ResetValuesCallback implements VisitCallback
2008     {
2009         public VisitResult visit(VisitContext context, UIComponent target)
2010         {
2011             if (target instanceof EditableValueHolder)
2012             {
2013                 ((EditableValueHolder)target).resetValue();
2014             }
2015             return VisitResult.ACCEPT;
2016         }
2017     }
2018     
2019     private void publishException (FacesContext facesContext, Throwable e, PhaseId phaseId, String key)
2020     {
2021         ExceptionQueuedEventContext context = new ExceptionQueuedEventContext (facesContext, e, null, phaseId);
2022         
2023         context.getAttributes().put (key, Boolean.TRUE);
2024         
2025         facesContext.getApplication().publishEvent (facesContext, ExceptionQueuedEvent.class, context);
2026     }
2027     
2028     private boolean shouldViewRootPhaseListenerQueuesExceptions(FacesContext context)
2029     {
2030         ExternalContext ec = context.getExternalContext();
2031         Boolean alwaysPerformValidationWhenRequiredTrue = (Boolean) ec.getApplicationMap().get(
2032                 VIEWROOT_PHASE_LISTENER_QUEUES_EXCEPTIONS_PARAM_NAME);
2033 
2034         if (alwaysPerformValidationWhenRequiredTrue == null)
2035         {
2036              String param = ec.getInitParameter(VIEWROOT_PHASE_LISTENER_QUEUES_EXCEPTIONS_PARAM_NAME);
2037 
2038              // null means the same as auto.
2039              if (param == null)
2040              {
2041                  param = "false";
2042              }
2043              else
2044              {
2045                  // The environment variables are case insensitive.
2046                  param = param.toLowerCase();
2047              }
2048 
2049              if (param.equals("true"))
2050              {
2051                  alwaysPerformValidationWhenRequiredTrue = true;
2052              }
2053              else
2054              {
2055                  alwaysPerformValidationWhenRequiredTrue = false;
2056              }
2057 
2058              // cache the parsed value
2059              ec.getApplicationMap().put(VIEWROOT_PHASE_LISTENER_QUEUES_EXCEPTIONS_PARAM_NAME, 
2060                      alwaysPerformValidationWhenRequiredTrue);
2061         }
2062 
2063         return alwaysPerformValidationWhenRequiredTrue;
2064     }    
2065 }