All Downloads are FREE. Search and download functionalities are using the official Maven repository.

javax.faces.component.UIViewRoot Maven / Gradle / Ivy

There is a newer version: 4.1.0
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package javax.faces.component;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.el.MethodExpression;
import javax.el.ValueExpression;
import javax.faces.FactoryFinder;
import javax.faces.application.ProjectStage;
import javax.faces.context.FacesContext;
import javax.faces.context.PartialViewContext;
import javax.faces.event.AbortProcessingException;
import javax.faces.event.ExceptionQueuedEvent;
import javax.faces.event.ExceptionQueuedEventContext;
import javax.faces.event.FacesEvent;
import javax.faces.event.PhaseEvent;
import javax.faces.event.PhaseId;
import javax.faces.event.PhaseListener;
import javax.faces.event.PostConstructViewMapEvent;
import javax.faces.event.PreDestroyViewMapEvent;
import javax.faces.event.SystemEvent;
import javax.faces.event.SystemEventListener;
import javax.faces.lifecycle.Lifecycle;
import javax.faces.lifecycle.LifecycleFactory;
import javax.faces.view.ViewDeclarationLanguage;
import javax.faces.view.ViewMetadata;
import javax.faces.webapp.FacesServlet;

import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFComponent;
import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFJspProperty;
import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFProperty;

