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.util.ArrayList;
import java.util.ConcurrentModificationException;
import java.util.List;
import java.util.ListIterator;
import java.util.Locale;
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.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.event.AbortProcessingException;
import javax.faces.event.FacesEvent;
import javax.faces.event.PhaseEvent;
import javax.faces.event.PhaseId;
import javax.faces.event.PhaseListener;
import javax.faces.lifecycle.Lifecycle;
import javax.faces.lifecycle.LifecycleFactory;
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 { public static final String COMPONENT_TYPE = "javax.faces.ViewRoot"; public static final String COMPONENT_FAMILY = "javax.faces.ViewRoot"; public static final String UNIQUE_ID_PREFIX = "j_id"; private static final int ANY_PHASE_ORDINAL = PhaseId.ANY_PHASE.getOrdinal(); private final Logger logger = Logger.getLogger(UIViewRoot.class.getName()); /** * 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; private Locale _locale; private String _renderKitId; private String _viewId; // todo: is it right to save the state of _events and _phaseListeners? private List _events; private List _phaseListeners; private MethodExpression _beforePhaseListener; private MethodExpression _afterPhaseListener; private transient Lifecycle _lifecycle = null; private interface Processor { void process(); } /** * Construct an instance of the UIViewRoot. */ public UIViewRoot() { setRendererType(null); } public void queueEvent(FacesEvent event) { checkNull(event, "event"); if (_events == null) { _events = new ArrayList(); } _events.add(event); } public void processDecodes(final FacesContext context) { checkNull(context, "context"); process(context, PhaseId.APPLY_REQUEST_VALUES, new Processor() { public void process() { UIViewRoot.super.processDecodes(context); } }, true); } public void processValidators(final FacesContext context) { checkNull(context, "context"); process(context, PhaseId.PROCESS_VALIDATIONS, new Processor() { public void process() { UIViewRoot.super.processValidators(context); } }, true); } public void processUpdates(final FacesContext context) { checkNull(context, "context"); process(context, PhaseId.UPDATE_MODEL_VALUES, new Processor() { public void process() { UIViewRoot.super.processUpdates(context); } }, true); } public void processApplication(final FacesContext context) { checkNull(context, "context"); process(context, PhaseId.INVOKE_APPLICATION, null, true); } public void encodeBegin(FacesContext context) throws java.io.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) { super.encodeBegin(context); } } public void encodeEnd(FacesContext context) throws java.io.IOException { checkNull(context, "context"); super.encodeEnd(context); 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); } } /** * Provides a unique id for this component instance. */ public String createUniqueId() { StringBuilder bld = __getSharedStringBuilder(); return bld.append(UNIQUE_ID_PREFIX).append( _uniqueIdCounter++).toString(); } /** * The locale for this view. *

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

*/ @JSFProperty public Locale getLocale() { if (_locale != null) { return _locale; } ValueExpression expression = getValueExpression("locale"); if (expression != null) { return (Locale) expression.getValue(getFacesContext() .getELContext()); } else { Object locale = getFacesContext().getApplication().getViewHandler() .calculateLocale(getFacesContext()); if (locale instanceof Locale) { return (Locale) locale; } else if (locale instanceof String) { return stringToLocale((String) locale); } } return getFacesContext().getApplication().getViewHandler() .calculateLocale(getFacesContext()); } public void setLocale(Locale locale) { this._locale = locale; } private boolean process(FacesContext context, PhaseId phaseId, Processor processor, boolean broadcast) { if (!notifyListeners(context, phaseId, getBeforePhaseListener(), true)) { if (processor != null) processor.process(); if (broadcast) { _broadcastForPhase(phaseId); } } if (context.getRenderResponse() || context.getResponseComplete()) { clearEvents(); } return notifyListeners(context, phaseId, getAfterPhaseListener(), false); } /** * 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. */ private boolean notifyListeners(FacesContext context, PhaseId phaseId, MethodExpression listener, boolean beforePhase) { boolean skipPhase = false; if (listener != null || (_phaseListeners != null && !_phaseListeners.isEmpty())) { PhaseEvent event = createEvent(context, phaseId); if (listener != null) { listener.invoke(context.getELContext(), new Object[] { event }); skipPhase = context.getResponseComplete() || context.getRenderResponse(); } if (_phaseListeners != null && !_phaseListeners.isEmpty()) { for (PhaseListener phaseListener : _phaseListeners) { PhaseId listenerPhaseId = phaseListener.getPhaseId(); if (phaseId.equals(listenerPhaseId) || PhaseId.ANY_PHASE.equals(listenerPhaseId)) { if (beforePhase) { phaseListener.beforePhase(event); } else { phaseListener.afterPhase(event); } skipPhase = context.getResponseComplete() || context.getRenderResponse(); } } } } return skipPhase; } 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); } private void _broadcastForPhase(PhaseId phaseId) { if (_events == null) { return; } boolean abort = false; int phaseIdOrdinal = phaseId.getOrdinal(); for (ListIterator listiterator = _events.listIterator(); listiterator .hasNext();) { FacesEvent event = listiterator.next(); int ordinal = event.getPhaseId().getOrdinal(); if (ordinal == ANY_PHASE_ORDINAL || ordinal == phaseIdOrdinal) { UIComponent source = event.getComponent(); try { source.broadcast(event); } catch (AbortProcessingException e) { // abort event processing // Page 3-30 of JSF 1.1 spec: "Throw an // AbortProcessingException, to tell the JSF implementation // that no further broadcast of this event, or any further // events, should take place." abort = true; break; } finally { try { listiterator.remove(); } catch (ConcurrentModificationException cme) { int eventIndex = listiterator.previousIndex(); _events.remove(eventIndex); listiterator = _events.listIterator(); } } } } if (abort) { // TODO: abort processing of any event of any phase or just of any // event of the current phase??? clearEvents(); } } private void clearEvents() { _events = null; } private void checkNull(Object value, String valueLabel) { if (value == null) { throw new NullPointerException(valueLabel + " is null"); } } private Locale stringToLocale(String localeStr) { // locale expr: \[a-z]{2}((-|_)[A-Z]{2})? if (localeStr.contains("_") || localeStr.contains("-")) { if (localeStr.length() == 2) { // localeStr is the lang return new Locale(localeStr); } } else { if (localeStr.length() == 5) { String lang = localeStr.substring(0, 1); String country = localeStr.substring(3, 4); return new Locale(lang, country); } } return Locale.getDefault(); } /** * Defines what renderkit should be used to render this view. */ @JSFProperty public String getRenderKitId() { if (_renderKitId != null) { return _renderKitId; } ValueExpression expression = getValueExpression("renderKitId"); if (expression != null) { return (String) expression.getValue(getFacesContext() .getELContext()); } return null; } public void setRenderKitId(String renderKitId) { this._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(); } @Override public boolean isRendered() { //Call parent method due to TCK problems return super.isRendered(); } /** * 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" */ 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); } public String getId() { // Should just return null. But as setId passes the method on, do same here. return super.getId(); } /** * DO NOT USE. *

* As this component has no "id" property, it has no clientId property either. */ public String getClientId(FacesContext context) { return super.getClientId(context); //Call parent method due to TCK problems //return null; } /** * 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 _viewId; } 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. this._viewId = viewId; } /** * Adds a The phaseListeners attached to ViewRoot. */ public void addPhaseListener(PhaseListener phaseListener) { if (phaseListener == null) throw new NullPointerException("phaseListener"); if (_phaseListeners == null) _phaseListeners = new ArrayList(); _phaseListeners.add(phaseListener); } /** * Removes a The phaseListeners attached to ViewRoot. */ public void removePhaseListener(PhaseListener phaseListener) { if (phaseListener == null || _phaseListeners == null) return; _phaseListeners.remove(phaseListener); } /** * 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(stateHolder = true, returnSignature = "void", methodSignature = "javax.faces.event.PhaseEvent", jspName = "beforePhase") public MethodExpression getBeforePhaseListener() { if (_beforePhaseListener != null) { return _beforePhaseListener; } ValueExpression expression = getValueExpression("beforePhaseListener"); if (expression != null) { return (MethodExpression) expression.getValue(getFacesContext() .getELContext()); } return null; } /** * Sets * * @param beforePhaseListener * the new beforePhaseListener value */ public void setBeforePhaseListener(MethodExpression beforePhaseListener) { this._beforePhaseListener = beforePhaseListener; } /** * 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(stateHolder = true, returnSignature = "void", methodSignature = "javax.faces.event.PhaseEvent", jspName = "afterPhase") public MethodExpression getAfterPhaseListener() { if (_afterPhaseListener != null) { return _afterPhaseListener; } ValueExpression expression = getValueExpression("afterPhaseListener"); if (expression != null) { return (MethodExpression) expression.getValue(getFacesContext() .getELContext()); } return null; } /** * Sets * * @param afterPhaseListener * the new afterPhaseListener value */ public void setAfterPhaseListener(MethodExpression afterPhaseListener) { this._afterPhaseListener = afterPhaseListener; } @Override public Object saveState(FacesContext facesContext) { Object[] values = new Object[8]; values[0] = super.saveState(facesContext); values[1] = _locale; values[2] = _renderKitId; values[3] = _viewId; values[4] = _uniqueIdCounter; values[5] = saveAttachedState(facesContext, _phaseListeners); values[6] = saveAttachedState(facesContext, _beforePhaseListener); values[7] = saveAttachedState(facesContext, _afterPhaseListener); return values; } @Override public void restoreState(FacesContext facesContext, Object state) { Object[] values = (Object[]) state; super.restoreState(facesContext, values[0]); _locale = (Locale) values[1]; _renderKitId = (String) values[2]; _viewId = (String) values[3]; _uniqueIdCounter = (Long) values[4]; _phaseListeners = (List) restoreAttachedState(facesContext, values[5]); _beforePhaseListener = (MethodExpression) restoreAttachedState( facesContext, values[6]); _afterPhaseListener = (MethodExpression) restoreAttachedState( facesContext, values[7]); } @Override public String getFamily() { return COMPONENT_FAMILY; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy