Coverage Report - javax.faces.component.UIViewRoot
 
Classes in this File Line Coverage Branch Coverage Complexity
UIViewRoot
0%
0/352
0%
0/210
0
UIViewRoot$1
N/A
N/A
0
UIViewRoot$ApplyRequestValuesPhaseProcessor
0%
0/6
0%
0/4
0
UIViewRoot$PhaseProcessor
N/A
N/A
0
UIViewRoot$ProcessValidatorPhaseProcessor
0%
0/6
0%
0/4
0
UIViewRoot$PropertyKeys
0%
0/8
N/A
0
UIViewRoot$UpdateModelPhaseProcessor
0%
0/6
0%
0/4
0
UIViewRoot$ViewScope
0%
0/5
N/A
0
 
 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.util.ArrayList;
 23  
 import java.util.Arrays;
 24  
 import java.util.Collection;
 25  
 import java.util.Collections;
 26  
 import java.util.HashMap;
 27  
 import java.util.Iterator;
 28  
 import java.util.List;
 29  
 import java.util.Locale;
 30  
 import java.util.Map;
 31  
 import java.util.logging.Level;
 32  
 import java.util.logging.Logger;
 33  
 
 34  
 import javax.el.MethodExpression;
 35  
 import javax.el.ValueExpression;
 36  
 import javax.faces.FactoryFinder;
 37  
 import javax.faces.context.ExternalContext;
 38  
 import javax.faces.context.FacesContext;
 39  
 import javax.faces.context.PartialViewContext;
 40  
 import javax.faces.event.AbortProcessingException;
 41  
 import javax.faces.event.ExceptionQueuedEvent;
 42  
 import javax.faces.event.ExceptionQueuedEventContext;
 43  
 import javax.faces.event.FacesEvent;
 44  
 import javax.faces.event.PhaseEvent;
 45  
 import javax.faces.event.PhaseId;
 46  
 import javax.faces.event.PhaseListener;
 47  
 import javax.faces.event.PostConstructViewMapEvent;
 48  
 import javax.faces.event.PreDestroyViewMapEvent;
 49  
 import javax.faces.event.SystemEvent;
 50  
 import javax.faces.event.SystemEventListener;
 51  
 import javax.faces.lifecycle.Lifecycle;
 52  
 import javax.faces.lifecycle.LifecycleFactory;
 53  
 import javax.faces.view.ViewDeclarationLanguage;
 54  
 import javax.faces.view.ViewMetadata;
 55  
 import javax.faces.webapp.FacesServlet;
 56  
 
 57  
 import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFComponent;
 58  
 import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFJspProperty;
 59  
 import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFProperty;
 60  
 
 61  
 /**
 62  
  * Creates a JSF View, which is a container that holds all of the components that are part of the view.
 63  
  * <p>
 64  
  * Unless otherwise specified, all attributes accept static values or EL expressions.
 65  
  * </p>
 66  
  * <p>
 67  
  * See the javadoc for this class in the <a href="http://java.sun.com/j2ee/javaserverfaces/1.2/docs/api/index.html">JSF
 68  
  * Specification</a> for further details.
 69  
  * </p>
 70  
  */
 71  0
 @JSFComponent(name = "f:view", bodyContent = "JSP", tagClass = "org.apache.myfaces.taglib.core.ViewTag")
 72  
 @JSFJspProperty(name = "binding", returnType = "java.lang.String", tagExcluded = true)
 73  0
 public class UIViewRoot extends UIComponentBase implements UniqueIdVendor
 74  
 {
 75  
     public static final String COMPONENT_FAMILY = "javax.faces.ViewRoot";
 76  
     public static final String COMPONENT_TYPE = "javax.faces.ViewRoot";
 77  
     public static final String METADATA_FACET_NAME = "javax_faces_metadata";
 78  
     public static final String UNIQUE_ID_PREFIX = "j_id";
 79  
     public static final String VIEW_PARAMETERS_KEY = "javax.faces.component.VIEW_PARAMETERS_KEY";
 80  
 
 81  0
     private final Logger logger = Logger.getLogger(UIViewRoot.class.getName());
 82  
 
 83  0
     private static final PhaseProcessor APPLY_REQUEST_VALUES_PROCESSOR = new ApplyRequestValuesPhaseProcessor();
 84  0
     private static final PhaseProcessor PROCESS_VALIDATORS_PROCESSOR = new ProcessValidatorPhaseProcessor();
 85  0
     private static final PhaseProcessor UPDATE_MODEL_PROCESSOR = new UpdateModelPhaseProcessor();
 86  
 
 87  
     /**
 88  
      * The counter which will ensure a unique component id for every component instance in the tree that doesn't have an
 89  
      * id attribute set.
 90  
      */
 91  
     //private long _uniqueIdCounter = 0;
 92  
 
 93  
     // todo: is it right to save the state of _events and _phaseListeners?
 94  
     private List<FacesEvent> _events;
 95  
 
 96  
     /**
 97  
      * Map containing view scope objects. 
 98  
      * 
 99  
      * It is not expected this map hold PartialStateHolder instances,
 100  
      * so we can use saveAttachedState and restoreAttachedState methods.
 101  
      */
 102  
     private Map<String, Object> _viewScope;
 103  
 
 104  0
     private transient Lifecycle _lifecycle = null;
 105  
     
 106  
     private HashMap<Class<? extends SystemEvent>, List<SystemEventListener>> _systemEventListeners;
 107  
     
 108  
     // Tracks success in the beforePhase. Listeners that threw an exception
 109  
     // in beforePhase or were never called, because a previous listener threw
 110  
     // an exception, should not have their afterPhase method called
 111  0
     private transient Map<PhaseId, boolean[]> listenerSuccessMap = new HashMap<PhaseId, boolean[]>();
 112  
     
 113  
     private static final String JAVAX_FACES_LOCATION_PREFIX = "javax_faces_location_";
 114  
     private static final String JAVAX_FACES_LOCATION_HEAD = "javax_faces_location_head";
 115  
     private static final String JAVAX_FACES_LOCATION_BODY = "javax_faces_location_body";
 116  
     private static final String JAVAX_FACES_LOCATION_FORM = "javax_faces_location_form";
 117  
     
 118  
     /**
 119  
      * Construct an instance of the UIViewRoot.
 120  
      */
 121  
     public UIViewRoot()
 122  0
     {
 123  0
         setRendererType(null);
 124  
         
 125  0
         _systemEventListeners = new HashMap<Class<? extends SystemEvent>, List<SystemEventListener>>();
 126  0
     }
 127  
 
 128  
     /**
 129  
      * @since 2.0
 130  
      */
 131  
     public void addComponentResource(FacesContext context, UIComponent componentResource)
 132  
     {
 133  0
         addComponentResource(context, componentResource, null);
 134  0
     }
 135  
 
 136  
     /**
 137  
      * @since 2.0
 138  
      */
 139  
     public void addComponentResource(FacesContext context, UIComponent componentResource, String target)
 140  
     {
 141  
         // If the target argument is null
 142  0
         if (target == null)
 143  
         {
 144  
             // Look for a target attribute on the component
 145  0
             target = (String)componentResource.getAttributes().get("target");
 146  
 
 147  
             // If there is no target attribute, set target to be the default value head
 148  0
             if (target == null)
 149  
             {
 150  0
                 target = "head";
 151  
             }
 152  
         }
 153  
 
 154  
         // Call getComponentResources to obtain the child list for the given target
 155  0
         List<UIComponent> componentResources = _getComponentResources(context, target);
 156  
 
 157  
         // If the component ID of componentResource matches the ID of a resource that has already been added, remove the old resource.
 158  0
         String componentId = componentResource.getId();
 159  
         
 160  0
         if (componentId == null)
 161  
         {
 162  
             // componentResource can have no id - calling createUniqueId makes us sure that component will have one
 163  
             // https://issues.apache.org/jira/browse/MYFACES-2775
 164  0
             componentId = createUniqueId(context, null);
 165  0
             componentResource.setId(componentId);
 166  
         }
 167  
         
 168  
         // This var helps to handle the case when we try to add a component that already is
 169  
         // on the resource list, because PostAddToViewEvent also is sent to components 
 170  
         // backing resources. The problem start when a component is already inside
 171  
         // componentResources list and we try to relocate it again. This leads to a StackOverflowException
 172  
         // so we need to check if a component is and prevent remove and add it again. Note
 173  
         // that remove and then add a component trigger another PostAddToViewEvent. The right
 174  
         // point to prevent this StackOverflowException is here, because this method is 
 175  
         // responsible to traverse the componentResources list and add when necessary.
 176  0
         boolean alreadyAdded = false;
 177  
 
 178  
         //The check is only necessary if the component resource is part of the tree.
 179  0
         if (componentResource.isInView())
 180  
         {
 181  0
             if (componentResource.getParent() != null &&
 182  
                 componentResource.getParent().getId() != null &&
 183  
                 componentResource.getParent().getId().startsWith(JAVAX_FACES_LOCATION_PREFIX))
 184  
             {
 185  
                 // We can assume safely that the component is in place, because there is no way to 
 186  
                 // put a component resource on a component resource container without call addComponentResource
 187  
                 // so relocation here will not happen.
 188  0
                 alreadyAdded = true;
 189  
             }
 190  0
             else if (componentId != null)
 191  
             {
 192  0
                 for(Iterator<UIComponent> it = componentResources.iterator(); it.hasNext();)
 193  
                 {
 194  0
                     UIComponent component = it.next();
 195  0
                     if(componentId.equals(component.getId()) && componentResource != component)
 196  
                     {
 197  0
                         it.remove();
 198  
                     }
 199  0
                     else if (componentResource == component)
 200  
                     {
 201  0
                         alreadyAdded = true;
 202  
                     }
 203  0
                 }
 204  
             }
 205  
         }
 206  
         
 207  
         // Add the component resource to the list
 208  0
         if (!alreadyAdded)
 209  
         {
 210  0
             componentResources.add(componentResource);
 211  
         }
 212  0
     }
 213  
 
 214  
     /**
 215  
      * Adds a The phaseListeners attached to ViewRoot.
 216  
      */
 217  
     public void addPhaseListener(PhaseListener phaseListener)
 218  
     {
 219  0
         if (phaseListener == null)
 220  0
             throw new NullPointerException("phaseListener");
 221  
         
 222  0
         getStateHelper().add(PropertyKeys.phaseListeners, phaseListener);
 223  0
     }
 224  
 
 225  
     /**
 226  
      * @since 2.0
 227  
      */
 228  
     public void broadcastEvents(FacesContext context, PhaseId phaseId)
 229  
     {
 230  0
         if (_events == null)
 231  
         {
 232  0
             return;
 233  
         }
 234  
 
 235  
         // Gather the events and purge the event list to prevent concurrent modification during broadcasting
 236  0
         List<FacesEvent> anyPhase = new ArrayList<FacesEvent>(_events.size());
 237  0
         List<FacesEvent> onPhase = new ArrayList<FacesEvent>(_events.size());
 238  0
         for (Iterator<FacesEvent> iterator = _events.iterator(); iterator.hasNext();)
 239  
         {
 240  0
             FacesEvent event = iterator.next();
 241  0
             if (event.getPhaseId().equals(PhaseId.ANY_PHASE))
 242  
             {
 243  0
                 anyPhase.add(event);
 244  0
                 iterator.remove();
 245  
             }
 246  0
             else if (event.getPhaseId().equals(phaseId))
 247  
             {
 248  0
                 onPhase.add(event);
 249  0
                 iterator.remove();
 250  
             }
 251  0
         }
 252  
 
 253  
         // First broadcast events that have been queued for PhaseId.ANY_PHASE.
 254  0
         if (_broadcastAll(context, anyPhase))
 255  
         {
 256  0
             _broadcastAll(context, onPhase);
 257  
         }
 258  0
     }
 259  
 
 260  
     /**
 261  
      * Provides a unique id for this component instance.
 262  
      */
 263  
     public String createUniqueId()
 264  
     {
 265  0
         return createUniqueId(getFacesContext(), null);
 266  
     }
 267  
 
 268  
     /**
 269  
      * 
 270  
      * {@inheritDoc}
 271  
      * 
 272  
      * @since 2.0
 273  
      */
 274  
     public String createUniqueId(FacesContext context, String seed)
 275  
     {
 276  0
         ExternalContext extCtx = context.getExternalContext();
 277  0
         StringBuilder bld = __getSharedStringBuilder();
 278  
 
 279  0
         Long uniqueIdCounter = (Long) getStateHelper().get(PropertyKeys.uniqueIdCounter);
 280  0
         uniqueIdCounter = (uniqueIdCounter == null) ? 0 : uniqueIdCounter;
 281  0
         getStateHelper().put(PropertyKeys.uniqueIdCounter, (uniqueIdCounter+1L));
 282  
         // Generate an identifier for a component. The identifier will be prefixed with UNIQUE_ID_PREFIX, and will be unique within this UIViewRoot. 
 283  0
         if(seed==null)
 284  
         {
 285  0
             return extCtx.encodeNamespace(bld.append(UNIQUE_ID_PREFIX).append(uniqueIdCounter).toString());    
 286  
         }
 287  
         // Optionally, a unique seed value can be supplied by component creators which should be included in the generated unique id.
 288  
         else
 289  
         {
 290  0
             return extCtx.encodeNamespace(bld.append(UNIQUE_ID_PREFIX).append(seed).toString());
 291  
         }
 292  
     }
 293  
 
 294  
     @Override
 295  
     public void encodeBegin(FacesContext context) throws IOException
 296  
     {
 297  0
         checkNull(context, "context");
 298  
 
 299  0
         boolean skipPhase = false;
 300  
 
 301  
         try
 302  
         {
 303  0
             skipPhase = notifyListeners(context, PhaseId.RENDER_RESPONSE, getBeforePhaseListener(), true);
 304  
         }
 305  0
         catch (Exception e)
 306  
         {
 307  
             // following the spec we have to swallow the exception
 308  0
             logger.log(Level.SEVERE, "Exception while processing phase listener: " + e.getMessage(), e);
 309  0
         }
 310  
 
 311  0
         if (!skipPhase)
 312  
         {
 313  
             //prerendering happens, we now publish the prerender view event
 314  
             //the specs states that the viewroot as source is about to be rendered
 315  
             //hence we issue the event immediately before publish, if the phase is not skipped
 316  
             //context.getApplication().publishEvent(context, PreRenderViewEvent.class, this);
 317  
             //then the view rendering is about to begin
 318  0
             super.encodeBegin(context);
 319  
         }
 320  
         else
 321  
         {
 322  0
             pushComponentToEL(context, this);
 323  
         }
 324  0
     }
 325  
 
 326  
     /**
 327  
      * @since 2.0
 328  
      */
 329  
     @Override
 330  
     public void encodeChildren(FacesContext context) throws IOException
 331  
     {
 332  0
         if (context.getResponseComplete())
 333  
         {
 334  0
             return;
 335  
         }
 336  0
         PartialViewContext pContext = context.getPartialViewContext();
 337  
         
 338  
         // If PartialViewContext.isAjaxRequest() returns true
 339  0
         if (pContext.isAjaxRequest())
 340  
         {
 341  
             // Perform partial rendering by calling PartialViewContext.processPartial() with PhaseId.RENDER_RESPONSE.
 342  
             //sectin 13.4.3 of the jsf2 specification
 343  0
             pContext.processPartial(PhaseId.RENDER_RESPONSE);
 344  
         }
 345  
         else
 346  
         {
 347  
             // If PartialViewContext.isAjaxRequest() returns false
 348  
             // delegate to super.encodeChildren(javax.faces.context.FacesContext) method.
 349  0
             super.encodeChildren(context);
 350  
         }
 351  0
     }
 352  
 
 353  
     @Override
 354  
     public void encodeEnd(FacesContext context) throws IOException
 355  
     {
 356  0
         checkNull(context, "context");
 357  
 
 358  0
         if (!context.getResponseComplete())
 359  
         {
 360  0
             super.encodeEnd(context);
 361  
             
 362  
             // the call to encodeAll() on every UIViewParameter here is only necessary
 363  
             // if the current request is _not_ an AJAX request, because if it was an
 364  
             // AJAX request, the call would already have happened in PartialViewContextImpl and
 365  
             // would anyway be too late here, because the state would already have been generated
 366  0
             PartialViewContext partialContext = context.getPartialViewContext();
 367  0
             if (!partialContext.isAjaxRequest())
 368  
             {
 369  0
                 ViewDeclarationLanguage vdl = context.getApplication().getViewHandler().getViewDeclarationLanguage(context, getViewId());
 370  0
                 if (vdl != null)
 371  
                 {
 372  
                     // If the current view has view parameters, as indicated by a non-empty and non-UnsupportedOperationException throwing 
 373  
                     // return from ViewDeclarationLanguage.getViewMetadata(javax.faces.context.FacesContext, String)
 374  0
                     ViewMetadata metadata = null;
 375  
                     try
 376  
                     {
 377  0
                         metadata = vdl.getViewMetadata(context, getViewId());    
 378  
                     }
 379  0
                     catch(UnsupportedOperationException e)
 380  
                     {
 381  0
                         logger.log(Level.SEVERE, "Exception while obtaining the view metadata: " + e.getMessage(), e);
 382  0
                     }
 383  
                     
 384  0
                     if (metadata != null)
 385  
                     {
 386  
                         try
 387  
                         {
 388  0
                             Collection<UIViewParameter> viewParams = ViewMetadata.getViewParameters(this);    
 389  0
                             if(!viewParams.isEmpty())
 390  
                             {
 391  
                                 // call UIViewParameter.encodeAll(javax.faces.context.FacesContext) on each parameter.
 392  0
                                 for(UIViewParameter param : viewParams)
 393  
                                 {
 394  0
                                     param.encodeAll(context);
 395  
                                 }
 396  
                             }
 397  
                         }
 398  0
                         catch(UnsupportedOperationException e)
 399  
                         {
 400  
                             // If calling getViewParameters() causes UnsupportedOperationException to be thrown, the exception must be silently swallowed.
 401  0
                         }
 402  
                     }
 403  
                 }
 404  
             }
 405  
         }
 406  
         
 407  
         try
 408  
         {
 409  0
             notifyListeners(context, PhaseId.RENDER_RESPONSE, getAfterPhaseListener(), false);
 410  
         }
 411  0
         catch (Exception e)
 412  
         {
 413  
             // following the spec we have to swallow the exception
 414  0
             logger.log(Level.SEVERE, "Exception while processing phase listener: " + e.getMessage(), e);
 415  0
         }
 416  0
     }
 417  
 
 418  
     /**
 419  
      * MethodBinding pointing to a method that takes a javax.faces.event.PhaseEvent and returns void, called after every
 420  
      * phase except for restore view.
 421  
      *
 422  
      * @return the new afterPhaseListener value
 423  
      */
 424  
     @JSFProperty(returnSignature = "void", methodSignature = "javax.faces.event.PhaseEvent", jspName = "afterPhase", stateHolder=true)
 425  
     public MethodExpression getAfterPhaseListener()
 426  
     {
 427  0
         return (MethodExpression) getStateHelper().eval(PropertyKeys.afterPhaseListener);
 428  
     }
 429  
 
 430  
     /**
 431  
      * MethodBinding pointing to a method that takes a javax.faces.event.PhaseEvent and returns void, called before
 432  
      * every phase except for restore view.
 433  
      *
 434  
      * @return the new beforePhaseListener value
 435  
      */
 436  
     @JSFProperty(returnSignature = "void", methodSignature = "javax.faces.event.PhaseEvent", jspName = "beforePhase", stateHolder=true)
 437  
     public MethodExpression getBeforePhaseListener()
 438  
     {
 439  0
         return (MethodExpression) getStateHelper().eval(PropertyKeys.beforePhaseListener);
 440  
     }
 441  
 
 442  
     /**
 443  
      * DO NOT USE.
 444  
      * <p>
 445  
      * As this component has no "id" property, it has no clientId property either.
 446  
      */
 447  
     @Override
 448  
     public String getClientId(FacesContext context)
 449  
     {
 450  0
         return super.getClientId(context);
 451  
         // Call parent method due to TCK problems
 452  
         // return null;
 453  
     }
 454  
 
 455  
     /**
 456  
      * @since 2.0
 457  
      */
 458  
     public List<UIComponent> getComponentResources(FacesContext context, String target)
 459  
     {
 460  
         // Locate the facet for the component by calling getFacet() using target as the argument
 461  0
         UIComponent facet = getFacet(target);
 462  
 
 463  
         /*
 464  
         // If the facet is not found,
 465  
         if (facet == null)
 466  
         {
 467  
             // create the facet by calling context.getApplication().createComponent()  using javax.faces.Panel as the argument
 468  
             facet = context.getApplication().createComponent("javax.faces.Panel");
 469  
 
 470  
             // Set the id of the facet to be target
 471  
             facet.setId(target);
 472  
 
 473  
             // Add the facet to the facets Map using target as the key
 474  
             getFacets().put(target, facet);
 475  
         }
 476  
 
 477  
         // Return the children of the facet
 478  
         // The API doc indicates that this method should "Return an unmodifiable List of UIComponents for the provided target argument."
 479  
         // and also that "If no children are found for the facet, return Collections.emptyList()."
 480  
         List<UIComponent> children = facet.getChildren();
 481  
         return ( children == null ? Collections.<UIComponent>emptyList() : Collections.unmodifiableList(children) );
 482  
         */
 483  0
         if (facet != null)
 484  
         {
 485  0
             List<UIComponent> children = facet.getChildren();
 486  0
             return ( children == null ? Collections.<UIComponent>emptyList() : Collections.unmodifiableList(children) );
 487  
         }
 488  0
         return Collections.<UIComponent>emptyList();
 489  
     }
 490  
     
 491  
     private List<UIComponent> _getComponentResources(FacesContext context, String target)
 492  
     {
 493  
         // Locate the facet for the component by calling getFacet() using target as the argument
 494  0
         UIComponent facet = getFacet(target);
 495  
 
 496  
         // If the facet is not found,
 497  0
         if (facet == null)
 498  
         {
 499  
             // create the facet by calling context.getApplication().createComponent()  using javax.faces.Panel as the argument
 500  0
             facet = context.getApplication().createComponent("javax.faces.ComponentResourceContainer");
 501  
 
 502  
             // Set the id of the facet to be target
 503  0
             if (target.equals("head"))
 504  
             {
 505  0
                 facet.setId(JAVAX_FACES_LOCATION_HEAD);
 506  
             }
 507  0
             else if (target.equals("body"))
 508  
             {
 509  0
                 facet.setId(JAVAX_FACES_LOCATION_BODY);
 510  
             }
 511  0
             else if (target.equals("form"))
 512  
             {
 513  0
                 facet.setId(JAVAX_FACES_LOCATION_FORM);
 514  
             }
 515  
             else
 516  
             {
 517  0
                 facet.setId(JAVAX_FACES_LOCATION_PREFIX + target);
 518  
             }
 519  
             
 520  
             // From jsr-314-open list it was made clear this facet is transient,
 521  
             // because all component resources does not change its inner state between
 522  
             // requests
 523  0
             facet.setTransient(true);
 524  
 
 525  
             // Add the facet to the facets Map using target as the key
 526  0
             getFacets().put(target, facet);
 527  
         }
 528  0
         return facet.getChildren();
 529  
     }
 530  
 
 531  
     @Override
 532  
     public String getFamily()
 533  
     {
 534  0
         return COMPONENT_FAMILY;
 535  
     }
 536  
 
 537  
     /**
 538  
      * The locale for this view.
 539  
      * <p>
 540  
      * Defaults to the default locale specified in the faces configuration file.
 541  
      * </p>
 542  
      */
 543  
     @JSFProperty
 544  
     public Locale getLocale()
 545  
     {
 546  0
         Object locale = getStateHelper().get(PropertyKeys.locale);
 547  0
         if (locale != null)
 548  
         {
 549  0
             return (Locale)locale;
 550  
         }
 551  0
         ValueExpression expression = getValueExpression(PropertyKeys.locale.toString());
 552  0
         if (expression != null)
 553  
         {
 554  0
             return (Locale)expression.getValue(getFacesContext().getELContext());
 555  
         }
 556  
         else
 557  
         {
 558  0
             locale = getFacesContext().getApplication().getViewHandler().calculateLocale(getFacesContext());
 559  
 
 560  0
             if (locale instanceof Locale)
 561  
             {
 562  0
                 return (Locale)locale;
 563  
             }
 564  0
             else if (locale instanceof String)
 565  
             {
 566  0
                 return stringToLocale((String)locale);
 567  
             }
 568  
         }
 569  
 
 570  0
         return getFacesContext().getApplication().getViewHandler().calculateLocale(getFacesContext());
 571  
     }
 572  
 
 573  
     /**
 574  
      * @since 2.0
 575  
      */
 576  
     public List<PhaseListener> getPhaseListeners()
 577  
     {
 578  0
         List<PhaseListener> listeners = (List<PhaseListener>) getStateHelper().get(PropertyKeys.phaseListeners);
 579  0
         if (listeners == null)
 580  
         {
 581  0
             listeners = Collections.emptyList();
 582  
         }
 583  
         else
 584  
         {
 585  0
             listeners = Collections.unmodifiableList(listeners);
 586  
         }
 587  
 
 588  0
         return listeners;
 589  
     }
 590  
 
 591  
     /**
 592  
      * Defines what renderkit should be used to render this view.
 593  
      */
 594  
     @JSFProperty
 595  
     public String getRenderKitId()
 596  
     {
 597  0
         return (String) getStateHelper().eval(PropertyKeys.renderKitId);
 598  
     }
 599  
 
 600  
     /**
 601  
      * @since 2.0
 602  
      */
 603  
     @Override
 604  
     public boolean getRendersChildren()
 605  
     {
 606  
         // Call UIComponentBase.getRendersChildren() 
 607  
         // If PartialViewContext.isAjaxRequest()  returns true this method must return true.
 608  0
         PartialViewContext context = getFacesContext().getPartialViewContext();
 609  
 
 610  0
         return (context.isAjaxRequest()) ? true : super.getRendersChildren();
 611  
     }
 612  
 
 613  
     /**
 614  
      * A unique identifier for the "template" from which this view was generated.
 615  
      * <p>
 616  
      * Typically this is the filesystem path to the template file, but the exact details are the responsibility of the
 617  
      * current ViewHandler implementation.
 618  
      */
 619  
     @JSFProperty(tagExcluded = true)
 620  
     public String getViewId()
 621  
     {
 622  0
         return (String) getStateHelper().eval(PropertyKeys.viewId);
 623  
     }
 624  
 
 625  
     /**
 626  
      * @since 2.0
 627  
      */
 628  
     public Map<String, Object> getViewMap()
 629  
     {
 630  0
         return this.getViewMap(true);
 631  
     }
 632  
 
 633  
     /**
 634  
      * @since 2.0
 635  
      */
 636  
     public Map<String, Object> getViewMap(boolean create)
 637  
     {
 638  0
         if (_viewScope == null && create)
 639  
         {
 640  0
             _viewScope = new ViewScope();
 641  0
             FacesContext facesContext = getFacesContext();
 642  0
             facesContext.getApplication().publishEvent(facesContext, PostConstructViewMapEvent.class, this);
 643  
         }
 644  
 
 645  0
         return _viewScope;
 646  
     }
 647  
     
 648  
     /**
 649  
      * {@inheritDoc}
 650  
      */
 651  
     @Override
 652  
     public boolean isInView()
 653  
     {
 654  0
         return true;
 655  
     }
 656  
 
 657  
     public void processApplication(final FacesContext context)
 658  
     {
 659  0
         checkNull(context, "context");
 660  0
         _process(context, PhaseId.INVOKE_APPLICATION, null);
 661  0
     }
 662  
 
 663  
     @Override
 664  
     public void processDecodes(FacesContext context)
 665  
     {
 666  0
         checkNull(context, "context");
 667  0
         _process(context, PhaseId.APPLY_REQUEST_VALUES, APPLY_REQUEST_VALUES_PROCESSOR);
 668  0
     }
 669  
 
 670  
     /**
 671  
      * @since 2.0
 672  
      */
 673  
     @Override
 674  
     public void processRestoreState(FacesContext context, Object state)
 675  
     {
 676  
         // The default implementation must call UIComponentBase.processRestoreState(javax.faces.context.FacesContext,
 677  
         // java.lang.Object) from within a try block.
 678  
         try
 679  
         {
 680  0
             super.processRestoreState(context, state);
 681  
         }
 682  
         finally
 683  
         {
 684  
             // The try block must have a finally block that ensures that no FacesEvents remain in the event queue
 685  0
             broadcastEvents(context, PhaseId.RESTORE_VIEW);
 686  
 
 687  
             //visitTree(VisitContext.createVisitContext(context), new RestoreStateCallback());
 688  0
         }
 689  0
     }
 690  
 
 691  
     @Override
 692  
     public void queueEvent(FacesEvent event)
 693  
     {
 694  0
         checkNull(event, "event");
 695  0
         if (_events == null)
 696  
         {
 697  0
             _events = new ArrayList<FacesEvent>();
 698  
         }
 699  
 
 700  0
         _events.add(event);
 701  0
     }
 702  
 
 703  
     @Override
 704  
     public void processValidators(FacesContext context)
 705  
     {
 706  0
         checkNull(context, "context");
 707  0
         _process(context, PhaseId.PROCESS_VALIDATIONS, PROCESS_VALIDATORS_PROCESSOR);
 708  0
     }
 709  
 
 710  
     @Override
 711  
     public void processUpdates(FacesContext context)
 712  
     {
 713  0
         checkNull(context, "context");
 714  0
         _process(context, PhaseId.UPDATE_MODEL_VALUES, UPDATE_MODEL_PROCESSOR);
 715  0
     }
 716  
 
 717  
     public void setLocale(Locale locale)
 718  
     {
 719  0
         getStateHelper().put(PropertyKeys.locale, locale );
 720  0
     }
 721  
 
 722  
     /**
 723  
      * Invoke view-specific phase listeners, plus an optional EL MethodExpression.
 724  
      * <p>
 725  
      * JSF1.2 adds the ability for PhaseListener objects to be added to a UIViewRoot instance, and for
 726  
      * "beforePhaseListener" and "afterPhaseListener" EL expressions to be defined on the viewroot. This method is
 727  
      * expected to be called at appropriate times, and will then execute the relevant listener callbacks.
 728  
      * <p>
 729  
      * Parameter "listener" may be null. If not null, then it is an EL expression pointing to a user method that will be
 730  
      * invoked.
 731  
      * <p>
 732  
      * Note that the global PhaseListeners are invoked via the Lifecycle implementation, not from this method here.
 733  
      * <p>
 734  
      * These PhaseListeners are processed with the same rules as the globally defined PhaseListeners, except
 735  
      * that any Exceptions, which may occur during the execution of the PhaseListeners, will only be logged
 736  
      * and not published to the ExceptionHandler.
 737  
      */
 738  
     private boolean notifyListeners(FacesContext context, PhaseId phaseId, MethodExpression listener,
 739  
                                     boolean beforePhase)
 740  
     {
 741  0
         List<PhaseListener> phaseListeners = (List<PhaseListener>) getStateHelper().get(PropertyKeys.phaseListeners);
 742  0
         if (listener != null || (phaseListeners != null && !phaseListeners.isEmpty()))
 743  
         {
 744  
             // how many listeners do we have? (the MethodExpression listener is counted in either way)
 745  
             // NOTE: beforePhaseSuccess[0] always refers to the MethodExpression listener
 746  0
             int listenerCount = (phaseListeners != null ? phaseListeners.size() + 1 : 1);
 747  
             
 748  
             boolean[] beforePhaseSuccess;
 749  0
             if (beforePhase)
 750  
             {
 751  0
                 beforePhaseSuccess = new boolean[listenerCount];
 752  0
                 listenerSuccessMap.put(phaseId, beforePhaseSuccess);
 753  
             }
 754  
             else {
 755  
                 // afterPhase - get beforePhaseSuccess from the Map
 756  0
                 beforePhaseSuccess = listenerSuccessMap.get(phaseId);
 757  0
                 if (beforePhaseSuccess == null)
 758  
                 {
 759  
                     // no Map available - assume that everything went well
 760  0
                     beforePhaseSuccess = new boolean[listenerCount];
 761  0
                     Arrays.fill(beforePhaseSuccess, true);
 762  
                 }
 763  
             }
 764  
             
 765  0
             PhaseEvent event = createEvent(context, phaseId);
 766  
 
 767  
             // only invoke the listener if we are in beforePhase
 768  
             // or if the related before PhaseListener finished without an Exception
 769  0
             if (listener != null && (beforePhase || beforePhaseSuccess[0]))
 770  
             {
 771  
                 try
 772  
                 {
 773  0
                     listener.invoke(context.getELContext(), new Object[] { event });
 774  0
                     beforePhaseSuccess[0] = true;
 775  
                 }
 776  0
                 catch (Throwable t) 
 777  
                 {
 778  0
                     beforePhaseSuccess[0] = false; // redundant - for clarity
 779  0
                     logger.log(Level.SEVERE, "An Exception occured while processing " +
 780  
                                              listener.getExpressionString() + 
 781  
                                              " in Phase " + phaseId, t);
 782  0
                     if (beforePhase)
 783  
                     {
 784  0
                         return context.getResponseComplete() || (context.getRenderResponse() && !PhaseId.RENDER_RESPONSE.equals(phaseId));
 785  
                     }
 786  0
                 }
 787  
             }
 788  0
             else if (beforePhase)
 789  
             {
 790  
                 // there is no beforePhase MethodExpression listener
 791  0
                 beforePhaseSuccess[0] = true;
 792  
             }
 793  
 
 794  0
             if (phaseListeners != null && !phaseListeners.isEmpty())
 795  
             {
 796  0
                 if (beforePhase)
 797  
                 {
 798  
                     // process listeners in ascending order
 799  0
                     for (int i = 0; i < beforePhaseSuccess.length - 1; i++)
 800  
                     {
 801  
                         PhaseListener phaseListener;
 802  
                         try 
 803  
                         {
 804  0
                             phaseListener = phaseListeners.get(i);
 805  
                         }
 806  0
                         catch (IndexOutOfBoundsException e)
 807  
                         {
 808  
                             // happens when a PhaseListener removes another PhaseListener 
 809  
                             // from UIViewRoot in its beforePhase method
 810  0
                             throw new IllegalStateException("A PhaseListener must not remove " +
 811  
                                     "PhaseListeners from UIViewRoot.");
 812  0
                         }
 813  0
                         PhaseId listenerPhaseId = phaseListener.getPhaseId();
 814  0
                         if (phaseId.equals(listenerPhaseId) || PhaseId.ANY_PHASE.equals(listenerPhaseId))
 815  
                         {
 816  
                             try
 817  
                             {
 818  0
                                 phaseListener.beforePhase(event);
 819  0
                                 beforePhaseSuccess[i + 1] = true;
 820  
                             }
 821  0
                             catch (Throwable t) 
 822  
                             {
 823  0
                                 beforePhaseSuccess[i + 1] = false; // redundant - for clarity
 824  0
                                 logger.log(Level.SEVERE, "An Exception occured while processing the " +
 825  
                                                          "beforePhase method of PhaseListener " + phaseListener +
 826  
                                                          " in Phase " + phaseId, t);
 827  0
                                 return context.getResponseComplete() || (context.getRenderResponse() && !PhaseId.RENDER_RESPONSE.equals(phaseId));
 828  0
                             }
 829  
                         }
 830  
                     }
 831  
                 }
 832  
                 else
 833  
                 {
 834  
                     // afterPhase
 835  
                     // process listeners in descending order
 836  0
                     for (int i = beforePhaseSuccess.length - 1; i > 0; i--)
 837  
                     {
 838  
                         PhaseListener phaseListener;
 839  
                         try 
 840  
                         {
 841  0
                             phaseListener = phaseListeners.get(i - 1);
 842  
                         }
 843  0
                         catch (IndexOutOfBoundsException e)
 844  
                         {
 845  
                             // happens when a PhaseListener removes another PhaseListener 
 846  
                             // from UIViewRoot in its beforePhase or afterPhase method
 847  0
                             throw new IllegalStateException("A PhaseListener must not remove " +
 848  
                                     "PhaseListeners from UIViewRoot.");
 849  0
                         }
 850  0
                         PhaseId listenerPhaseId = phaseListener.getPhaseId();
 851  0
                         if ((phaseId.equals(listenerPhaseId) || PhaseId.ANY_PHASE.equals(listenerPhaseId))
 852  
                                 && beforePhaseSuccess[i])
 853  
                         {
 854  
                             try
 855  
                             {
 856  0
                                 phaseListener.afterPhase(event);
 857  
                             }
 858  0
                             catch (Throwable t) 
 859  
                             {
 860  0
                                 logger.log(Level.SEVERE, "An Exception occured while processing the " +
 861  
                                                          "afterPhase method of PhaseListener " + phaseListener +
 862  
                                                          " in Phase " + phaseId, t);
 863  0
                             }
 864  
                         }
 865  
                     }
 866  
                 }
 867  
             }
 868  
         }
 869  
 
 870  0
         if (beforePhase)
 871  
         {
 872  0
             return context.getResponseComplete() || (context.getRenderResponse() && !PhaseId.RENDER_RESPONSE.equals(phaseId));
 873  
         }
 874  
         else
 875  
         {
 876  0
             return context.getResponseComplete() || context.getRenderResponse();
 877  
         }
 878  
     }
 879  
 
 880  
     private PhaseEvent createEvent(FacesContext context, PhaseId phaseId)
 881  
     {
 882  0
         if (_lifecycle == null)
 883  
         {
 884  0
             LifecycleFactory factory = (LifecycleFactory)FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY);
 885  0
             String id = context.getExternalContext().getInitParameter(FacesServlet.LIFECYCLE_ID_ATTR);
 886  0
             if (id == null)
 887  
             {
 888  0
                 id = LifecycleFactory.DEFAULT_LIFECYCLE;
 889  
             }
 890  0
             _lifecycle = factory.getLifecycle(id);
 891  
         }
 892  0
         return new PhaseEvent(context, phaseId, _lifecycle);
 893  
     }
 894  
 
 895  
     /**
 896  
      * Broadcast all events in the specified collection, stopping the at any time an AbortProcessingException
 897  
      * is thrown.
 898  
      *
 899  
      * @param context the current JSF context
 900  
      * @param events the events to broadcast
 901  
      *
 902  
      * @return <code>true</code> if the broadcast was completed without abortion, <code>false</code> otherwise
 903  
      */
 904  
     private boolean _broadcastAll(FacesContext context, Collection<? extends FacesEvent> events)
 905  
     {
 906  0
         assert events != null;
 907  
 
 908  0
         for (FacesEvent event : events)
 909  
         {
 910  0
             UIComponent source = event.getComponent();
 911  0
             UIComponent compositeParent = UIComponent.getCompositeComponentParent(source);
 912  0
             if (compositeParent != null)
 913  
             {
 914  0
                 pushComponentToEL(context, compositeParent);
 915  
             }
 916  
             // Push the source as the current component
 917  0
             pushComponentToEL(context, source);
 918  
 
 919  
             try
 920  
             {
 921  
                 // Actual event broadcasting
 922  0
                 source.broadcast(event);
 923  
             }
 924  0
             catch (AbortProcessingException e)
 925  
             {
 926  
                 // publish the Exception to be handled by the ExceptionHandler
 927  0
                 ExceptionQueuedEventContext exceptionContext 
 928  
                         = new ExceptionQueuedEventContext(context, e, source, context.getCurrentPhaseId());
 929  0
                 context.getApplication().publishEvent(context, ExceptionQueuedEvent.class, exceptionContext);
 930  
                 
 931  
                 // Abortion
 932  0
                 return false;
 933  
             }
 934  
             finally
 935  
             {
 936  
                 // Restore the current component
 937  0
                 popComponentFromEL(context);
 938  0
                 if (compositeParent != null)
 939  
                 {
 940  0
                     popComponentFromEL(context);
 941  
                 }
 942  
             }
 943  0
         }
 944  
 
 945  0
         return true;
 946  
     }
 947  
 
 948  
     private void clearEvents()
 949  
     {
 950  0
         _events = null;
 951  0
     }
 952  
 
 953  
     private void checkNull(Object value, String valueLabel)
 954  
     {
 955  0
         if (value == null)
 956  
         {
 957  0
             throw new NullPointerException(valueLabel + " is null");
 958  
         }
 959  0
     }
 960  
 
 961  
     private Locale stringToLocale(String localeStr)
 962  
     {
 963  
         // locale expr: \[a-z]{2}((-|_)[A-Z]{2})?
 964  
 
 965  0
         if (localeStr.contains("_") || localeStr.contains("-"))
 966  
         {
 967  0
             if (localeStr.length() == 2)
 968  
             {
 969  
                 // localeStr is the lang
 970  0
                 return new Locale(localeStr);
 971  
             }
 972  
         }
 973  
         else
 974  
         {
 975  0
             if (localeStr.length() == 5)
 976  
             {
 977  0
                 String lang = localeStr.substring(0, 1);
 978  0
                 String country = localeStr.substring(3, 4);
 979  0
                 return new Locale(lang, country);
 980  
             }
 981  
         }
 982  
 
 983  0
         return Locale.getDefault();
 984  
     }
 985  
 
 986  
     public void setRenderKitId(String renderKitId)
 987  
     {
 988  0
         getStateHelper().put(PropertyKeys.renderKitId, renderKitId );
 989  0
     }
 990  
 
 991  
     /**
 992  
      * DO NOT USE.
 993  
      * <p>
 994  
      * This inherited property is disabled. Although this class extends a base-class that defines a read/write rendered
 995  
      * property, this particular subclass does not support setting it. Yes, this is broken OO design: direct all
 996  
      * complaints to the JSF spec group.
 997  
      */
 998  
     @Override
 999  
     @JSFProperty(tagExcluded = true)
 1000  
     public void setRendered(boolean state)
 1001  
     {
 1002  
         // Call parent method due to TCK problems
 1003  0
         super.setRendered(state);
 1004  
         // throw new UnsupportedOperationException();
 1005  0
     }
 1006  
 
 1007  
     /**
 1008  
      * DO NOT USE.
 1009  
      * <p>
 1010  
      * Although this class extends a base-class that defines a read/write id property, it makes no sense for this
 1011  
      * particular subclass to support it. The tag library does not export this property for use, but there is no way to
 1012  
      * "undeclare" a java method. Yes, this is broken OO design: direct all complaints to the JSF spec group.
 1013  
      * <p>
 1014  
      * This property should be disabled (ie throw an exception if invoked). However there are currently several places
 1015  
      * that call this method (eg during restoreState) so it just does the normal thing for the moment. TODO: fix callers
 1016  
      * then make this throw an exception.
 1017  
      *
 1018  
      * @JSFProperty tagExcluded="true"
 1019  
      */
 1020  
     @Override
 1021  
     public void setId(String id)
 1022  
     {
 1023  
         // throw new UnsupportedOperationException();
 1024  
 
 1025  
         // Leave enabled for now. Things like the TreeStructureManager call this,
 1026  
         // even though they probably should not.
 1027  0
         super.setId(id);
 1028  0
     }
 1029  
     
 1030  
     /**
 1031  
      * {@inheritDoc}
 1032  
      */
 1033  
     @Override
 1034  
     public void setInView(boolean isInView)
 1035  
     {
 1036  
         // no-op view root is always in view
 1037  0
     }
 1038  
 
 1039  
     public void removeComponentResource(FacesContext context, UIComponent componentResource)
 1040  
     {
 1041  0
         removeComponentResource(context, componentResource, null);
 1042  0
     }
 1043  
 
 1044  
     public void removeComponentResource(FacesContext context, UIComponent componentResource, String target)
 1045  
     {
 1046  
         // If the target argument is null
 1047  0
         if (target == null)
 1048  
         {
 1049  
             // Look for a target attribute on the component
 1050  0
             target = (String)componentResource.getAttributes().get("target");
 1051  
 
 1052  
             // If there is no target attribute
 1053  0
             if (target == null)
 1054  
             {
 1055  
                 // Set target to be the default value head
 1056  0
                 target = "head";
 1057  
             }
 1058  
         }
 1059  
 
 1060  
 
 1061  
         // Call getComponentResources to obtain the child list for the given target.
 1062  
         //List<UIComponent> componentResources = getComponentResources(context, target);
 1063  0
         UIComponent facet = getFacet(target);
 1064  0
         if (facet != null)
 1065  
         {
 1066  
             //Only if the facet is found it is possible to remove the resource,
 1067  
             //otherwise nothing should happen (call to getComponentResource trigger
 1068  
             //creation of facet)
 1069  0
             List<UIComponent> componentResources = facet.getChildren();
 1070  
             // Remove the component resource from the child list
 1071  0
             componentResources.remove(componentResource);
 1072  
         }
 1073  0
     }
 1074  
 
 1075  
     public void setViewId(String viewId)
 1076  
     {
 1077  
         // It really doesn't make much sense to allow null here.
 1078  
         // However the TCK does not check for it, and sun's implementation
 1079  
         // allows it so here we allow it too.
 1080  0
         getStateHelper().put(PropertyKeys.viewId, viewId );
 1081  0
     }
 1082  
 
 1083  
     /**
 1084  
      * Removes a The phaseListeners attached to ViewRoot.
 1085  
      */
 1086  
     public void removePhaseListener(PhaseListener phaseListener)
 1087  
     {
 1088  0
         if (phaseListener == null)
 1089  0
             return;
 1090  
 
 1091  0
         getStateHelper().remove(PropertyKeys.phaseListeners, phaseListener);
 1092  0
     }
 1093  
 
 1094  
     /**
 1095  
      * Sets
 1096  
      *
 1097  
      * @param beforePhaseListener
 1098  
      *            the new beforePhaseListener value
 1099  
      */
 1100  
     public void setBeforePhaseListener(MethodExpression beforePhaseListener)
 1101  
     {
 1102  0
         getStateHelper().put(PropertyKeys.beforePhaseListener, beforePhaseListener);
 1103  0
     }
 1104  
 
 1105  
     /**
 1106  
      * Sets
 1107  
      *
 1108  
      * @param afterPhaseListener
 1109  
      *            the new afterPhaseListener value
 1110  
      */
 1111  
     public void setAfterPhaseListener(MethodExpression afterPhaseListener)
 1112  
     {
 1113  0
         getStateHelper().put(PropertyKeys.afterPhaseListener, afterPhaseListener);
 1114  0
     }
 1115  
     
 1116  0
     enum PropertyKeys
 1117  
     {
 1118  0
          afterPhaseListener
 1119  0
         , beforePhaseListener
 1120  0
         , phaseListeners
 1121  0
         , locale
 1122  0
         , renderKitId
 1123  0
         , viewId
 1124  0
         , uniqueIdCounter
 1125  
     }
 1126  
     
 1127  
     @Override
 1128  
     public Object saveState(FacesContext facesContext)
 1129  
     {
 1130  0
         if (initialStateMarked())
 1131  
         {
 1132  0
             Object parentSaved = super.saveState(facesContext);
 1133  0
             if (parentSaved == null && _viewScope == null)
 1134  
             {
 1135  
                 //No values
 1136  0
                 return null;
 1137  
             }
 1138  
             
 1139  0
             Object[] values = new Object[2];
 1140  0
             values[0] = parentSaved;
 1141  0
             values[1] = saveAttachedState(facesContext,_viewScope);
 1142  0
             return values;
 1143  
         }
 1144  
         else
 1145  
         {
 1146  0
             Object[] values = new Object[2];
 1147  0
             values[0] = super.saveState(facesContext);
 1148  0
             values[1] = saveAttachedState(facesContext,_viewScope);
 1149  0
             return values;
 1150  
         }
 1151  
     }
 1152  
 
 1153  
     @SuppressWarnings("unchecked")
 1154  
     @Override
 1155  
     public void restoreState(FacesContext facesContext, Object state)
 1156  
     {
 1157  0
         if (state == null)
 1158  
         {
 1159  0
             return;
 1160  
         }
 1161  
         
 1162  0
         Object[] values = (Object[])state;
 1163  0
         super.restoreState(facesContext,values[0]);
 1164  0
         _viewScope = (Map<String, Object>) restoreAttachedState(facesContext, values[1]);
 1165  0
     }
 1166  
     
 1167  
     public List<SystemEventListener> getViewListenersForEventClass(Class<? extends SystemEvent> systemEvent)
 1168  
     {
 1169  0
         checkNull (systemEvent, "systemEvent");
 1170  
         
 1171  0
         return _systemEventListeners.get (systemEvent);
 1172  
     }
 1173  
     
 1174  
     public void subscribeToViewEvent(Class<? extends SystemEvent> systemEvent,
 1175  
             SystemEventListener listener)
 1176  
     {
 1177  
         List<SystemEventListener> listeners;
 1178  
         
 1179  0
         checkNull (systemEvent, "systemEvent");
 1180  0
         checkNull (listener, "listener");
 1181  
         
 1182  0
         listeners = _systemEventListeners.get (systemEvent);
 1183  
         
 1184  0
         if (listeners == null) {
 1185  0
             listeners = new ArrayList<SystemEventListener>();
 1186  
             
 1187  0
             _systemEventListeners.put (systemEvent, listeners);
 1188  
         }
 1189  
         
 1190  0
         listeners.add (listener);
 1191  0
     }
 1192  
     
 1193  
     public void unsubscribeFromViewEvent(Class<? extends SystemEvent> systemEvent,
 1194  
             SystemEventListener listener)
 1195  
     {
 1196  
         List<SystemEventListener> listeners;
 1197  
         
 1198  0
         checkNull (systemEvent, "systemEvent");
 1199  0
         checkNull (listener, "listener");
 1200  
         
 1201  0
         listeners = _systemEventListeners.get (systemEvent);
 1202  
         
 1203  0
         if (listeners != null) {
 1204  0
             listeners.remove (listener);
 1205  
         }
 1206  0
     }
 1207  
 
 1208  
     /**
 1209  
      * Process the specified phase by calling PhaseListener.beforePhase for every phase listeners defined on this
 1210  
      * view root, then calling the process method of the processor, broadcasting relevant events and finally
 1211  
      * notifying the afterPhase method of every phase listeners registered on this view root.
 1212  
      *
 1213  
      * @param context
 1214  
      * @param phaseId
 1215  
      * @param processor
 1216  
      * @param broadcast
 1217  
      *
 1218  
      * @return
 1219  
      */
 1220  
     private boolean _process(FacesContext context, PhaseId phaseId, PhaseProcessor processor)
 1221  
     {
 1222  0
         RuntimeException processingException = null;
 1223  
         try
 1224  
         {
 1225  0
             if (!notifyListeners(context, phaseId, getBeforePhaseListener(), true))
 1226  
             {
 1227  
                 try
 1228  
                 {
 1229  0
                     if (processor != null)
 1230  
                     {
 1231  0
                         processor.process(context, this);
 1232  
                     }
 1233  
         
 1234  0
                     broadcastEvents(context, phaseId);
 1235  
                 }
 1236  0
                 catch (RuntimeException re)
 1237  
                 {
 1238  
                     // catch any Exception that occures while processing the phase
 1239  
                     // to ensure invocation of the afterPhase methods
 1240  0
                     processingException = re;
 1241  0
                 }
 1242  
             }
 1243  
         }
 1244  
         finally
 1245  
         {
 1246  0
             if (context.getRenderResponse() || context.getResponseComplete())
 1247  
             {
 1248  0
                 clearEvents();
 1249  
             }            
 1250  
         }
 1251  
 
 1252  0
         boolean retVal = notifyListeners(context, phaseId, getAfterPhaseListener(), false);
 1253  0
         if (processingException == null) 
 1254  
         {
 1255  0
             return retVal;   
 1256  
         }
 1257  
         else
 1258  
         {
 1259  0
             throw processingException;
 1260  
         }
 1261  
     }
 1262  
 
 1263  
     private void _processDecodesDefault(FacesContext context)
 1264  
     {
 1265  0
         super.processDecodes(context);
 1266  0
     }
 1267  
 
 1268  
     private void _processUpdatesDefault(FacesContext context)
 1269  
     {
 1270  0
         super.processUpdates(context);
 1271  0
     }
 1272  
 
 1273  
     private void _processValidatorsDefault(FacesContext context)
 1274  
     {
 1275  0
         super.processValidators(context);
 1276  0
     }
 1277  
 
 1278  
     private static interface PhaseProcessor
 1279  
     {
 1280  
         public void process(FacesContext context, UIViewRoot root);
 1281  
     }
 1282  
 
 1283  0
     private static class ApplyRequestValuesPhaseProcessor implements PhaseProcessor
 1284  
     {
 1285  
         public void process(FacesContext context, UIViewRoot root)
 1286  
         {
 1287  0
             PartialViewContext pvc = context.getPartialViewContext();
 1288  
             // Perform partial processing by calling PartialViewContext.processPartial(javax.faces.event.PhaseId) with PhaseId.UPDATE_MODEL_VALUES if:
 1289  
             //   * PartialViewContext.isPartialRequest() returns true and we don't have a request to process all components in the view (PartialViewContext.isExecuteAll() returns false)
 1290  
             //section 13.4.2 from the  JSF2  spec also see https://issues.apache.org/jira/browse/MYFACES-2119
 1291  0
             if (pvc.isPartialRequest() && !pvc.isExecuteAll())
 1292  
             {
 1293  0
                 pvc.processPartial(PhaseId.APPLY_REQUEST_VALUES);
 1294  
             }
 1295  
             // Perform full processing by calling UIComponentBase.processUpdates(javax.faces.context.FacesContext) if one of the following conditions are met:
 1296  
             // *   PartialViewContext.isPartialRequest() returns true and we have a request to process all components in the view (PartialViewContext.isExecuteAll() returns true)
 1297  
             // *   PartialViewContext.isPartialRequest() returns false
 1298  
             else
 1299  
             {
 1300  0
                 root._processDecodesDefault(context);
 1301  
             }
 1302  0
         }
 1303  
     }
 1304  
 
 1305  0
     private static class ProcessValidatorPhaseProcessor implements PhaseProcessor
 1306  
     {
 1307  
         public void process(FacesContext context, UIViewRoot root)
 1308  
         {
 1309  0
             PartialViewContext pvc = context.getPartialViewContext();
 1310  
             // Perform partial processing by calling PartialViewContext.processPartial(javax.faces.event.PhaseId) with PhaseId.UPDATE_MODEL_VALUES if:
 1311  
             // PartialViewContext.isPartialRequest() returns true and we don't have a request to process all components in the view (PartialViewContext.isExecuteAll() returns false)
 1312  
             //section 13.4.2 from the  JSF2  spec also see https://issues.apache.org/jira/browse/MYFACES-2119
 1313  0
             if (pvc.isPartialRequest() && !pvc.isExecuteAll())
 1314  
             {
 1315  0
                 pvc.processPartial(PhaseId.PROCESS_VALIDATIONS);
 1316  
             }
 1317  
             // Perform full processing by calling UIComponentBase.processUpdates(javax.faces.context.FacesContext) if one of the following conditions are met:
 1318  
             // *   PartialViewContext.isPartialRequest() returns true and we have a request to process all components in the view (PartialViewContext.isExecuteAll() returns true)
 1319  
             // *   PartialViewContext.isPartialRequest() returns false
 1320  
             else
 1321  
             {
 1322  0
                 root._processValidatorsDefault(context);
 1323  
             }
 1324  0
         }
 1325  
     }
 1326  
 
 1327  0
     private static class UpdateModelPhaseProcessor implements PhaseProcessor
 1328  
     {
 1329  
         public void process(FacesContext context, UIViewRoot root)
 1330  
         {
 1331  0
             PartialViewContext pvc = context.getPartialViewContext();
 1332  
             // Perform partial processing by calling PartialViewContext.processPartial(javax.faces.event.PhaseId) with PhaseId.UPDATE_MODEL_VALUES if:
 1333  
             //   * PartialViewContext.isPartialRequest() returns true and we don't have a request to process all components in the view (PartialViewContext.isExecuteAll() returns false)
 1334  
             //section 13.4.2 from the JSF2 spec also see https://issues.apache.org/jira/browse/MYFACES-2119
 1335  0
             if (pvc.isPartialRequest() && !pvc.isExecuteAll())
 1336  
             {
 1337  0
                 pvc.processPartial(PhaseId.UPDATE_MODEL_VALUES);
 1338  
             }
 1339  
             // Perform full processing by calling UIComponentBase.processUpdates(javax.faces.context.FacesContext) if one of the following conditions are met:
 1340  
             // *   PartialViewContext.isPartialRequest() returns true and we have a request to process all components in the view (PartialViewContext.isExecuteAll() returns true)
 1341  
             // *   PartialViewContext.isPartialRequest() returns false
 1342  
             else
 1343  
             {
 1344  0
                 root._processUpdatesDefault(context);
 1345  
             }
 1346  0
         }
 1347  
     }
 1348  
 
 1349  
 /*
 1350  
     private static class RestoreStateCallback implements VisitCallback
 1351  
     {
 1352  
         private PostRestoreStateEvent event;
 1353  
 
 1354  
         public VisitResult visit(VisitContext context, UIComponent target)
 1355  
         {
 1356  
             if (event == null)
 1357  
             {
 1358  
                 event = new PostRestoreStateEvent(target);
 1359  
             }
 1360  
             else
 1361  
             {
 1362  
                 event.setComponent(target);
 1363  
             }
 1364  
 
 1365  
             // call the processEvent method of the current component.
 1366  
             // The argument event must be an instance of AfterRestoreStateEvent whose component
 1367  
             // property is the current component in the traversal.
 1368  
             target.processEvent(event);
 1369  
             
 1370  
             return VisitResult.ACCEPT;
 1371  
         }
 1372  
     }
 1373  
 */
 1374  
 
 1375  
     // we cannot make this class a inner class, because the 
 1376  
     // enclosing class (UIViewRoot) would also have to be serialized.
 1377  0
     private static class ViewScope extends HashMap<String, Object>
 1378  
     {
 1379  
         
 1380  
         private static final long serialVersionUID = -1088893802269478164L;
 1381  
         
 1382  
         @Override
 1383  
         public void clear()
 1384  
         {
 1385  
             /*
 1386  
              * The returned Map must be implemented such that calling clear() on the Map causes
 1387  
              * Application.publishEvent(java.lang.Class, java.lang.Object) to be called, passing
 1388  
              * ViewMapDestroyedEvent.class as the first argument and this UIViewRoot instance as the second argument.
 1389  
              */
 1390  0
             FacesContext facesContext = FacesContext.getCurrentInstance();
 1391  0
             facesContext.getApplication().publishEvent(facesContext, 
 1392  
                     PreDestroyViewMapEvent.class, facesContext.getViewRoot());
 1393  
             
 1394  0
             super.clear();
 1395  0
         }
 1396  
         
 1397  
     }
 1398  
 }