/**
 * Creates a JSF View, which is a container that holds all of the components that are part of the view.
 * 

* Unless otherwise specified, all attributes accept static values or EL expressions. *

*

* See the javadoc for this class in the JSF * Specification for further details. *

*/ @JSFComponent(name = "f:view", bodyContent = "JSP", tagClass = "org.apache.myfaces.taglib.core.ViewTag") @JSFJspProperty(name = "binding", returnType = "java.lang.String", tagExcluded = true) public class UIViewRoot extends UIComponentBase implements UniqueIdVendor { public static final String COMPONENT_FAMILY = "javax.faces.ViewRoot"; public static final String COMPONENT_TYPE = "javax.faces.ViewRoot"; public static final String METADATA_FACET_NAME = "javax_faces_metadata"; public static final String UNIQUE_ID_PREFIX = "j_id"; public static final String VIEW_PARAMETERS_KEY = "javax.faces.component.VIEW_PARAMETERS_KEY"; private final Logger logger = Logger.getLogger(UIViewRoot.class.getName()); private static final PhaseProcessor APPLY_REQUEST_VALUES_PROCESSOR = new ApplyRequestValuesPhaseProcessor(); private static final PhaseProcessor PROCESS_VALIDATORS_PROCESSOR = new ProcessValidatorPhaseProcessor(); private static final PhaseProcessor UPDATE_MODEL_PROCESSOR = new UpdateModelPhaseProcessor(); /** * The counter which will ensure a unique component id for every component instance in the tree that doesn't have an * id attribute set. */ //private long _uniqueIdCounter = 0; // todo: is it right to save the state of _events and _phaseListeners? private List _events; /** * Map containing view scope objects. * * It is not expected this map hold PartialStateHolder instances, * so we can use saveAttachedState and restoreAttachedState methods. */ private Map _viewScope; private transient Lifecycle _lifecycle = null; private HashMap, List> _systemEventListeners; // Tracks success in the beforePhase. Listeners that threw an exception // in beforePhase or were never called, because a previous listener threw // an exception, should not have their afterPhase method called private transient Map listenerSuccessMap = new HashMap(); private static final String JAVAX_FACES_LOCATION_PREFIX = "javax_faces_location_"; private static final String JAVAX_FACES_LOCATION_HEAD = "javax_faces_location_head"; private static final String JAVAX_FACES_LOCATION_BODY = "javax_faces_location_body"; private static final String JAVAX_FACES_LOCATION_FORM = "javax_faces_location_form"; /** * Construct an instance of the UIViewRoot. */ public UIViewRoot() { setRendererType(null); _systemEventListeners = new HashMap, List>(); } /** * @since 2.0 */ public void addComponentResource(FacesContext context, UIComponent componentResource) { addComponentResource(context, componentResource, null); } /** * @since 2.0 */ public void addComponentResource(FacesContext context, UIComponent componentResource, String target) { // If the target argument is null if (target == null) { // Look for a target attribute on the component target = (String)componentResource.getAttributes().get("target"); // If there is no target attribute, set target to be the default value head if (target == null) { target = "head"; } } // Call getComponentResources to obtain the child list for the given target List componentResources = _getComponentResources(context, target); // If the component ID of componentResource matches the ID of a resource that has already been added, remove the old resource. String componentId = componentResource.getId(); if (componentId == null) { // componentResource can have no id - calling createUniqueId makes us sure that component will have one // https://issues.apache.org/jira/browse/MYFACES-2775 componentId = createUniqueId(context, null); componentResource.setId(componentId); } // This var helps to handle the case when we try to add a component that already is // on the resource list, because PostAddToViewEvent also is sent to components // backing resources. The problem start when a component is already inside // componentResources list and we try to relocate it again. This leads to a StackOverflowException // so we need to check if a component is and prevent remove and add it again. Note // that remove and then add a component trigger another PostAddToViewEvent. The right // point to prevent this StackOverflowException is here, because this method is // responsible to traverse the componentResources list and add when necessary. boolean alreadyAdded = false; //The check is only necessary if the component resource is part of the tree. if (componentResource.isInView()) { if (componentResource.getParent() != null && componentResource.getParent().getId() != null && componentResource.getParent().getId().equals(JAVAX_FACES_LOCATION_PREFIX + target)) { // We can assume safely that the component is in place, because there is no way to // put a component resource on a component resource container without call addComponentResource // so relocation here will not happen. alreadyAdded = true; } else if (componentId != null) { for(Iterator it = componentResources.iterator(); it.hasNext();) { UIComponent component = it.next(); if(componentId.equals(component.getId()) && componentResource != component) { it.remove(); } else if (componentResource == component) { alreadyAdded = true; } } } } else if (componentId != null) { for(Iterator it = componentResources.iterator(); it.hasNext();) { UIComponent component = it.next(); if(componentId.equals(component.getId()) && componentResource != component) { it.remove(); } else if (componentResource == component) { alreadyAdded = true; } } } // Add the component resource to the list if (!alreadyAdded) { componentResources.add(componentResource); } } /** * Adds a The phaseListeners attached to ViewRoot. */ public void addPhaseListener(PhaseListener phaseListener) { if (phaseListener == null) throw new NullPointerException("phaseListener"); getStateHelper().add(PropertyKeys.phaseListeners, phaseListener); } /** * @since 2.0 */ public void broadcastEvents(FacesContext context, PhaseId phaseId) { if (_events == null) { return; } Events events = _getEvents(phaseId); // Spec. 3.4.2.6 Event Broadcasting: // Queue one or more additional events, from the same source component or a different one, for processing during the // current lifecycle phase. // Unfortunately with that requirement it is easy to create infinite loop in processing. One example can be: // // public processAction(ActionEvent actionEvent) // { // actionEvent = new ActionEvent(actionEvent.getComponent()); // actionEvent.queue(); // } // // Thus we iterate here only 15x. If iteration overreachs 15 we output a warning int loops = 0; int maxLoops = 15; Collection eventsAborted = new LinkedList(); do { // First broadcast events that have been queued for PhaseId.ANY_PHASE. _broadcastAll(context, events.getAnyPhase(), eventsAborted); Collection eventsOnPhase = events.getOnPhase(); if (!eventsAborted.isEmpty()) { eventsOnPhase.removeAll(eventsAborted); eventsAborted.clear(); } _broadcastAll(context, eventsOnPhase, eventsAborted); events = _getEvents(phaseId); loops++; } while (events.hasMoreEvents() && loops < maxLoops); if (loops == maxLoops && events.hasMoreEvents()) { // broadcast reach maxLoops - probably a infinitive recursion: boolean production = getFacesContext().isProjectStage(ProjectStage.Production); Level level = production ? Level.FINE : Level.WARNING; if (logger.isLoggable(level)) { List name = new ArrayList(events.getAnyPhase().size() + events.getOnPhase().size()); for (FacesEvent facesEvent : events.getAnyPhase()) { String clientId = facesEvent.getComponent().getClientId(getFacesContext()); name.add(clientId); } for (FacesEvent facesEvent : events.getOnPhase()) { String clientId = facesEvent.getComponent().getClientId(getFacesContext()); name.add(clientId); } logger.log(level, "Event broadcating for PhaseId {0} at UIViewRoot {1} reaches maximal limit, please check " + "listeners for infinite recursion. Component id: {2}", new Object [] {phaseId, getViewId(), name}); } } } /** * Provides a unique id for this component instance. */ public String createUniqueId() { return createUniqueId(getFacesContext(), null); } /** * * {@inheritDoc} * * @since 2.0 */ public String createUniqueId(FacesContext context, String seed) { StringBuilder bld = __getSharedStringBuilder(context); Long uniqueIdCounter = (Long) getStateHelper().get(PropertyKeys.uniqueIdCounter); uniqueIdCounter = (uniqueIdCounter == null) ? 0 : uniqueIdCounter; getStateHelper().put(PropertyKeys.uniqueIdCounter, (uniqueIdCounter+1L)); // Generate an identifier for a component. The identifier will be prefixed with UNIQUE_ID_PREFIX, and will be unique within this UIViewRoot. if(seed==null) { return bld.append(UNIQUE_ID_PREFIX).append(uniqueIdCounter).toString(); } // Optionally, a unique seed value can be supplied by component creators which should be included in the generated unique id. else { return bld.append(UNIQUE_ID_PREFIX).append(seed).toString(); } } @Override public void encodeBegin(FacesContext context) throws IOException { checkNull(context, "context"); boolean skipPhase = false; try { skipPhase = notifyListeners(context, PhaseId.RENDER_RESPONSE, getBeforePhaseListener(), true); } catch (Exception e) { // following the spec we have to swallow the exception logger.log(Level.SEVERE, "Exception while processing phase listener: " + e.getMessage(), e); } if (!skipPhase) { //prerendering happens, we now publish the prerender view event //the specs states that the viewroot as source is about to be rendered //hence we issue the event immediately before publish, if the phase is not skipped //context.getApplication().publishEvent(context, PreRenderViewEvent.class, this); //then the view rendering is about to begin super.encodeBegin(context); } else { pushComponentToEL(context, this); } } /** * @since 2.0 */ @Override public void encodeChildren(FacesContext context) throws IOException { if (context.getResponseComplete()) { return; } PartialViewContext pContext = context.getPartialViewContext(); // If PartialViewContext.isAjaxRequest() returns true if (pContext.isAjaxRequest()) { // Perform partial rendering by calling PartialViewContext.processPartial() with PhaseId.RENDER_RESPONSE. //sectin 13.4.3 of the jsf2 specification pContext.processPartial(PhaseId.RENDER_RESPONSE); } else { // If PartialViewContext.isAjaxRequest() returns false // delegate to super.encodeChildren(javax.faces.context.FacesContext) method. super.encodeChildren(context); } } @Override public void encodeEnd(FacesContext context) throws IOException { checkNull(context, "context"); if (!context.getResponseComplete()) { super.encodeEnd(context); // the call to encodeAll() on every UIViewParameter here is only necessary // if the current request is _not_ an AJAX request, because if it was an // AJAX request, the call would already have happened in PartialViewContextImpl and // would anyway be too late here, because the state would already have been generated PartialViewContext partialContext = context.getPartialViewContext(); if (!partialContext.isAjaxRequest()) { ViewDeclarationLanguage vdl = context.getApplication().getViewHandler().getViewDeclarationLanguage(context, getViewId()); if (vdl != null) { // If the current view has view parameters, as indicated by a non-empty and non-UnsupportedOperationException throwing // return from ViewDeclarationLanguage.getViewMetadata(javax.faces.context.FacesContext, String) ViewMetadata metadata = null; try { metadata = vdl.getViewMetadata(context, getViewId()); } catch(UnsupportedOperationException e) { logger.log(Level.SEVERE, "Exception while obtaining the view metadata: " + e.getMessage(), e); } if (metadata != null) { try { Collection viewParams = ViewMetadata.getViewParameters(this); if(!viewParams.isEmpty()) { // call UIViewParameter.encodeAll(javax.faces.context.FacesContext) on each parameter. for(UIViewParameter param : viewParams) { param.encodeAll(context); } } } catch(UnsupportedOperationException e) { // If calling getViewParameters() causes UnsupportedOperationException to be thrown, the exception must be silently swallowed. } } } } } try { notifyListeners(context, PhaseId.RENDER_RESPONSE, getAfterPhaseListener(), false); } catch (Exception e) { // following the spec we have to swallow the exception logger.log(Level.SEVERE, "Exception while processing phase listener: " + e.getMessage(), e); } } /** * MethodBinding pointing to a method that takes a javax.faces.event.PhaseEvent and returns void, called after every * phase except for restore view. * * @return the new afterPhaseListener value */ @JSFProperty(returnSignature = "void", methodSignature = "javax.faces.event.PhaseEvent", jspName = "afterPhase", stateHolder=true) public MethodExpression getAfterPhaseListener() { return (MethodExpression) getStateHelper().eval(PropertyKeys.afterPhaseListener); } /** * MethodBinding pointing to a method that takes a javax.faces.event.PhaseEvent and returns void, called before * every phase except for restore view. * * @return the new beforePhaseListener value */ @JSFProperty(returnSignature = "void", methodSignature = "javax.faces.event.PhaseEvent", jspName = "beforePhase", stateHolder=true) public MethodExpression getBeforePhaseListener() { return (MethodExpression) getStateHelper().eval(PropertyKeys.beforePhaseListener); } /** * DO NOT USE. *

* As this component has no "id" property, it has no clientId property either. */ @Override public String getClientId(FacesContext context) { return super.getClientId(context); // Call parent method due to TCK problems // return null; } /** * @since 2.0 */ public List getComponentResources(FacesContext context, String target) { // Locate the facet for the component by calling getFacet() using target as the argument UIComponent facet = getFacet(target); /* // If the facet is not found, if (facet == null) { // create the facet by calling context.getApplication().createComponent() using javax.faces.Panel as the argument facet = context.getApplication().createComponent("javax.faces.Panel"); // Set the id of the facet to be target facet.setId(target); // Add the facet to the facets Map using target as the key getFacets().put(target, facet); } // Return the children of the facet // The API doc indicates that this method should "Return an unmodifiable List of UIComponents for the provided target argument." // and also that "If no children are found for the facet, return Collections.emptyList()." List children = facet.getChildren(); return ( children == null ? Collections.emptyList() : Collections.unmodifiableList(children) ); */ if (facet != null) { if (facet.getChildCount() > 0) { return Collections.unmodifiableList(facet.getChildren()); } else { return Collections.emptyList(); } } return Collections.emptyList(); } private List _getComponentResources(FacesContext context, String target) { // Locate the facet for the component by calling getFacet() using target as the argument UIComponent facet = getFacet(target); // If the facet is not found, if (facet == null) { // create the facet by calling context.getApplication().createComponent() using javax.faces.Panel as the argument facet = context.getApplication().createComponent("javax.faces.ComponentResourceContainer"); // Set the id of the facet to be target if (target.equals("head")) { facet.setId(JAVAX_FACES_LOCATION_HEAD); } else if (target.equals("body")) { facet.setId(JAVAX_FACES_LOCATION_BODY); } else if (target.equals("form")) { facet.setId(JAVAX_FACES_LOCATION_FORM); } else { facet.setId(JAVAX_FACES_LOCATION_PREFIX + target); } // From jsr-314-open list it was made clear this facet is transient, // because all component resources does not change its inner state between // requests // // MYFACES-3047 It was found that resources added using ResourceDependency annotation // requires to be saved and restored, so it is not possible to mark this facets // as transient. The previous statement is true only for PSS. //facet.setTransient(true); // Add the facet to the facets Map using target as the key getFacets().put(target, facet); } return facet.getChildren(); } @Override public String getFamily() { return COMPONENT_FAMILY; } /** * The locale for this view. *

* Defaults to the default locale specified in the faces configuration file. *

*/ @JSFProperty public Locale getLocale() { Object locale = getStateHelper().get(PropertyKeys.locale); if (locale != null) { return (Locale)locale; } ValueExpression expression = getValueExpression(PropertyKeys.locale.toString()); if (expression != null) { Object veLocale = expression.getValue(getFacesContext().getELContext()); if (veLocale instanceof Locale) { return (Locale) veLocale; } else { return (Locale) _LocaleUtils.toLocale(veLocale.toString()); } } else { locale = getFacesContext().getApplication().getViewHandler().calculateLocale(getFacesContext()); if (locale instanceof Locale) { return (Locale)locale; } else if (locale instanceof String) { return _LocaleUtils.toLocale((String)locale); } } return getFacesContext().getApplication().getViewHandler().calculateLocale(getFacesContext()); } /** * @since 2.0 */ public List getPhaseListeners() { List listeners = (List) getStateHelper().get(PropertyKeys.phaseListeners); if (listeners == null) { listeners = Collections.emptyList(); } else { listeners = Collections.unmodifiableList(listeners); } return listeners; } /** * Defines what renderkit should be used to render this view. */ @JSFProperty public String getRenderKitId() { return (String) getStateHelper().eval(PropertyKeys.renderKitId); } /** * @since 2.0 */ @Override public boolean getRendersChildren() { // Call UIComponentBase.getRendersChildren() // If PartialViewContext.isAjaxRequest() returns true this method must return true. PartialViewContext context = getFacesContext().getPartialViewContext(); return (context.isAjaxRequest()) ? true : super.getRendersChildren(); } /** * A unique identifier for the "template" from which this view was generated. *

* Typically this is the filesystem path to the template file, but the exact details are the responsibility of the * current ViewHandler implementation. */ @JSFProperty(tagExcluded = true) public String getViewId() { return (String) getStateHelper().eval(PropertyKeys.viewId); } /** * @since 2.0 */ public Map getViewMap() { return this.getViewMap(true); } /** * @since 2.0 */ public Map getViewMap(boolean create) { if (_viewScope == null && create) { _viewScope = new ViewScope(); FacesContext facesContext = getFacesContext(); facesContext.getApplication().publishEvent(facesContext, PostConstructViewMapEvent.class, this); } return _viewScope; } /** * {@inheritDoc} */ @Override public boolean isInView() { return true; } public void processApplication(final FacesContext context) { checkNull(context, "context"); _process(context, PhaseId.INVOKE_APPLICATION, null); } @Override public void processDecodes(FacesContext context) { checkNull(context, "context"); _process(context, PhaseId.APPLY_REQUEST_VALUES, APPLY_REQUEST_VALUES_PROCESSOR); } /** * @since 2.0 */ @Override public void processRestoreState(FacesContext context, Object state) { // The default implementation must call UIComponentBase.processRestoreState(javax.faces.context.FacesContext, // java.lang.Object) from within a try block. try { super.processRestoreState(context, state); } finally { // The try block must have a finally block that ensures that no FacesEvents remain in the event queue broadcastEvents(context, PhaseId.RESTORE_VIEW); //visitTree(VisitContext.createVisitContext(context), new RestoreStateCallback()); } } @Override public void queueEvent(FacesEvent event) { checkNull(event, "event"); if (_events == null) { _events = new ArrayList(); } _events.add(event); } @Override public void processValidators(FacesContext context) { checkNull(context, "context"); _process(context, PhaseId.PROCESS_VALIDATIONS, PROCESS_VALIDATORS_PROCESSOR); } @Override public void processUpdates(FacesContext context) { checkNull(context, "context"); _process(context, PhaseId.UPDATE_MODEL_VALUES, UPDATE_MODEL_PROCESSOR); } public void setLocale(Locale locale) { getStateHelper().put(PropertyKeys.locale, locale ); } /** * Invoke view-specific phase listeners, plus an optional EL MethodExpression. *

* JSF1.2 adds the ability for PhaseListener objects to be added to a UIViewRoot instance, and for * "beforePhaseListener" and "afterPhaseListener" EL expressions to be defined on the viewroot. This method is * expected to be called at appropriate times, and will then execute the relevant listener callbacks. *

* Parameter "listener" may be null. If not null, then it is an EL expression pointing to a user method that will be * invoked. *

* Note that the global PhaseListeners are invoked via the Lifecycle implementation, not from this method here. *

* These PhaseListeners are processed with the same rules as the globally defined PhaseListeners, except * that any Exceptions, which may occur during the execution of the PhaseListeners, will only be logged * and not published to the ExceptionHandler. */ private boolean notifyListeners(FacesContext context, PhaseId phaseId, MethodExpression listener, boolean beforePhase) { List phaseListeners = (List) getStateHelper().get(PropertyKeys.phaseListeners); if (listener != null || (phaseListeners != null && !phaseListeners.isEmpty())) { // how many listeners do we have? (the MethodExpression listener is counted in either way) // NOTE: beforePhaseSuccess[0] always refers to the MethodExpression listener int listenerCount = (phaseListeners != null ? phaseListeners.size() + 1 : 1); boolean[] beforePhaseSuccess; if (beforePhase) { beforePhaseSuccess = new boolean[listenerCount]; listenerSuccessMap.put(phaseId, beforePhaseSuccess); } else { // afterPhase - get beforePhaseSuccess from the Map beforePhaseSuccess = listenerSuccessMap.get(phaseId); if (beforePhaseSuccess == null) { // no Map available - assume that everything went well beforePhaseSuccess = new boolean[listenerCount]; Arrays.fill(beforePhaseSuccess, true); } } PhaseEvent event = createEvent(context, phaseId); // only invoke the listener if we are in beforePhase // or if the related before PhaseListener finished without an Exception if (listener != null && (beforePhase || beforePhaseSuccess[0])) { try { listener.invoke(context.getELContext(), new Object[] { event }); beforePhaseSuccess[0] = true; } catch (Throwable t) { beforePhaseSuccess[0] = false; // redundant - for clarity logger.log(Level.SEVERE, "An Exception occured while processing " + listener.getExpressionString() + " in Phase " + phaseId, t); if (beforePhase) { return context.getResponseComplete() || (context.getRenderResponse() && !PhaseId.RENDER_RESPONSE.equals(phaseId)); } } } else if (beforePhase) { // there is no beforePhase MethodExpression listener beforePhaseSuccess[0] = true; } if (phaseListeners != null && !phaseListeners.isEmpty()) { if (beforePhase) { // process listeners in ascending order for (int i = 0; i < beforePhaseSuccess.length - 1; i++) { PhaseListener phaseListener; try { phaseListener = phaseListeners.get(i); } catch (IndexOutOfBoundsException e) { // happens when a PhaseListener removes another PhaseListener // from UIViewRoot in its beforePhase method throw new IllegalStateException("A PhaseListener must not remove " + "PhaseListeners from UIViewRoot."); } PhaseId listenerPhaseId = phaseListener.getPhaseId(); if (phaseId.equals(listenerPhaseId) || PhaseId.ANY_PHASE.equals(listenerPhaseId)) { try { phaseListener.beforePhase(event); beforePhaseSuccess[i + 1] = true; } catch (Throwable t) { beforePhaseSuccess[i + 1] = false; // redundant - for clarity logger.log(Level.SEVERE, "An Exception occured while processing the " + "beforePhase method of PhaseListener " + phaseListener + " in Phase " + phaseId, t); return context.getResponseComplete() || (context.getRenderResponse() && !PhaseId.RENDER_RESPONSE.equals(phaseId)); } } } } else { // afterPhase // process listeners in descending order for (int i = beforePhaseSuccess.length - 1; i > 0; i--) { PhaseListener phaseListener; try { phaseListener = phaseListeners.get(i - 1); } catch (IndexOutOfBoundsException e) { // happens when a PhaseListener removes another PhaseListener // from UIViewRoot in its beforePhase or afterPhase method throw new IllegalStateException("A PhaseListener must not remove " + "PhaseListeners from UIViewRoot."); } PhaseId listenerPhaseId = phaseListener.getPhaseId(); if ((phaseId.equals(listenerPhaseId) || PhaseId.ANY_PHASE.equals(listenerPhaseId)) && beforePhaseSuccess[i]) { try { phaseListener.afterPhase(event); } catch (Throwable t) { logger.log(Level.SEVERE, "An Exception occured while processing the " + "afterPhase method of PhaseListener " + phaseListener + " in Phase " + phaseId, t); } } } } } } if (beforePhase) { return context.getResponseComplete() || (context.getRenderResponse() && !PhaseId.RENDER_RESPONSE.equals(phaseId)); } else { return context.getResponseComplete() || context.getRenderResponse(); } } private PhaseEvent createEvent(FacesContext context, PhaseId phaseId) { if (_lifecycle == null) { LifecycleFactory factory = (LifecycleFactory)FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY); String id = context.getExternalContext().getInitParameter(FacesServlet.LIFECYCLE_ID_ATTR); if (id == null) { id = LifecycleFactory.DEFAULT_LIFECYCLE; } _lifecycle = factory.getLifecycle(id); } return new PhaseEvent(context, phaseId, _lifecycle); } /** * Broadcast all events in the specified collection, stopping the at any time an AbortProcessingException * is thrown. * * @param context the current JSF context * @param events the events to broadcast * * @return true if the broadcast was completed without abortion, false otherwise */ private void _broadcastAll(FacesContext context, Collection events, Collection eventsAborted) { assert events != null; for (FacesEvent event : events) { UIComponent source = event.getComponent(); UIComponent compositeParent = UIComponent.getCompositeComponentParent(source); if (compositeParent != null) { pushComponentToEL(context, compositeParent); } // Push the source as the current component pushComponentToEL(context, source); try { // Actual event broadcasting source.broadcast(event); } catch (AbortProcessingException e) { // publish the Exception to be handled by the ExceptionHandler ExceptionQueuedEventContext exceptionContext = new ExceptionQueuedEventContext(context, e, source, context.getCurrentPhaseId()); context.getApplication().publishEvent(context, ExceptionQueuedEvent.class, exceptionContext); // Abortion eventsAborted.add(event); } finally { // Restore the current component popComponentFromEL(context); if (compositeParent != null) { popComponentFromEL(context); } } } } private void clearEvents() { _events = null; } private void checkNull(Object value, String valueLabel) { if (value == null) { throw new NullPointerException(valueLabel + " is null"); } } public void setRenderKitId(String renderKitId) { getStateHelper().put(PropertyKeys.renderKitId, renderKitId ); } /** * DO NOT USE. *

* This inherited property is disabled. Although this class extends a base-class that defines a read/write rendered * property, this particular subclass does not support setting it. Yes, this is broken OO design: direct all * complaints to the JSF spec group. */ @Override @JSFProperty(tagExcluded = true) public void setRendered(boolean state) { // Call parent method due to TCK problems super.setRendered(state); // throw new UnsupportedOperationException(); } /** * DO NOT USE. *

* Although this class extends a base-class that defines a read/write id property, it makes no sense for this * particular subclass to support it. The tag library does not export this property for use, but there is no way to * "undeclare" a java method. Yes, this is broken OO design: direct all complaints to the JSF spec group. *

* This property should be disabled (ie throw an exception if invoked). However there are currently several places * that call this method (eg during restoreState) so it just does the normal thing for the moment. TODO: fix callers * then make this throw an exception. * * @JSFProperty tagExcluded="true" */ @Override public void setId(String id) { // throw new UnsupportedOperationException(); // Leave enabled for now. Things like the TreeStructureManager call this, // even though they probably should not. super.setId(id); } /** * {@inheritDoc} */ @Override public void setInView(boolean isInView) { // no-op view root is always in view } public void removeComponentResource(FacesContext context, UIComponent componentResource) { removeComponentResource(context, componentResource, null); } public void removeComponentResource(FacesContext context, UIComponent componentResource, String target) { // If the target argument is null if (target == null) { // Look for a target attribute on the component target = (String)componentResource.getAttributes().get("target"); // If there is no target attribute if (target == null) { // Set target to be the default value head target = "head"; } } // Call getComponentResources to obtain the child list for the given target. //List componentResources = getComponentResources(context, target); UIComponent facet = getFacet(target); if (facet != null) { //Only if the facet is found it is possible to remove the resource, //otherwise nothing should happen (call to getComponentResource trigger //creation of facet) // Remove the component resource from the child list facet.getChildren().remove(componentResource); } } public void setViewId(String viewId) { // It really doesn't make much sense to allow null here. // However the TCK does not check for it, and sun's implementation // allows it so here we allow it too. getStateHelper().put(PropertyKeys.viewId, viewId ); } /** * Removes a The phaseListeners attached to ViewRoot. */ public void removePhaseListener(PhaseListener phaseListener) { if (phaseListener == null) return; getStateHelper().remove(PropertyKeys.phaseListeners, phaseListener); } /** * Sets * * @param beforePhaseListener * the new beforePhaseListener value */ public void setBeforePhaseListener(MethodExpression beforePhaseListener) { getStateHelper().put(PropertyKeys.beforePhaseListener, beforePhaseListener); } /** * Sets * * @param afterPhaseListener * the new afterPhaseListener value */ public void setAfterPhaseListener(MethodExpression afterPhaseListener) { getStateHelper().put(PropertyKeys.afterPhaseListener, afterPhaseListener); } enum PropertyKeys { afterPhaseListener , beforePhaseListener , phaseListeners , locale , renderKitId , viewId , uniqueIdCounter } @Override public Object saveState(FacesContext facesContext) { if (initialStateMarked()) { Object parentSaved = super.saveState(facesContext); if (parentSaved == null && _viewScope == null) { //No values return null; } Object[] values = new Object[2]; values[0] = parentSaved; values[1] = saveAttachedState(facesContext,_viewScope); return values; } else { Object[] values = new Object[2]; values[0] = super.saveState(facesContext); values[1] = saveAttachedState(facesContext,_viewScope); return values; } } @SuppressWarnings("unchecked") @Override public void restoreState(FacesContext facesContext, Object state) { if (state == null) { return; } Object[] values = (Object[])state; super.restoreState(facesContext,values[0]); _viewScope = (Map) restoreAttachedState(facesContext, values[1]); } public List getViewListenersForEventClass(Class systemEvent) { checkNull (systemEvent, "systemEvent"); return _systemEventListeners.get (systemEvent); } public void subscribeToViewEvent(Class systemEvent, SystemEventListener listener) { List listeners; checkNull (systemEvent, "systemEvent"); checkNull (listener, "listener"); listeners = _systemEventListeners.get (systemEvent); if (listeners == null) { listeners = new ArrayList(); _systemEventListeners.put (systemEvent, listeners); } listeners.add (listener); } public void unsubscribeFromViewEvent(Class systemEvent, SystemEventListener listener) { List listeners; checkNull (systemEvent, "systemEvent"); checkNull (listener, "listener"); listeners = _systemEventListeners.get (systemEvent); if (listeners != null) { listeners.remove (listener); } } /** * Process the specified phase by calling PhaseListener.beforePhase for every phase listeners defined on this * view root, then calling the process method of the processor, broadcasting relevant events and finally * notifying the afterPhase method of every phase listeners registered on this view root. * * @param context * @param phaseId * @param processor * @param broadcast * * @return */ private boolean _process(FacesContext context, PhaseId phaseId, PhaseProcessor processor) { RuntimeException processingException = null; try { if (!notifyListeners(context, phaseId, getBeforePhaseListener(), true)) { try { if (processor != null) { processor.process(context, this); } broadcastEvents(context, phaseId); } catch (RuntimeException re) { // catch any Exception that occures while processing the phase // to ensure invocation of the afterPhase methods processingException = re; } } } finally { if (context.getRenderResponse() || context.getResponseComplete()) { clearEvents(); } } boolean retVal = notifyListeners(context, phaseId, getAfterPhaseListener(), false); if (processingException == null) { return retVal; } else { throw processingException; } } private void _processDecodesDefault(FacesContext context) { super.processDecodes(context); } private void _processUpdatesDefault(FacesContext context) { super.processUpdates(context); } private void _processValidatorsDefault(FacesContext context) { super.processValidators(context); } /** * Gathers all event for current and ANY phase * @param phaseId current phase id */ private Events _getEvents(PhaseId phaseId) { // Gather the events and purge the event list to prevent concurrent modification during broadcasting List anyPhase = new ArrayList( _events.size()); List onPhase = new ArrayList(_events.size()); for (Iterator iterator = _events.iterator(); iterator .hasNext();) { FacesEvent event = iterator.next(); if (event.getPhaseId().equals(PhaseId.ANY_PHASE)) { anyPhase.add(event); iterator.remove(); } else if (event.getPhaseId().equals(phaseId)) { onPhase.add(event); iterator.remove(); } } return new Events(anyPhase, onPhase); } private static interface PhaseProcessor { public void process(FacesContext context, UIViewRoot root); } private static class ApplyRequestValuesPhaseProcessor implements PhaseProcessor { public void process(FacesContext context, UIViewRoot root) { PartialViewContext pvc = context.getPartialViewContext(); // Perform partial processing by calling PartialViewContext.processPartial(javax.faces.event.PhaseId) with PhaseId.UPDATE_MODEL_VALUES if: // * PartialViewContext.isPartialRequest() returns true and we don't have a request to process all components in the view (PartialViewContext.isExecuteAll() returns false) //section 13.4.2 from the JSF2 spec also see https://issues.apache.org/jira/browse/MYFACES-2119 if (pvc.isPartialRequest() && !pvc.isExecuteAll()) { pvc.processPartial(PhaseId.APPLY_REQUEST_VALUES); } // Perform full processing by calling UIComponentBase.processUpdates(javax.faces.context.FacesContext) if one of the following conditions are met: // * PartialViewContext.isPartialRequest() returns true and we have a request to process all components in the view (PartialViewContext.isExecuteAll() returns true) // * PartialViewContext.isPartialRequest() returns false else { root._processDecodesDefault(context); } } } private static class ProcessValidatorPhaseProcessor implements PhaseProcessor { public void process(FacesContext context, UIViewRoot root) { PartialViewContext pvc = context.getPartialViewContext(); // Perform partial processing by calling PartialViewContext.processPartial(javax.faces.event.PhaseId) with PhaseId.UPDATE_MODEL_VALUES if: // PartialViewContext.isPartialRequest() returns true and we don't have a request to process all components in the view (PartialViewContext.isExecuteAll() returns false) //section 13.4.2 from the JSF2 spec also see https://issues.apache.org/jira/browse/MYFACES-2119 if (pvc.isPartialRequest() && !pvc.isExecuteAll()) { pvc.processPartial(PhaseId.PROCESS_VALIDATIONS); } // Perform full processing by calling UIComponentBase.processUpdates(javax.faces.context.FacesContext) if one of the following conditions are met: // * PartialViewContext.isPartialRequest() returns true and we have a request to process all components in the view (PartialViewContext.isExecuteAll() returns true) // * PartialViewContext.isPartialRequest() returns false else { root._processValidatorsDefault(context); } } } private static class UpdateModelPhaseProcessor implements PhaseProcessor { public void process(FacesContext context, UIViewRoot root) { PartialViewContext pvc = context.getPartialViewContext(); // Perform partial processing by calling PartialViewContext.processPartial(javax.faces.event.PhaseId) with PhaseId.UPDATE_MODEL_VALUES if: // * PartialViewContext.isPartialRequest() returns true and we don't have a request to process all components in the view (PartialViewContext.isExecuteAll() returns false) //section 13.4.2 from the JSF2 spec also see https://issues.apache.org/jira/browse/MYFACES-2119 if (pvc.isPartialRequest() && !pvc.isExecuteAll()) { pvc.processPartial(PhaseId.UPDATE_MODEL_VALUES); } // Perform full processing by calling UIComponentBase.processUpdates(javax.faces.context.FacesContext) if one of the following conditions are met: // * PartialViewContext.isPartialRequest() returns true and we have a request to process all components in the view (PartialViewContext.isExecuteAll() returns true) // * PartialViewContext.isPartialRequest() returns false else { root._processUpdatesDefault(context); } } } /* private static class RestoreStateCallback implements VisitCallback { private PostRestoreStateEvent event; public VisitResult visit(VisitContext context, UIComponent target) { if (event == null) { event = new PostRestoreStateEvent(target); } else { event.setComponent(target); } // call the processEvent method of the current component. // The argument event must be an instance of AfterRestoreStateEvent whose component // property is the current component in the traversal. target.processEvent(event); return VisitResult.ACCEPT; } } */ // we cannot make this class a inner class, because the // enclosing class (UIViewRoot) would also have to be serialized. private static class ViewScope extends HashMap { private static final long serialVersionUID = -1088893802269478164L; @Override public void clear() { /* * The returned Map must be implemented such that calling clear() on the Map causes * Application.publishEvent(java.lang.Class, java.lang.Object) to be called, passing * ViewMapDestroyedEvent.class as the first argument and this UIViewRoot instance as the second argument. */ FacesContext facesContext = FacesContext.getCurrentInstance(); facesContext.getApplication().publishEvent(facesContext, PreDestroyViewMapEvent.class, facesContext.getViewRoot()); super.clear(); } } /** * Agregates events for ANY_PHASE and current phase */ private class Events { private final List _anyPhase; private final List _onPhase; public Events(List anyPhase, List onPhase) { super(); this._anyPhase = anyPhase; this._onPhase = onPhase; } public boolean hasMoreEvents() { return (_anyPhase != null && _anyPhase.size() > 0) || (_onPhase != null && _onPhase.size() > 0); } public List getAnyPhase() { return _anyPhase; } public List getOnPhase() { return _onPhase; } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy