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

jakarta.faces.component.UIComponentBase Maven / Gradle / Ivy

The 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 jakarta.faces.component;

import org.apache.myfaces.core.api.shared.ComponentUtils;
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;

import jakarta.el.ValueExpression;
import jakarta.faces.FacesException;
import jakarta.faces.component.behavior.Behavior;
import jakarta.faces.component.behavior.ClientBehavior;
import jakarta.faces.component.visit.VisitCallback;
import jakarta.faces.component.visit.VisitContext;
import jakarta.faces.context.FacesContext;
import jakarta.faces.event.AbortProcessingException;
import jakarta.faces.event.BehaviorEvent;
import jakarta.faces.event.FacesEvent;
import jakarta.faces.event.FacesListener;
import jakarta.faces.event.PostAddToViewEvent;
import jakarta.faces.event.PostValidateEvent;
import jakarta.faces.event.PreRemoveFromViewEvent;
import jakarta.faces.event.PreRenderComponentEvent;
import jakarta.faces.event.PreValidateEvent;
import jakarta.faces.event.SystemEvent;
import jakarta.faces.event.SystemEventListener;
import jakarta.faces.render.RenderKit;
import jakarta.faces.render.Renderer;
import jakarta.faces.view.Location;
import java.io.IOException;
import java.io.Serializable;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import jakarta.faces.event.PhaseId;
import org.apache.myfaces.core.api.shared.lang.Assert;
import org.apache.myfaces.core.api.shared.lang.SharedStringBuilder;


/**
 * Standard implementation of the UIComponent base class; all standard Faces components extend this class.
 * 

* Disclaimer: The official definition for the behaviour of this class is the Faces 1.1 specification but for legal * reasons the specification cannot be replicated here. Any javadoc here therefore describes the current implementation * rather than the spec, though this class has been verified as correctly implementing the spec. * * see Javadoc of Faces Specification for * more. */ @JSFComponent(type = "jakarta.faces.ComponentBase", family = "jakarta.faces.ComponentBase", desc = "base component when all components must inherit", tagClass = "jakarta.faces.webapp.UIComponentELTag", configExcluded = true) @JSFJspProperty(name = "binding", returnType = "jakarta.faces.component.UIComponent", longDesc = "Identifies a backing bean property (of type UIComponent or appropriate subclass) to bind " + "to this component instance. This value must be an EL expression.", desc = "backing bean property to bind to this component instance") public abstract class UIComponentBase extends UIComponent { private static Logger log = Logger.getLogger(UIComponentBase.class.getName()); private static final String _STRING_BUILDER_KEY = "jakarta.faces.component.UIComponentBase.SHARED_STRING_BUILDER"; // See ViewPoolProcessor for comments and usages static final int RESET_MODE_OFF = 0; static final int RESET_MODE_SOFT = 1; static final int RESET_MODE_HARD = 2; private _ComponentAttributesMap _attributesMap = null; private _PassThroughAttributesMap _passthroughAttributesMap = null; private List _childrenList = null; private Map _facetMap = null; private _DeltaList _facesListeners = null; private String _clientId = null; private String _id = null; private UIComponent _parent = null; private boolean _transient = false; private String _rendererType; private String _markCreated; private String _facetName; private int _capabilities = 0; private final static int FLAG_IS_RENDERER_TYPE_SET = 1; private final static int FLAG_ADDED_BY_HANDLER = 2; private final static int FLAG_FACET_CREATED_UIPANEL = 4; private final static int FLAG_PASSTHROUGH_ATTRIBUTE_MAP_SET = 8; /** * This map holds ClientBehavior instances. * * Note that BehaviorBase implements PartialStateHolder, so this class * should deal with that fact on clearInitialState() and * markInitialState() methods. * * Also, the map used by this instance is not set from outside this class. * * Note it is possible (but maybe not expected/valid) to manipulate * the values of the map(the list) but not put instances on the map * directly, because ClientBehaviorHolder.getClientBehaviors says that * this method should return a non null unmodificable map. * */ private Map> _behaviorsMap = null; private transient Map> _unmodifiableBehaviorsMap = null; private transient FacesContext _facesContext; private transient Boolean _cachedIsRendered; private transient Renderer _cachedRenderer; public UIComponentBase() { } /** * Set an identifier for this component which is unique within the scope of the nearest ancestor NamingContainer * component. The id is not necessarily unique across all components in the current view. *

* The id must start with an underscore if it is generated by the Faces framework, and must not start with an * underscore if it has been specified by the user (eg in a JSP tag). *

* The first character of the id must be an underscore or letter. Following characters may be letters, digits, * underscores or dashes. *

* Null is allowed as a parameter, and will reset the id to null. *

* The clientId of this component is reset by this method; see getClientId for more info. * * @throws IllegalArgumentException * if the id is not valid. */ @Override public void setId(String id) { isIdValid(id); _id = id; _clientId = null; } /** *

Set the parent UIComponent of this * UIComponent.

* * @param parent The new parent, or null for the root node * of a component tree */ @Override public void setParent(UIComponent parent) { // removing kids OR this is UIViewRoot if (parent == null) { // not UIViewRoot... if (_parent != null && _parent.isInView()) { // trigger the "remove event" lifecycle // and call setInView(false) for all children/facets // doing this => recursive FacesContext facesContext = getFacesContext(); if (facesContext.isProcessingEvents()) { _publishPreRemoveFromViewEvent(facesContext, this); } else { _updateInView(this, false); } } _parent = null; } else { _parent = parent; if (parent.isInView()) { // trigger the ADD_EVENT and call setInView(true) // recursive for all kids/facets... // Application.publishEvent(java.lang.Class, java.lang.Object) must be called, passing // PostAddToViewEvent.class as the first argument and the newly added component as the second // argument. FacesContext facesContext = parent.isCachedFacesContext() ? parent.getFacesContext() : getFacesContext(); if (facesContext.isProcessingEvents()) { _publishPostAddToViewEvent(facesContext, this); } else { _updateInView(this, true); } } } } /** * Publish PostAddToViewEvent to the component and all facets and children. * * @param context * @param component */ private static void _publishPostAddToViewEvent(FacesContext context, UIComponent component) { component.setInView(true); context.getApplication().publishEvent(context, PostAddToViewEvent.class, component.getClass(), component); if (component.getChildCount() > 0) { // PostAddToViewEvent could cause component relocation // (h:outputScript, h:outputStylesheet, composite:insertChildren, composite:insertFacet) // so we need to check if the component was relocated or not List children = component.getChildren(); for (int i = 0; i < children.size(); i++) { // spin on same index while component removed/replaced // to prevent skipping components: while (true) { UIComponent child = children.get(i); child.pushComponentToEL(context, child); try { _publishPostAddToViewEvent(context, child); } finally { child.popComponentFromEL(context); } if (i < children.size() && children.get(i) != child) { continue; } break; } } } if (component.getFacetCount() > 0) { for (UIComponent child : component.getFacets().values()) { child.pushComponentToEL(context, child); try { _publishPostAddToViewEvent(context, child); } finally { child.popComponentFromEL(context); } } } } /** * Publish PreRemoveFromViewEvent to the component and all facets and children. * * @param context * @param component */ private static void _publishPreRemoveFromViewEvent(FacesContext context, UIComponent component) { component.setInView(false); context.getApplication().publishEvent(context, PreRemoveFromViewEvent.class, component.getClass(), component); if (component.getChildCount() > 0) { for (int i = 0, childCount = component.getChildCount(); i < childCount; i++) { UIComponent child = component.getChildren().get(i); _publishPreRemoveFromViewEvent(context, child); } } if (component.getFacetCount() > 0) { for (UIComponent child : component.getFacets().values()) { _publishPreRemoveFromViewEvent(context, child); } } } private static void _updateInView(UIComponent component, boolean isInView) { component.setInView(isInView); if (component.getChildCount() > 0) { for (int i = 0, childCount = component.getChildCount(); i < childCount; i++) { UIComponent child = component.getChildren().get(i); _updateInView(child, isInView); } } if (component.getFacetCount() > 0) { for (UIComponent child : component.getFacets().values()) { _updateInView(child, isInView); } } } /** * * @param eventName * @param behavior * * @since 2.0 */ public void addClientBehavior(String eventName, ClientBehavior behavior) { Collection eventNames = getEventNames(); if (eventNames == null) { throw new IllegalStateException("Attempting to add a Behavior to a component, " + "that does not support any event types. getEventTypes() must return a non-null Set."); } if (eventNames.contains(eventName)) { if (_behaviorsMap == null) { _behaviorsMap = new HashMap<>(5, 1f); } List behaviorsForEvent = _behaviorsMap.get(eventName); if (behaviorsForEvent == null) { // Normally have client only 1 client behaviour per event name, so size 2 must be sufficient: behaviorsForEvent = new _DeltaList<>(2); _behaviorsMap.put(eventName, behaviorsForEvent); } behaviorsForEvent.add(behavior); _unmodifiableBehaviorsMap = null; } } /** * Invoke any listeners attached to this object which are listening for an event whose type matches the specified * event's runtime type. *

* This method does not propagate the event up to parent components, ie listeners attached to parent components * don't automatically get called. *

* If any of the listeners throws AbortProcessingException then that exception will prevent any further listener * callbacks from occurring, and the exception propagates out of this method without alteration. *

* ActionEvent events are typically queued by the renderer associated with this component in its decode method; * ValueChangeEvent events by the component's validate method. In either case the event's source property references * a component. At some later time the UIViewRoot component iterates over its queued events and invokes the * broadcast method on each event's source object. * * @param event * must not be null. */ @Override public void broadcast(FacesEvent event) throws AbortProcessingException { Assert.notNull(event, "event"); if (event instanceof BehaviorEvent && event.getComponent() == this) { Behavior behavior = ((BehaviorEvent) event).getBehavior(); behavior.broadcast((BehaviorEvent) event); } if (_facesListeners == null) { return; } // perf: _facesListeners is RandomAccess instance (jakarta.faces.component._DeltaList) for (int i = 0, size = _facesListeners.size(); i < size; i++) { FacesListener facesListener = _facesListeners.get(i); if (event.isAppropriateListener(facesListener)) { event.processListener(facesListener); } } } @Override public void clearInitialState() { super.clearInitialState(); if (_facesListeners != null) { _facesListeners.clearInitialState(); } if (_behaviorsMap != null) { for (Map.Entry> entry : _behaviorsMap.entrySet()) { ((PartialStateHolder) entry.getValue()).clearInitialState(); } } if (_systemEventListenerClassMap != null) { for (Map.Entry, List> entry : _systemEventListenerClassMap.entrySet()) { ((PartialStateHolder) entry.getValue()).clearInitialState(); } } _capabilities &= ~(FLAG_IS_RENDERER_TYPE_SET); } /** * Check the submitted form parameters for data associated with this component. This default implementation * delegates to this component's renderer if there is one, and otherwise ignores the call. */ @Override public void decode(FacesContext context) { Assert.notNull(context, "context"); setCachedRenderer(null); Renderer renderer = getRenderer(context); if (renderer != null) { setCachedRenderer(renderer); try { renderer.decode(context, this); } finally { setCachedRenderer(null); } } } @Override public void encodeAll(FacesContext context) throws IOException { Assert.notNull(context, "context"); pushComponentToEL(context, this); try { setCachedIsRendered(null); boolean rendered; try { setCachedFacesContext(context); rendered = isRendered(); } finally { setCachedFacesContext(null); } setCachedIsRendered(rendered); if (!rendered) { setCachedIsRendered(null); return; } setCachedRenderer(null); setCachedRenderer(getRenderer(context)); } finally { popComponentFromEL(context); } try { this.encodeBegin(context); // rendering children boolean rendersChildren; try { setCachedFacesContext(context); rendersChildren = this.getRendersChildren(); } finally { setCachedFacesContext(null); } if (rendersChildren) { this.encodeChildren(context); } // let children render itself else { if (this.getChildCount() > 0) { for (int i = 0; i < this.getChildCount(); i++) { UIComponent comp = this.getChildren().get(i); comp.encodeAll(context); } } } this.encodeEnd(context); } finally { setCachedIsRendered(null); setCachedRenderer(null); } } @Override public void encodeBegin(FacesContext context) throws IOException { Assert.notNull(context, "context"); try { setCachedFacesContext(context); // Call UIComponent.pushComponentToEL(jakarta.faces.context.FacesContext, jakarta.faces.component.UIComponent) pushComponentToEL(context, this); if (isRendered()) { // If our rendered property is true, render the beginning of the current state of this // UIComponent to the response contained in the specified FacesContext. // Call Application.publishEvent(java.lang.Class, java.lang.Object), passing BeforeRenderEvent.class as // the first argument and the component instance to be rendered as the second argument. // The main issue we have here is that the listeners are normally just registered // to UIComponent, how do we deal with inherited ones? // We have to ask the EG context.getApplication().publishEvent(context, PreRenderComponentEvent.class, UIComponent.class, this); Renderer renderer = getRenderer(context); if (renderer != null) { // If a Renderer is associated with this UIComponent, the actual encoding will be delegated to // Renderer.encodeBegin(FacesContext, UIComponent). renderer.encodeBegin(context, this); } } } finally { setCachedFacesContext(null); } } @Override public void encodeChildren(FacesContext context) throws IOException { Assert.notNull(context, "context"); boolean isCachedFacesContext = isCachedFacesContext(); try { if (!isCachedFacesContext) { setCachedFacesContext(context); } if (isRendered()) { // If our rendered property is true, render the child UIComponents of this UIComponent. Renderer renderer = getRenderer(context); if (renderer == null) { // If no Renderer is associated with this UIComponent, iterate over each of the children of this // component and call UIComponent.encodeAll(jakarta.faces.context.FacesContext). if (getChildCount() > 0) { for (int i = 0, childCount = getChildCount(); i < childCount; i++) { UIComponent child = getChildren().get(i); child.encodeAll(context); } } } else { // If a Renderer is associated with this UIComponent, the actual encoding will be delegated to // Renderer.encodeChildren(FacesContext, UIComponent). renderer.encodeChildren(context, this); } } } finally { if (!isCachedFacesContext) { setCachedFacesContext(null); } } } @Override public void encodeEnd(FacesContext context) throws IOException { Assert.notNull(context, "context"); try { setCachedFacesContext(context); if (isRendered()) { // If our rendered property is true, render the ending of the current state of this UIComponent. Renderer renderer = getRenderer(context); if (renderer != null) { // If a Renderer is associated with this UIComponent, the actual encoding will be delegated to // Renderer.encodeEnd(FacesContext, UIComponent). renderer.encodeEnd(context, this); } } } finally { // Call UIComponent.popComponentFromEL(jakarta.faces.context.FacesContext). before returning regardless // of the value of the rendered property. popComponentFromEL(context); setCachedFacesContext(null); } } /** * Standard method for finding other components by id, inherited by most UIComponent objects. *

* The lookup is performed in a manner similar to finding a file in a filesystem; there is a "base" at which to * start, and the id can be for something in the "local directory", or can include a relative path. Here, * NamingContainer components fill the role of directories, and ":" is the "path separator". Note, however, that * although components have a strict parent/child hierarchy, component ids are only prefixed ("namespaced") with the * id of their parent when the parent is a NamingContainer. *

* The base node at which the search starts is determined as follows: *

    *
  • When expr starts with ':', the search starts with the root component of the tree that this component is in * (ie the ancestor whose parent is null). *
  • Otherwise, if this component is a NamingContainer then the search starts with this component. *
  • Otherwise, the search starts from the nearest ancestor NamingContainer (or the root component if there is no * NamingContainer ancestor). *
* * @param expr * is of form "id1:id2:id3". * @return UIComponent or null if no component with the specified id is found. */ @Override public UIComponent findComponent(String expr) { Assert.notNull(expr, "expr"); if (expr.length() == 0) { return null; } char separatorChar = getFacesContext().getNamingContainerSeparatorChar(); UIComponent findBase; if (expr.charAt(0) == separatorChar) { findBase = ComponentUtils.findRootComponent(this); expr = expr.substring(1); } else { if (this instanceof NamingContainer) { findBase = this; } else { findBase = ComponentUtils.findClosestNamingContainer(this, true /* root if not found */); } } int separator = expr.indexOf(separatorChar); if (separator == -1) { return ComponentUtils.findComponent(findBase, expr, separatorChar); } String id = expr.substring(0, separator); findBase = ComponentUtils.findComponent(findBase, id, separatorChar); if (findBase == null) { return null; } if (!(findBase instanceof NamingContainer)) { throw new IllegalArgumentException("Intermediate identifier " + id + " in search expression " + expr + " identifies a UIComponent that is not a NamingContainer"); } return findBase.findComponent(expr.substring(separator + 1)); } /** * Get a map through which all the UIComponent's properties, value-bindings and non-property attributes can be read * and written. *

* When writing to the returned map: *

    *
  • If this component has an explicit property for the specified key then the setter method is called. An * IllegalArgumentException is thrown if the property is read-only. If the property is readable then the old value * is returned, otherwise null is returned. *
  • Otherwise the key/value pair is stored in a map associated with the component. *
* Note that value-bindings are not written by put calls to this map. Writing to the attributes map using a * key for which a value-binding exists will just store the value in the attributes map rather than evaluating the * binding, effectively "hiding" the value-binding from later attributes.get calls. Setter methods on components * commonly do not evaluate a binding of the same name; they just store the provided value directly on the * component. *

* When reading from the returned map: *

    *
  • If this component has an explicit property for the specified key then the getter method is called. If the * property exists, but is read-only (ie only a setter method is defined) then an IllegalArgumentException is * thrown. *
  • If the attribute map associated with the component has an entry with the specified key, then that is * returned. *
  • If this component has a value-binding for the specified key, then the value-binding is evaluated to fetch the * value. *
  • Otherwise, null is returned. *
* Note that components commonly define getter methods such that they evaluate a value-binding of the same name if * there isn't yet a local property. *

* Assigning values to the map which are not explicit properties on the underlying component can be used to "tunnel" * attributes from the JSP tag (or view-specific equivalent) to the associated renderer without modifying the * component itself. *

* Any value-bindings and non-property attributes stored in this map are automatically serialized along with the * component when the view is serialized. */ @Override public Map getAttributes() { if (_attributesMap == null) { _attributesMap = new _ComponentAttributesMap(this); } return _attributesMap; } @Override public Map getPassThroughAttributes(boolean create) { // Take into account the param "create" in MyFaces case does not have // sense at all if (_passthroughAttributesMap == null) { if (!create) { if ((_capabilities & FLAG_PASSTHROUGH_ATTRIBUTE_MAP_SET) != 0) { // Was already created, return wrapper _passthroughAttributesMap = new _PassThroughAttributesMap(this); } } else { _passthroughAttributesMap = new _PassThroughAttributesMap(this); _capabilities |= FLAG_PASSTHROUGH_ATTRIBUTE_MAP_SET; } } return _passthroughAttributesMap; } /** * Return the number of direct child components this component has. *

* Identical to getChildren().size() except that when this component has no children this method will not force an * empty list to be created. */ @Override public int getChildCount() { return _childrenList == null ? 0 : _childrenList.size(); } /** * Return a list of the UIComponent objects which are direct children of this component. *

* The list object returned has some non-standard behaviour: *

    *
  • The list is type-checked; only UIComponent objects can be added. *
  • If a component is added to the list with an id which is the same as some other component in the list then an * exception is thrown. However multiple components with a null id may be added. *
  • The component's parent property is set to this component. If the component already had a parent, then the * component is first removed from its original parent's child list. *
*/ @Override public List getChildren() { if (_childrenList == null) { _childrenList = new _ComponentChildrenList(this); } return _childrenList; } /** * * @return * * @since 2.0 */ public Map> getClientBehaviors() { if(_behaviorsMap == null) { return Collections.emptyMap(); } return wrapBehaviorsMap(); } /** * Get a string which can be output to the response which uniquely identifies this UIComponent within the current * view. *

* The component should have an id attribute already assigned to it; however if the id property is currently null * then a unique id is generated and set for this component. This only happens when components are programmatically * created without ids, as components created by a ViewHandler should be assigned ids when they are created. *

* If this component is a descendant of a NamingContainer then the client id is of form * "{namingContainerId}:{componentId}". Note that the naming container's id may itself be of compound form if it has * an ancestor naming container. Note also that this only applies to naming containers; other UIComponent types in * the component's ancestry do not affect the clientId. *

* Finally the renderer associated with this component is asked to convert the id into a suitable form. This allows * escaping of any characters in the clientId which are significant for the markup language generated by that * renderer. */ @Override public String getClientId(FacesContext context) { Assert.notNull(context, "context"); if (_clientId != null) { return _clientId; } String id = getId(); if (id == null) { // Although this is an error prone side effect, we automatically create a new id // just to be compatible to the RI // The documentation of UniqueIdVendor says that this interface should be implemented by // components that also implements NamingContainer. The only component that does not implement // NamingContainer but UniqueIdVendor is UIViewRoot. Anyway we just can't be 100% sure about this // fact, so it is better to scan for the closest UniqueIdVendor. If it is not found use // viewRoot.createUniqueId, otherwise use UniqueIdVendor.createUniqueId(context,seed). UniqueIdVendor parentUniqueIdVendor = ComponentUtils.findClosest(UniqueIdVendor.class, this); if (parentUniqueIdVendor == null) { UIViewRoot viewRoot = context.getViewRoot(); if (viewRoot != null) { id = viewRoot.createUniqueId(); } else { // The RI throws a NPE String location = getComponentLocation(this); throw new FacesException("Cannot create clientId. No id is assigned for component" + " to create an id and UIViewRoot is not defined: " + ComponentUtils.getPathToComponent(this) + (location != null ? " created from: " + location : "")); } } else { id = parentUniqueIdVendor.createUniqueId(context, null); } setId(id); } UIComponent namingContainer = ComponentUtils.findClosestNamingContainer(this, false); if (namingContainer != null) { String containerClientId = namingContainer.getContainerClientId(context); if (containerClientId != null) { StringBuilder bld = _getSharedStringBuilder(context); _clientId = bld.append(containerClientId).append( context.getNamingContainerSeparatorChar()).append(id).toString(); } else { _clientId = id; } } else { _clientId = id; } Renderer renderer = getRenderer(context); if (renderer != null) { _clientId = renderer.convertClientId(context, _clientId); } // -=Leonardo Uribe=- In jsf 1.1 and 1.2 this warning has sense, but in jsf 2.0 it is common to have // components without any explicit id (UIViewParameter components and UIOuput resource components) instances. // So, this warning is becoming obsolete in this new context and should be removed. //if (idWasNull && log.isLoggable(Level.WARNING)) //{ // log.warning("WARNING: Component " + _clientId // + " just got an automatic id, because there was no id assigned yet. " // + "If this component was created dynamically (i.e. not by a JSP tag) you should assign it an " // + "explicit static id or assign it the id you get from " // + "the createUniqueId from the current UIViewRoot " // + "component right after creation! Path to Component: " + _ComponentUtils.getPathToComponent(this)); //} return _clientId; } /** * * @return * * @since 2.0 */ public String getDefaultEventName() { // if a default event exists for a component, this method is overriden thus assume null return null; } /** * * @return * * @since 2.0 */ public Collection getEventNames() { // must be specified by the implementing component. // Returning null will force an error message in addClientBehavior. return null; } @Override public UIComponent getFacet(String name) { return _facetMap == null ? null : _facetMap.get(name); } /** * @since 1.2 */ @Override public int getFacetCount() { return _facetMap == null ? 0 : _facetMap.size(); } @Override public Map getFacets() { if (_facetMap == null) { _facetMap = new _ComponentFacetMap<>(this); } return _facetMap; } @Override public Iterator getFacetsAndChildren() { // we can't use _facetMap and _childrenList here directly, // because some component implementation could keep their // own properties for facets and children and just override // getFacets() and getChildren() (e.g. seen in PrimeFaces). // See MYFACES-2611 for details. if (getFacetCount() == 0) { if (getChildCount() == 0) { return Collections.emptyIterator(); } return getChildren().iterator(); } else { if (getChildCount() == 0) { return getFacets().values().iterator(); } return new _FacetsAndChildrenIterator(getFacets(), getChildren()); } } /** * Get a string which uniquely identifies this UIComponent within the scope of the nearest ancestor NamingContainer * component. The id is not necessarily unique across all components in the current view. */ @JSFProperty(rtexprvalue = true) @Override public String getId() { return _id; } @Override public UIComponent getParent() { return _parent; } @Override public String getRendererType() { // rendererType is literal-only, no ValueExpression - MYFACES-3136: // Even if this is true, according to Faces spec section 8 Rendering Model, // this part is essential to implement "delegated implementation" pattern, // so we can't do this optimization here. Instead, Faces developers could prevent // this evaluation overriding this method directly. if (_rendererType != null) { return _rendererType; } ValueExpression expression = getValueExpression("rendererType"); if (expression != null) { return expression.getValue(getFacesContext().getELContext()); } return null; } /** * Indicates whether this component or its renderer manages the invocation of the rendering methods of its child * components. When this is true: *

    *
  • This component's encodeBegin method will only be called after all the child components have been created and * added to this component.
  • This component's encodeChildren method will be called after its encodeBegin method. * Components for which this method returns false do not get this method invoked at all.
  • No rendering methods * will be called automatically on child components; this component is required to invoke the * encodeBegin/encodeEnd/etc on them itself. *
*/ @Override public boolean getRendersChildren() { Renderer renderer = getRenderer(getFacesContext()); return renderer != null ? renderer.getRendersChildren() : false; } /** * invokeOnComponent must be implemented in UIComponentBase too... */ @Override public boolean invokeOnComponent(FacesContext context, String clientId, ContextCallback callback) throws FacesException { if (isCachedFacesContext()) { return super.invokeOnComponent(context, clientId, callback); } else { try { setCachedFacesContext(context); return super.invokeOnComponent(context, clientId, callback); } finally { setCachedFacesContext(null); } } } @Override public boolean visitTree(VisitContext context, VisitCallback callback) { if (isCachedFacesContext()) { return super.visitTree(context, callback); } else { try { setCachedFacesContext(context.getFacesContext()); return super.visitTree(context, callback); } finally { setCachedFacesContext(null); } } } /** * A boolean value that indicates whether this component should be rendered. Default value: true. **/ @Override @JSFProperty public boolean isRendered() { if (_cachedIsRendered != null) { return Boolean.TRUE.equals(_cachedIsRendered); } return (Boolean) getStateHelper().eval(PropertyKeys.rendered, DEFAULT_RENDERED); } @JSFProperty(literalOnly = true, istransient = true, tagExcluded = true) @Override public boolean isTransient() { return _transient; } @Override public void markInitialState() { super.markInitialState(); // Enable copyFullInitialState behavior when delta is written into this component. ((_DeltaStateHelper)getStateHelper()).setCopyFullInitialState(true); if (_facesListeners != null) { _facesListeners.markInitialState(); } if (_behaviorsMap != null) { for (Map.Entry> entry : _behaviorsMap.entrySet()) { ((PartialStateHolder) entry.getValue()).markInitialState(); } } if (_systemEventListenerClassMap != null) { for (Map.Entry, List> entry : _systemEventListenerClassMap.entrySet()) { ((PartialStateHolder) entry.getValue()).markInitialState(); } } } @Override protected void addFacesListener(FacesListener listener) { Assert.notNull(listener, "listener"); if (_facesListeners == null) { // How many facesListeners have single component normally? _facesListeners = new _DeltaList<>(5); } _facesListeners.add(listener); } @Override protected FacesContext getFacesContext() { if (_facesContext == null) { return FacesContext.getCurrentInstance(); } else { return _facesContext; } } // FIXME: Notify EG for generic usage @Override protected FacesListener[] getFacesListeners(Class clazz) { Assert.notNull(clazz, "clazz"); if (!FacesListener.class.isAssignableFrom(clazz)) { throw new IllegalArgumentException("Class " + clazz.getName() + " must implement " + FacesListener.class); } if (_facesListeners == null) { return (FacesListener[]) Array.newInstance(clazz, 0); } List lst = null; // perf: _facesListeners is RandomAccess instance (jakarta.faces.component._DeltaList) for (int i = 0, size = _facesListeners.size(); i < size; i++) { FacesListener facesListener = _facesListeners.get(i); if (facesListener != null && clazz.isAssignableFrom(facesListener.getClass())) { if (lst == null) { lst = new ArrayList<>(5); } lst.add(facesListener); } } if (lst == null || lst.isEmpty()) { return (FacesListener[]) Array.newInstance(clazz, 0); } return lst.toArray((FacesListener[]) Array.newInstance(clazz, lst.size())); } @Override protected Renderer getRenderer(FacesContext context) { Assert.notNull(context, "context"); Renderer renderer = getCachedRenderer(); if (renderer != null) { return renderer; } String rendererType = getRendererType(); if (rendererType == null) { return null; } RenderKit renderKit = context.getRenderKit(); renderer = renderKit.getRenderer(getFamily(), rendererType); if (renderer == null) { String location = getComponentLocation(this); String logStr = "No Renderer found for component " + ComponentUtils.getPathToComponent(this) + " (component-family=" + getFamily() + ", renderer-type=" + rendererType + ')' + (location != null ? " created from: " + location : ""); getFacesContext().getExternalContext().log(logStr); log.warning(logStr); } return renderer; } @Override protected void removeFacesListener(FacesListener listener) { Assert.notNull(listener, "listener"); if (_facesListeners != null) { _facesListeners.remove(listener); } } @Override public void queueEvent(FacesEvent event) { Assert.notNull(event, "event"); UIComponent parent = getParent(); if (parent == null) { throw new IllegalStateException("component is not a descendant of a UIViewRoot"); } parent.queueEvent(event); } @Override public void processDecodes(FacesContext context) { try { setCachedFacesContext(context); // Call UIComponent.pushComponentToEL(jakarta.faces.context.FacesContext, jakarta.faces.component.UIComponent) pushComponentToEL(context, this); if (_isPhaseExecutable(context)) { // Call the processDecodes() method of all facets and children of this UIComponent, in the order // determined by a call to getFacetsAndChildren(). int facetCount = getFacetCount(); if (facetCount > 0) { for (UIComponent facet : getFacets().values()) { facet.processDecodes(context); } } for (int i = 0, childCount = getChildCount(); i < childCount; i++) { UIComponent child = getChildren().get(i); child.processDecodes(context); } try { // Call the decode() method of this component. decode(context); } catch (RuntimeException e) { // If a RuntimeException is thrown during decode processing, call FacesContext.renderResponse() // and re-throw the exception. context.renderResponse(); throw e; } } } finally { // Call UIComponent.popComponentFromEL(jakarta.faces.context.FacesContext) from inside of a finally // block, just before returning. popComponentFromEL(context); setCachedFacesContext(null); } } @Override public void processValidators(FacesContext context) { try { setCachedFacesContext(context); // Call UIComponent.pushComponentToEL(jakarta.faces.context.FacesContext, jakarta.faces.component.UIComponent) pushComponentToEL(context, this); if (_isPhaseExecutable(context)) { //Pre validation event dispatch for component context.getApplication().publishEvent(context, PreValidateEvent.class, getClass(), this); try { // Call the processValidators() method of all facets and children of this UIComponent, in the order // determined by a call to getFacetsAndChildren(). int facetCount = getFacetCount(); if (facetCount > 0) { for (UIComponent facet : getFacets().values()) { facet.processValidators(context); } } for (int i = 0, childCount = getChildCount(); i < childCount; i++) { UIComponent child = getChildren().get(i); child.processValidators(context); } } finally { context.getApplication().publishEvent(context, PostValidateEvent.class, getClass(), this); } } } finally { popComponentFromEL(context); setCachedFacesContext(null); } } /** * This isn't an input component, so just pass on the processUpdates call to child components and facets that might * be input components. *

* Components that were never rendered can't possibly be receiving update data (no corresponding fields were ever * put into the response) so if this component is not rendered then this method does not invoke processUpdates on * its children. */ @Override public void processUpdates(FacesContext context) { try { setCachedFacesContext(context); // Call UIComponent.pushComponentToEL(jakarta.faces.context.FacesContext, jakarta.faces.component.UIComponent) pushComponentToEL(context, this); if (_isPhaseExecutable(context)) { // Call the processUpdates() method of all facets and children of this UIComponent, in the order // determined by a call to getFacetsAndChildren(). int facetCount = getFacetCount(); if (facetCount > 0) { for (UIComponent facet : getFacets().values()) { facet.processUpdates(context); } } for (int i = 0, childCount = getChildCount(); i < childCount; i++) { UIComponent child = getChildren().get(i); child.processUpdates(context); } } } finally { // After returning from the processUpdates() method on a child or facet, call // UIComponent.popComponentFromEL(jakarta.faces.context.FacesContext) popComponentFromEL(context); setCachedFacesContext(null); } } @Override public Object processSaveState(FacesContext context) { Assert.notNull(context, "context"); if (isTransient()) { // consult the transient property of this component. If true, just return null. return null; } // Call UIComponent.pushComponentToEL(jakarta.faces.context.FacesContext, jakarta.faces.component.UIComponent) pushComponentToEL(context, this); Map facetMap; List childrenList; Object savedState; try { facetMap = null; int facetCount = getFacetCount(); if (facetCount > 0) { // Call the processSaveState() method of all facets and children of this UIComponent in the order // determined by a call to getFacetsAndChildren(), skipping children and facets that are transient. // To improve speed and robustness, the facets and children processing is splited to maintain the // facet --> state coherence based on the facet's name for (Map.Entry entry : getFacets().entrySet()) { UIComponent component = entry.getValue(); if (!component.isTransient()) { if (facetMap == null) { facetMap = new HashMap<>(facetCount, 1); } facetMap.put(entry.getKey(), component.processSaveState(context)); } } } childrenList = null; int childCount = getChildCount(); if (childCount > 0) { // Call the processSaveState() method of all facets and children of this UIComponent in the order // determined by a call to getFacetsAndChildren(), skipping children and facets that are transient. // To improve speed and robustness, the facets and children processing is splited to maintain the // facet --> state coherence based on the facet's name for (int i = 0; i < childCount; i++) { UIComponent child = getChildren().get(i); if (!child.isTransient()) { if (childrenList == null) { childrenList = new ArrayList<>(childCount); } Object childState = child.processSaveState(context); if (childState != null) { // FIXME: Isn't that check dangerous for restoration since the child isn't marked transient? childrenList.add(childState); } } } } // Call the saveState() method of this component. savedState = saveState(context); } finally { // Ensure that UIComponent.popComponentFromEL(jakarta.faces.context.FacesContext) is called // correctly after each child or facet. popComponentFromEL(context); } // Encapsulate the child state and your state into a Serializable Object and return it. return new Object[] { savedState, facetMap, childrenList }; } @SuppressWarnings("unchecked") @Override public void processRestoreState(FacesContext context, Object state) { Assert.notNull(context, "context"); Object[] stateValues = (Object[]) state; try { // Call UIComponent.pushComponentToEL(jakarta.faces.context.FacesContext, jakarta.faces.component.UIComponent) pushComponentToEL(context, this); // Call the restoreState() method of this component. restoreState(context, stateValues[0]); Map facetMap = (Map) stateValues[1]; if (facetMap != null && getFacetCount() > 0) { // Call the processRestoreState() method of all facets and children of this UIComponent in the order // determined by a call to getFacetsAndChildren(). // To improve speed and robustness, the facets and children processing is splited to maintain the // facet --> state coherence based on the facet's name for (Map.Entry entry : getFacets().entrySet()) { Object facetState = facetMap.get(entry.getKey()); if (facetState != null) { entry.getValue().processRestoreState(context, facetState); } else { context.getExternalContext().log("No state found to restore facet " + entry.getKey()); } } } List childrenList = (List) stateValues[2]; if (childrenList != null && getChildCount() > 0) { // Call the processRestoreState() method of all facets and children of this UIComponent in the order // determined by a call to getFacetsAndChildren(). // To improve speed and robustness, the facets and children processing is splited to maintain the // facet --> state coherence based on the facet's name int idx = 0; for (int i = 0, childCount = getChildCount(); i < childCount; i++) { UIComponent child = getChildren().get(i); if (!child.isTransient()) { Object childState = childrenList.get(idx++); if (childState != null) { child.processRestoreState(context, childState); } else { context.getExternalContext().log("No state found to restore child of component " + getId()); } } } } } finally { // After returning from the processRestoreState() method on a child or facet, call // UIComponent.popComponentFromEL(jakarta.faces.context.FacesContext) popComponentFromEL(context); } } /** * Gets the Location of the given UIComponent from its attribute map. * @param component * @return */ private String getComponentLocation(UIComponent component) { Location location = (Location) component.getAttributes().get(UIComponent.VIEW_LOCATION_KEY); return location == null ? null : location.toString(); } @Override public void setTransient(boolean transientFlag) { _transient = transientFlag; } /** * Serializes objects which are "attached" to this component but which are not UIComponent children of it. Examples * are validator and listener objects. To be precise, it returns an object which implements java.io.Serializable, * and which when serialized will persist the state of the provided object. *

* If the attachedObject is a List then every object in the list is saved via a call to this method, and the * returned wrapper object contains a List object. *

* If the object implements StateHolder then the object's saveState is called immediately, and a wrapper is returned * which contains both this saved state and the original class name. However in the case where the * StateHolder.isTransient method returns true, null is returned instead. *

* If the object implements java.io.Serializable then the object is simply returned immediately; standard java * serialization will later be used to store this object. *

* In all other cases, a wrapper is returned which simply stores the type of the provided object. When deserialized, * a default instance of that type will be recreated. */ public static Object saveAttachedState(FacesContext context, Object attachedObject) { if (context == null) { throw new NullPointerException ("context"); } if (attachedObject == null) { return null; } // StateHolder interface should take precedence over // List children if (attachedObject instanceof StateHolder) { StateHolder holder = (StateHolder) attachedObject; if (holder.isTransient()) { return null; } return new _AttachedStateWrapper(attachedObject.getClass(), holder.saveState(context)); } else if (attachedObject instanceof Collection) { if (ArrayList.class.equals(attachedObject.getClass())) { ArrayList list = (ArrayList) attachedObject; int size = list.size(); List lst = new ArrayList(size); for (int i = 0; i < size; i++) { Object item = list.get(i); if (item != null) { lst.add(saveAttachedState(context, item)); } } return new _AttachedListStateWrapper(lst); } else { List lst = new ArrayList<>(((Collection) attachedObject).size()); for (Object item : (Collection) attachedObject) { if (item != null) { lst.add(saveAttachedState(context, item)); } } return new _AttachedCollectionStateWrapper(attachedObject.getClass(), lst); } } else if (attachedObject instanceof Serializable) { return attachedObject; } else { return new _AttachedStateWrapper(attachedObject.getClass(), null); } } public static Object restoreAttachedState(FacesContext context, Object stateObj) throws IllegalStateException { Assert.notNull(context, "context"); if (stateObj == null) { return null; } if (stateObj instanceof _AttachedListStateWrapper) { // perf: getWrappedStateList in _AttachedListStateWrapper is always ArrayList: see saveAttachedState ArrayList lst = (ArrayList) ((_AttachedListStateWrapper) stateObj).getWrappedStateList(); List restoredList = new ArrayList(lst.size()); for (int i = 0, size = lst.size(); i < size; i++) { Object item = lst.get(i); restoredList.add(restoreAttachedState(context, item)); } return restoredList; } else if (stateObj instanceof _AttachedCollectionStateWrapper) { _AttachedCollectionStateWrapper wrappedState = (_AttachedCollectionStateWrapper) stateObj; Class clazz = wrappedState.getClazz(); List lst = wrappedState.getWrappedStateList(); Collection restoredList; try { restoredList = (Collection) clazz.newInstance(); } catch (InstantiationException e) { throw new RuntimeException("Could not restore StateHolder of type " + clazz.getName() + " (missing no-args constructor?)", e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } for (int i = 0; i < lst.size(); i++) { Object item = lst.get(i); restoredList.add(restoreAttachedState(context, item)); } return restoredList; } else if (stateObj instanceof _AttachedStateWrapper) { Class clazz = ((_AttachedStateWrapper) stateObj).getClazz(); Object restoredObject; try { restoredObject = clazz.newInstance(); } catch (InstantiationException e) { throw new RuntimeException("Could not restore StateHolder of type " + clazz.getName() + " (missing no-args constructor?)", e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } if (restoredObject instanceof StateHolder) { _AttachedStateWrapper wrapper = (_AttachedStateWrapper) stateObj; Object wrappedState = wrapper.getWrappedStateObject(); StateHolder holder = (StateHolder) restoredObject; holder.restoreState(context, wrappedState); } return restoredObject; } else { return stateObj; } } private static final int FULL_STATE_ARRAY_SIZE = 10; /** * Invoked after the render phase has completed, this method returns an object which can be passed to the * restoreState of some other instance of UIComponentBase to reset that object's state to the same values as this * object currently has. */ @Override public Object saveState(FacesContext context) { if (context == null) { throw new NullPointerException ("context"); } if (context.getViewRoot() != null) { if (context.getViewRoot().getResetSaveStateMode() == RESET_MODE_SOFT) { // Force FacesContext cleanup to prevent leak it. setCachedFacesContext(null); // Reset state to recalculate state first. StateHelper stateHelper = getStateHelper(false); if (stateHelper != null) { ((_DeltaStateHelper)stateHelper).resetSoftState(context); } } if (context.getViewRoot().getResetSaveStateMode() == RESET_MODE_HARD) { // Force FacesContext cleanup to prevent leak it. setCachedFacesContext(null); // Reset state to recalculate state first. StateHelper stateHelper = getStateHelper(false); if (stateHelper != null) { ((_DeltaStateHelper)stateHelper).resetHardState(context); } } } if (initialStateMarked()) { //Delta //_id and _clientId was already restored from template //and never changes during component life. Object facesListenersSaved = saveFacesListenersList(context); Object behaviorsMapSaved = saveBehaviorsMap(context); Object systemEventListenerClassMapSaved = saveSystemEventListenerClassMap(context); Object stateHelperSaved = null; StateHelper stateHelper = getStateHelper(false); if (stateHelper != null) { stateHelperSaved = stateHelper.saveState(context); } if (facesListenersSaved == null && stateHelperSaved == null && behaviorsMapSaved == null && systemEventListenerClassMapSaved == null && !((_capabilities & FLAG_IS_RENDERER_TYPE_SET) != 0)) { return null; } Object transientState = null; if (context.getCurrentPhaseId() != null && !PhaseId.RENDER_RESPONSE.equals(context.getCurrentPhaseId())) { transientState = saveTransientState(context); } if (transientState != null) { if ((_capabilities & FLAG_IS_RENDERER_TYPE_SET) != 0) { return new Object[] {facesListenersSaved, stateHelperSaved, behaviorsMapSaved, systemEventListenerClassMapSaved, transientState, _rendererType}; } else { return new Object[] {facesListenersSaved, stateHelperSaved, behaviorsMapSaved, systemEventListenerClassMapSaved, transientState}; } } else { if ((_capabilities & FLAG_IS_RENDERER_TYPE_SET) != 0) { return new Object[] {facesListenersSaved, stateHelperSaved, behaviorsMapSaved, systemEventListenerClassMapSaved, null, _rendererType}; } else { return new Object[] {facesListenersSaved, stateHelperSaved, behaviorsMapSaved, systemEventListenerClassMapSaved}; } } } else { //Full Object[] values = new Object[FULL_STATE_ARRAY_SIZE]; values[0] = saveFacesListenersList(context); StateHelper stateHelper = getStateHelper(false); if (stateHelper != null) { values[1] = stateHelper.saveState(context); } values[2] = saveBehaviorsMap(context); values[3] = saveSystemEventListenerClassMap(context); values[4] = _id; values[5] = _clientId; values[6] = _markCreated; values[7] = _rendererType; values[8] = _capabilities; if (context.getCurrentPhaseId() != null && !PhaseId.RENDER_RESPONSE.equals(context.getCurrentPhaseId())) { values[9] = saveTransientState(context); } return values; } } /** * Invoked in the "restore view" phase, this initialises this object's members from the values saved previously into * the provided state object. *

* * @param state * is an object previously returned by the saveState method of this class. */ @SuppressWarnings("unchecked") @Override public void restoreState(FacesContext context, Object state) { if (context == null) { throw new NullPointerException ("context"); } if (state == null) { //Only happens if initialStateMarked return true if (initialStateMarked()) { return; } throw new NullPointerException ("state"); } Object[] values = (Object[]) state; if ( values.length == FULL_STATE_ARRAY_SIZE && initialStateMarked()) { //Delta mode is active, but we are restoring a full state. //we need to clear the initial state, to restore state without //take into account delta. clearInitialState(); } if (values[0] instanceof _AttachedDeltaWrapper) { //Delta: check for null is not necessary since _facesListener field //is only set once and never reset ((StateHolder)_facesListeners).restoreState(context, ((_AttachedDeltaWrapper) values[0]).getWrappedStateObject()); } else if (values[0] != null || (values.length == FULL_STATE_ARRAY_SIZE)) { //Full _facesListeners = (_DeltaList) restoreAttachedState(context,values[0]); } // Note that if values[0] == null && initialStateMarked(), // means delta is null, not that _facesListeners == null. // We can do this here because _facesListeners instance once // is created is never replaced or set to null. getStateHelper().restoreState(context, values[1]); if (values.length == FULL_STATE_ARRAY_SIZE) { _id = (String) values[4]; _clientId = (String) values[5]; _markCreated = (String) values[6]; _rendererType = (String) values[7]; _capabilities = (Integer) values[8]; } else if (values.length == 6) { restoreTransientState(context, values[4]); _rendererType = (String) values[5]; _capabilities |= FLAG_IS_RENDERER_TYPE_SET; } else if (values.length == 5) { restoreTransientState(context, values[4]); } // rendererType needs to be restored before SystemEventListener, // otherwise UIComponent.getCurrentComponent(context).getRenderer(context) // will not work correctly if (values.length == FULL_STATE_ARRAY_SIZE) { //Full restore restoreFullBehaviorsMap(context, values[2]); restoreFullSystemEventListenerClassMap(context, values[3]); restoreTransientState(context, values[9]); } else { //Delta restore restoreDeltaBehaviorsMap(context, values[2]); restoreDeltaSystemEventListenerClassMap(context, values[3]); } } private Object saveFacesListenersList(FacesContext facesContext) { PartialStateHolder holder = _facesListeners; if (initialStateMarked() && _facesListeners != null && holder.initialStateMarked()) { Object attachedState = holder.saveState(facesContext); if (attachedState != null) { return new _AttachedDeltaWrapper(_facesListeners.getClass(), attachedState); } //_facesListeners instances once is created never changes, we can return null return null; } else { return saveAttachedState(facesContext,_facesListeners); } } @SuppressWarnings("unchecked") private void restoreFullBehaviorsMap(FacesContext facesContext, Object stateObj) { if (stateObj != null) { Map stateMap = (Map) stateObj; _behaviorsMap = new HashMap<>(stateMap.size(), 1f); _unmodifiableBehaviorsMap = null; for (Map.Entry entry : stateMap.entrySet()) { _behaviorsMap.put(entry.getKey(), (List) restoreAttachedState(facesContext, entry.getValue())); } } else { _behaviorsMap = null; _unmodifiableBehaviorsMap = null; } } @SuppressWarnings("unchecked") private void restoreDeltaBehaviorsMap(FacesContext facesContext, Object stateObj) { if (stateObj != null) { _unmodifiableBehaviorsMap = null; Map stateMap = (Map) stateObj; if (_behaviorsMap == null) { _behaviorsMap = new HashMap<>(stateMap.size(), 1f); } for (Map.Entry entry : stateMap.entrySet()) { Object savedObject = entry.getValue(); if (savedObject instanceof _AttachedDeltaWrapper) { StateHolder holderList = (StateHolder) _behaviorsMap.get(entry.getKey()); holderList.restoreState(facesContext, ((_AttachedDeltaWrapper) savedObject).getWrappedStateObject()); } else { _behaviorsMap.put(entry.getKey(), (List) restoreAttachedState(facesContext, savedObject)); } } } } private Object saveBehaviorsMap(FacesContext facesContext) { if (_behaviorsMap != null) { if (initialStateMarked()) { HashMap stateMap = new HashMap<>(_behaviorsMap.size(), 1); boolean nullDelta = true; for (Map.Entry > entry : _behaviorsMap.entrySet()) { // The list is always an instance of _DeltaList so we can cast to // PartialStateHolder PartialStateHolder holder = (PartialStateHolder) entry.getValue(); if (holder.initialStateMarked()) { Object attachedState = holder.saveState(facesContext); if (attachedState != null) { stateMap.put(entry.getKey(), new _AttachedDeltaWrapper(_behaviorsMap.getClass(), attachedState)); nullDelta = false; } } else { stateMap.put(entry.getKey(), saveAttachedState(facesContext, holder)); nullDelta = false; } } if (nullDelta) { return null; } return stateMap; } else { //Save it in the traditional way HashMap stateMap = new HashMap<>(_behaviorsMap.size(), 1); for (Map.Entry > entry : _behaviorsMap.entrySet()) { stateMap.put(entry.getKey(), saveAttachedState(facesContext, entry.getValue())); } return stateMap; } } else { return null; } } @SuppressWarnings("unchecked") private void restoreFullSystemEventListenerClassMap(FacesContext facesContext, Object stateObj) { if (stateObj != null) { Map, Object> stateMap = (Map, Object>) stateObj; _systemEventListenerClassMap = new HashMap<>(stateMap.size(), 1f); for (Map.Entry, Object> entry : stateMap.entrySet()) { _systemEventListenerClassMap.put(entry.getKey(), (List) restoreAttachedState(facesContext, entry.getValue())); } } else { _systemEventListenerClassMap = null; } } @SuppressWarnings("unchecked") private void restoreDeltaSystemEventListenerClassMap(FacesContext facesContext, Object stateObj) { if (stateObj != null) { Map, Object> stateMap = (Map, Object>) stateObj; if (_systemEventListenerClassMap == null) { _systemEventListenerClassMap = new HashMap<>(stateMap.size(), 1f); } for (Map.Entry, Object> entry : stateMap.entrySet()) { Object savedObject = entry.getValue(); if (savedObject instanceof _AttachedDeltaWrapper) { StateHolder holderList = (StateHolder) _systemEventListenerClassMap.get(entry.getKey()); holderList.restoreState(facesContext, ((_AttachedDeltaWrapper) savedObject).getWrappedStateObject()); } else { _systemEventListenerClassMap.put(entry.getKey(), (List) restoreAttachedState(facesContext, savedObject)); } } } } private Object saveSystemEventListenerClassMap(FacesContext facesContext) { if (_systemEventListenerClassMap != null) { if (initialStateMarked()) { HashMap, Object> stateMap = new HashMap<>(_systemEventListenerClassMap.size(), 1); boolean nullDelta = true; for (Map.Entry, List > entry : _systemEventListenerClassMap.entrySet()) { // The list is always an instance of _DeltaList so we can cast to // PartialStateHolder PartialStateHolder holder = (PartialStateHolder) entry.getValue(); if (holder.initialStateMarked()) { Object attachedState = holder.saveState(facesContext); if (attachedState != null) { stateMap.put(entry.getKey(), new _AttachedDeltaWrapper(_systemEventListenerClassMap.getClass(), attachedState)); nullDelta = false; } } else { stateMap.put(entry.getKey(), saveAttachedState(facesContext, holder)); nullDelta = false; } } if (nullDelta) { return null; } return stateMap; } else { //Save it in the traditional way HashMap, Object> stateMap = new HashMap<>(_systemEventListenerClassMap.size(), 1); for (Map.Entry, List> entry : _systemEventListenerClassMap.entrySet()) { stateMap.put(entry.getKey(), saveAttachedState(facesContext, entry.getValue())); } return stateMap; } } else { return null; } } /** * @param string * the component id, that should be a vaild one. */ private void isIdValid(String string) { // is there any component identifier ? if (string == null) { return; } // Component identifiers must obey the following syntax restrictions: // 1. Must not be a zero-length String. if (string.length() == 0) { throw new IllegalArgumentException("component identifier must not be a zero-length String"); } // If new id is the same as old it must be valid if (string.equals(_id)) { return; } // 2. First character must be a letter or an underscore ('_'). char firstChar = string.charAt(0); if (!Character.isLetter(firstChar) && firstChar != '_') { throw new IllegalArgumentException("component identifier's first character must be a letter " + "or an underscore ('_')! But it is \"" + firstChar + '"'); } for (int i = 1; i < string.length(); i++) { char c = string.charAt(i); // 3. Subsequent characters must be a letter, a digit, an underscore ('_'), or a dash ('-'). if (!Character.isLetterOrDigit(c) && c != '-' && c != '_') { throw new IllegalArgumentException("Subsequent characters of component identifier must be a letter, " + "a digit, an underscore ('_'), or a dash ('-')! " + "But component identifier \"" + string + "\" contains \"" + c + '"'); } } } private boolean _isPhaseExecutable(FacesContext context) { Assert.notNull(context, "context"); // If the rendered property of this UIComponent is false, skip further processing. return isRendered(); } @Override boolean isCachedFacesContext() { return _facesContext != null; } @Override void setCachedFacesContext(FacesContext facesContext) { _facesContext = facesContext; } Renderer getCachedRenderer() { return _cachedRenderer; } void setCachedRenderer(Renderer renderer) { _cachedRenderer = renderer; } Boolean isCachedIsRendered() { return _cachedIsRendered; } void setCachedIsRendered(Boolean rendered) { _cachedIsRendered = rendered; } void setOamVfMarkCreated(String markCreated) { _markCreated = markCreated; } String getOamVfMarkCreated() { return _markCreated; } String getOamVfFacetName() { return _facetName; } void setOamVfFacetName(String facetName) { _facetName = facetName; } boolean isOamVfAddedByHandler() { return (_capabilities & FLAG_ADDED_BY_HANDLER) != 0; } void setOamVfAddedByHandler(boolean addedByHandler) { if (addedByHandler) { _capabilities |= FLAG_ADDED_BY_HANDLER; } else { _capabilities &= ~(FLAG_ADDED_BY_HANDLER); } } boolean isOamVfFacetCreatedUIPanel() { return (_capabilities & FLAG_FACET_CREATED_UIPANEL) != 0; } void setOamVfFacetCreatedUIPanel(boolean facetCreatedUIPanel) { if (facetCreatedUIPanel) { _capabilities |= FLAG_FACET_CREATED_UIPANEL; } else { _capabilities &= ~(FLAG_FACET_CREATED_UIPANEL); } } /** *

* This gets a single FacesContext-local shared stringbuilder instance, each time you call * _getSharedStringBuilder it sets the length of the stringBuilder instance to 0. *

* This allows you to use the same StringBuilder instance over and over. * You must call toString on the instance before calling _getSharedStringBuilder again. *

* Example that works *

     * StringBuilder sb1 = _getSharedStringBuilder();
     * sb1.append(a).append(b);
     * String c = sb1.toString();
     *
     * StringBuilder sb2 = _getSharedStringBuilder();
     * sb2.append(b).append(a);
     * String d = sb2.toString();
     * 
*

* Example that doesn't work, you must call toString on sb1 before * calling _getSharedStringBuilder again. *

     * StringBuilder sb1 = _getSharedStringBuilder();
     * StringBuilder sb2 = _getSharedStringBuilder();
     *
     * sb1.append(a).append(b);
     * String c = sb1.toString();
     *
     * sb2.append(b).append(a);
     * String d = sb2.toString();
     * 
* * @param facesContext */ static StringBuilder _getSharedStringBuilder(FacesContext facesContext) { return SharedStringBuilder.get(facesContext, _STRING_BUILDER_KEY); } // ------------------ GENERATED CODE BEGIN (do not modify!) -------------------- private static final Boolean DEFAULT_RENDERED = Boolean.TRUE; @Override public void setRendered(boolean rendered) { getStateHelper().put(PropertyKeys.rendered, rendered ); setCachedIsRendered(null); } @Override public void setRendererType(String rendererType) { this._rendererType = rendererType; if (initialStateMarked()) { //This flag just indicates the rendererType //should be included on the delta _capabilities |= FLAG_IS_RENDERER_TYPE_SET; } setCachedRenderer(null); } // ------------------ GENERATED CODE END --------------------------------------- private Map> wrapBehaviorsMap() { if (_unmodifiableBehaviorsMap == null) { _unmodifiableBehaviorsMap = Collections.unmodifiableMap(_behaviorsMap); } return _unmodifiableBehaviorsMap; } }