Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright (c) 2022, 2024 Contributors to Eclipse Foundation.
* Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
* version 2 with the GNU Classpath Exception, which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
*/
package jakarta.faces.component;
import static com.sun.faces.facelets.tag.faces.ComponentSupport.addToDescendantMarkIdCache;
import static com.sun.faces.facelets.tag.faces.ComponentSupport.isNotRenderingResponse;
import static com.sun.faces.facelets.tag.faces.ComponentSupport.removeFromDescendantMarkIdCache;
import static com.sun.faces.util.Util.isAllNull;
import static com.sun.faces.util.Util.isAnyNull;
import static com.sun.faces.util.Util.isEmpty;
import static java.beans.Introspector.getBeanInfo;
import static java.lang.Boolean.TRUE;
import static java.lang.Character.isDigit;
import static java.lang.Character.isLetter;
import static java.lang.Thread.currentThread;
import static java.util.Collections.unmodifiableCollection;
import static java.util.Collections.unmodifiableList;
import static java.util.logging.Level.FINE;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.AbstractCollection;
import java.util.AbstractMap;
import java.util.AbstractSet;
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.ListIterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import jakarta.el.ELException;
import jakarta.el.ValueExpression;
import jakarta.faces.FacesException;
import jakarta.faces.application.Application;
import jakarta.faces.component.behavior.Behavior;
import jakarta.faces.component.behavior.ClientBehavior;
import jakarta.faces.component.behavior.ClientBehaviorHolder;
import jakarta.faces.context.FacesContext;
import jakarta.faces.event.AbortProcessingException;
import jakarta.faces.event.BehaviorEvent;
import jakarta.faces.event.ComponentSystemEventListener;
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.Renderer;
/**
*
* UIComponentBase is a
* convenience base class that implements the default concrete behavior of all methods defined by {@link UIComponent}.
*
*
*
* By default, this class defines getRendersChildren() to find the renderer for this component and call its
* getRendersChildren() method. The default implementation on the Renderer returns
* false. As of version 1.2 of the Jakarta Faces Specification, component authors are encouraged to
* return true from this method and rely on the implementation of {@link #encodeChildren} in this class and
* in the Renderer ({@link Renderer#encodeChildren}). Subclasses that wish to manage the rendering of their children
* should override this method to return true instead.
*
*/
public abstract class UIComponentBase extends UIComponent {
// -------------------------------------------------------------- Attributes
private static final Logger LOGGER = Logger.getLogger("jakarta.faces.component", "jakarta.faces.LogStrings");
private static final String ADDED = UIComponentBase.class.getName() + ".ADDED";
private static final int MY_STATE = 0;
private static final int CHILD_STATE = 1;
/**
*
* Each entry is an map of PropertyDescriptors describing the properties of a concrete {@link UIComponent}
* implementation, keyed by the corresponding java.lang.Class.
*
*
*/
private Map, Map> descriptors;
/**
* Reference to the map of PropertyDescriptors for this class in the descriptors
* Map.
*/
private Map propertyDescriptorMap;
private Map, List> listenersByEventClass;
/**
*
* An EMPTY_OBJECT_ARRAY argument list to be passed to reflection methods.
*
*/
private static final Object EMPTY_OBJECT_ARRAY[] = new Object[0];
/**
*
* The Map containing our attributes, keyed by attribute name.
*
*/
private AttributesMap attributes;
/**
*
* The component identifier for this component.
*
*/
private String id;
/**
*
* The assigned client identifier for this component.
*
*/
private String clientId;
/**
*
* The parent component for this component.
*
*/
private UIComponent parent;
/**
* The List containing our child components.
*/
private List children;
/**
* The Map containing our related facet components.
*/
private Map facets;
private AttachedObjectListHolder listeners;
/**
* Flag indicating a desire to now participate in state saving.
*/
private boolean transientFlag;
/**
* Default constructor, populates the descriptor map.
*/
public UIComponentBase() {
populateDescriptorsMapIfNecessary();
}
@Override
public Map getAttributes() {
if (attributes == null) {
attributes = new AttributesMap(this);
}
return attributes;
}
@Override
public Map getPassThroughAttributes(boolean create) {
@SuppressWarnings("unchecked")
Map passThroughAttributes = (Map) this.getStateHelper().get(PropertyKeys.passThroughAttributes);
if (passThroughAttributes == null && create) {
passThroughAttributes = new PassThroughAttributesMap<>();
getStateHelper().put(PropertyKeys.passThroughAttributes, passThroughAttributes);
}
return passThroughAttributes;
}
// -------------------------------------------------------------- Properties
/**
* @throws NullPointerException {@inheritDoc}
*/
@Override
public String getClientId(FacesContext context) {
if (context == null) {
throw new NullPointerException();
}
// If the clientId is not yet set
if (clientId == null) {
UIComponent namingContainerAncestor = getNamingContainerAncestor();
// Give the parent the opportunity to first grab a unique clientId
String parentId = getParentId(context, namingContainerAncestor);
// Now resolve our own client id
clientId = getId();
if (clientId == null) {
setId(generateId(context, namingContainerAncestor));
clientId = getId();
}
if (parentId != null) {
clientId = addParentId(context, parentId, clientId);
}
// Allow the renderer to convert the clientId
Renderer renderer = getRenderer(context);
if (renderer != null) {
clientId = renderer.convertClientId(context, clientId);
}
}
return clientId;
}
@Override
public String getId() {
return id;
}
/**
* @throws IllegalArgumentException {@inheritDoc}
* @throws IllegalStateException {@inheritDoc}
*/
@Override
public void setId(String id) {
// if the current ID is not null, and the passed
// argument is the same, no need to validate it
// as it has already been validated.
if (this.id == null || !this.id.equals(id)) {
validateId(id);
this.id = id;
}
clientId = null; // Erase any cached value
}
@Override
public UIComponent getParent() {
return parent;
}
@Override
public void setParent(UIComponent parent) {
if (parent == null) {
if (this.parent != null) {
doPreRemoveProcessing(FacesContext.getCurrentInstance(), this);
this.parent = parent;
}
compositeParent = null;
} else {
this.parent = parent;
if (getAttributes().get(ADDED) == null) {
// Add an attribute to this component here to indiciate that
// it's being processed. If we don't do this, and the component
// is re-parented, the events could fire again in certain cases
// and cause a stack overflow.
getAttributes().put(ADDED, TRUE);
doPostAddProcessing(FacesContext.getCurrentInstance(), this);
// Remove the attribute once we've returned from the event
// processing.
getAttributes().remove(ADDED);
}
}
}
@Override
public boolean isRendered() {
return Boolean.valueOf(getStateHelper().eval(PropertyKeys.rendered, TRUE).toString());
}
@Override
public void setRendered(boolean rendered) {
getStateHelper().put(PropertyKeys.rendered, rendered);
}
@Override
public String getRendererType() {
return (String) getStateHelper().eval(PropertyKeys.rendererType);
}
@Override
public void setRendererType(String rendererType) {
getStateHelper().put(PropertyKeys.rendererType, rendererType);
}
@Override
public boolean getRendersChildren() {
if (getRendererType() != null) {
Renderer renderer = getRenderer(getFacesContext());
if (renderer != null) {
return renderer.getRendersChildren();
}
}
return false;
}
// ------------------------------------------------- Tree Management Methods
@Override
public List getChildren() {
if (children == null) {
children = new ChildrenList(this);
}
return children;
}
// Do not allocate the children List to answer this question
@Override
public int getChildCount() {
if (children != null) {
return children.size();
}
return 0;
}
/**
* @throws NullPointerException {@inheritDoc}
*/
@Override
public UIComponent findComponent(String expression) {
if (expression == null) {
throw new NullPointerException();
}
if (expression.isEmpty()) {
// If an empty value is provided, fail fast.
throw new IllegalArgumentException("\"\"");
}
final char sepChar = UINamingContainer.getSeparatorChar(FacesContext.getCurrentInstance());
// Identify the base component from which we will perform our search
UIComponent base = findBaseComponent(expression, sepChar);
if (expression.charAt(0) == sepChar) {
// Treat remainder of the expression as relative
expression = expression.substring(1);
}
// Evaluate the search expression (now guaranteed to be relative)
return evaluateSearchExpression(base, expression, String.valueOf(sepChar));
}
/**
* {@inheritDoc}
*
* @throws NullPointerException {@inheritDoc}
* @throws FacesException {@inheritDoc}
* @since 1.2
*/
@Override
public boolean invokeOnComponent(FacesContext context, String clientId, ContextCallback callback) throws FacesException {
return super.invokeOnComponent(context, clientId, callback);
}
// ------------------------------------------------ Facet Management Methods
@Override
public Map getFacets() {
if (facets == null) {
facets = new FacetsMap(this);
}
return facets;
}
// Do not allocate the children List to answer this question
@Override
public int getFacetCount() {
if (facets != null) {
return facets.size();
}
return 0;
}
// Do not allocate the facets Map to answer this question
@Override
public UIComponent getFacet(String name) {
if (facets != null) {
return facets.get(name);
}
return null;
}
@Override
public Iterator getFacetsAndChildren() {
int childCount = getChildCount(), facetCount = getFacetCount();
// If there are neither facets nor children
if (childCount == 0 && facetCount == 0) {
return EMPTY_ITERATOR;
}
// If there are only facets and no children
if (childCount == 0) {
return unmodifiableCollection(getFacets().values()).iterator();
}
// If there are only children and no facets
if (facetCount == 0) {
return unmodifiableList(getChildren()).iterator();
}
// If there are both children and facets
return new FacetsAndChildrenIterator(this);
}
// -------------------------------------------- Lifecycle Processing Methods
/**
* @throws AbortProcessingException {@inheritDoc}
* @throws IllegalStateException {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
*/
@Override
public void broadcast(FacesEvent event) throws AbortProcessingException {
if (event == null) {
throw new NullPointerException();
}
if (event instanceof BehaviorEvent) {
BehaviorEvent behaviorEvent = (BehaviorEvent) event;
Behavior behavior = behaviorEvent.getBehavior();
behavior.broadcast(behaviorEvent);
}
if (listeners == null) {
return;
}
for (FacesListener listener : listeners.asArray(FacesListener.class)) {
if (event.isAppropriateListener(listener)) {
event.processListener(listener);
}
}
}
/**
* @throws NullPointerException {@inheritDoc}
*/
@Override
public void decode(FacesContext context) {
if (context == null) {
throw new NullPointerException();
}
String rendererType = getRendererType();
if (rendererType != null) {
Renderer renderer = getRenderer(context);
if (renderer != null) {
renderer.decode(context, this);
} else {
if (LOGGER.isLoggable(FINE)) {
LOGGER.fine("Can't get Renderer for type " + rendererType);
}
}
}
}
/**
* @throws NullPointerException {@inheritDoc}
*/
@Override
public void encodeBegin(FacesContext context) throws IOException {
if (context == null) {
throw new NullPointerException();
}
pushComponentToEL(context, null);
if (!isRendered()) {
return;
}
context.getApplication().publishEvent(context, PreRenderComponentEvent.class, this);
String rendererType = getRendererType();
if (rendererType != null) {
Renderer renderer = getRenderer(context);
if (renderer != null) {
renderer.encodeBegin(context, this);
} else {
if (LOGGER.isLoggable(FINE)) {
LOGGER.fine("Can't get Renderer for type " + rendererType);
}
}
}
}
/**
* @throws NullPointerException {@inheritDoc}
*/
@Override
public void encodeChildren(FacesContext context) throws IOException {
if (context == null) {
throw new NullPointerException();
}
if (!isRendered()) {
return;
}
if (getRendererType() != null) {
Renderer renderer = getRenderer(context);
if (renderer != null) {
renderer.encodeChildren(context, this);
}
// We've already logged for this component
} else if (getChildCount() > 0) {
for (UIComponent child : getChildren()) {
child.encodeAll(context);
}
}
}
/**
* @throws IOException {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
*/
@Override
public void encodeEnd(FacesContext context) throws IOException {
if (context == null) {
throw new NullPointerException();
}
if (!isRendered()) {
popComponentFromEL(context);
return;
}
if (getRendererType() != null) {
Renderer renderer = getRenderer(context);
if (renderer != null) {
renderer.encodeEnd(context, this);
}
// We've already logged for this component
}
popComponentFromEL(context);
}
// -------------------------------------------------- Event Listener Methods
/**
*
* Add the specified {@link FacesListener} to the set of listeners registered to receive event notifications from this
* {@link UIComponent}. It is expected that {@link UIComponent} classes acting as event sources will have corresponding
* typesafe APIs for registering listeners of the required type, and the implementation of those registration methods
* will delegate to this method. For example:
*
*
* @param listener The {@link FacesListener} to be registered
* @throws NullPointerException if listener is null
*/
@Override
protected void addFacesListener(FacesListener listener) {
if (listener == null) {
throw new NullPointerException();
}
if (listeners == null) {
listeners = new AttachedObjectListHolder<>();
}
listeners.add(listener);
}
/**
* @throws IllegalArgumentException {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
*/
@Override
protected FacesListener[] getFacesListeners(Class clazz) {
if (clazz == null) {
throw new NullPointerException();
}
if (!FacesListener.class.isAssignableFrom(clazz)) {
throw new IllegalArgumentException();
}
if (listeners == null) {
return (FacesListener[]) Array.newInstance(clazz, 0);
}
FacesListener[] listeners = this.listeners.asArray(FacesListener.class);
if (listeners.length == 0) {
return (FacesListener[]) Array.newInstance(clazz, 0);
}
List results = new ArrayList<>(listeners.length);
for (FacesListener listener : listeners) {
if (((Class>) clazz).isAssignableFrom(listener.getClass())) {
results.add(listener);
}
}
return results.toArray((FacesListener[]) Array.newInstance(clazz, results.size()));
}
/**
*
* Remove the specified {@link FacesListener} from the set of listeners registered to receive event notifications from
* this {@link UIComponent}.
*
* @param listener The {@link FacesListener} to be deregistered
* @throws NullPointerException if listener is null
*/
@Override
protected void removeFacesListener(FacesListener listener) {
if (listener == null) {
throw new NullPointerException();
}
if (listeners != null) {
listeners.remove(listener);
}
}
/**
* @throws IllegalStateException {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
*/
@Override
public void queueEvent(FacesEvent event) {
if (event == null) {
throw new NullPointerException();
}
UIComponent parent = getParent();
if (parent == null) {
throw new IllegalStateException();
}
parent.queueEvent(event);
}
/**
*
* Install the listener instance referenced by argument componentListener as a listener for events of type
* eventClass originating from this specific instance of UIComponent. The default
* implementation creates an inner {@link SystemEventListener} instance that wraps argument
* componentListener as the listener argument. This inner class must call through to the
* argument componentListener in its implementation of {@link SystemEventListener#processEvent} and its
* implementation of {@link SystemEventListener#isListenerForSource} must return true if the instance class of this
* UIComponent is assignable from the argument to isListenerForSource.
*
*
* The listener instance referenced by argument componentListener may not already be installed as a listener for events of type
* eventClass originating from this specific instance of UIComponent. When doing the
* comparison to determine if an existing listener is equal to the argument componentListener,
* the equals() method on the existing listener must be invoked, passing the
* argument componentListener, rather than the other way around.
*
*
* @param eventClass the Class of event for which listener must be fired.
* @param componentListener the implementation of {@link jakarta.faces.event.ComponentSystemEventListener} whose
* {@link jakarta.faces.event.ComponentSystemEventListener#processEvent} method must be called when events of type
* facesEventClass are fired.
*
* @throws NullPointerException if any of the arguments are null.
*
* @since 2.1
*/
@Override
public void subscribeToEvent(Class extends SystemEvent> eventClass, ComponentSystemEventListener componentListener) {
if (isAnyNull(eventClass, componentListener)) {
throw new NullPointerException();
}
if (initialStateMarked()) {
initialState = false;
}
if (listenersByEventClass == null) {
listenersByEventClass = new HashMap<>(3, 1.0f);
}
SystemEventListener facesLifecycleListener = new ComponentSystemEventListenerAdapter(componentListener, this);
List listenersForEventClass = listenersByEventClass.get(eventClass);
if (listenersForEventClass == null) {
listenersForEventClass = new ArrayList<>(3);
listenersByEventClass.put(eventClass, listenersForEventClass);
}
if (!listenersForEventClass.contains(facesLifecycleListener)) {
listenersForEventClass.add(facesLifecycleListener);
}
}
/**
*
* Remove the listener instance referenced by argument componentListener as a listener for events of type
* eventClass originating from this specific instance of UIComponent. When doing the
* comparison to determine if an existing listener is equal to the argument componentListener (and thus
* must be removed), the equals() method on the existing listener must be invoked, passing the
* argument componentListener, rather than the other way around.
*
*
* @param eventClass the Class of event for which listener must be removed.
* @param componentListener the implementation of {@link ComponentSystemEventListener} whose
* {@link ComponentSystemEventListener#processEvent} method must no longer be called when events of type
* eventClass are fired.
*
* @throws NullPointerException if any of the arguments are null.
*
* @since 2.1
*/
@Override
public void unsubscribeFromEvent(Class extends SystemEvent> eventClass, ComponentSystemEventListener componentListener) {
if (isAnyNull(eventClass, componentListener)) {
throw new NullPointerException();
}
List listeners = getListenersForEventClass(eventClass);
if (!isEmpty(listeners)) {
for (Iterator i = listeners.iterator(); i.hasNext();) {
ComponentSystemEventListener existingListener = ((ComponentSystemEventListenerAdapter) i.next()).getWrapped();
if (existingListener.equals(componentListener)) {
i.remove();
break;
}
}
}
}
/**
*
* Return the SystemEventListener instances registered on this UIComponent instance that are
* interested in events of type eventClass.
*
*
* @param eventClass the Class of event for which the listeners must be returned.
*
* @throws NullPointerException if argument eventClass is null.
*
* @since 2.1
*/
@Override
public List getListenersForEventClass(Class extends SystemEvent> eventClass) {
if (eventClass == null) {
throw new NullPointerException();
}
if (listenersByEventClass != null) {
return listenersByEventClass.getOrDefault(eventClass, Collections.emptyList());
}
return Collections.emptyList();
}
// ------------------------------------------------ Lifecycle Phase Handlers
/**
* @throws NullPointerException {@inheritDoc}
*/
@Override
public void processDecodes(FacesContext context) {
if (context == null) {
throw new NullPointerException();
}
// Skip processing if our rendered flag is false
if (!isRendered()) {
return;
}
pushComponentToEL(context, null);
try {
// Process all facets and children of this component
Iterator kids = getFacetsAndChildren();
while (kids.hasNext()) {
UIComponent kid = kids.next();
kid.processDecodes(context);
}
// Process this component itself
try {
decode(context);
} catch (RuntimeException e) {
context.renderResponse();
throw e;
}
} finally {
popComponentFromEL(context);
}
}
/**
* @throws NullPointerException {@inheritDoc}
*/
@Override
public void processValidators(FacesContext context) {
if (context == null) {
throw new NullPointerException();
}
// Skip processing if our rendered flag is false
if (!isRendered()) {
return;
}
pushComponentToEL(context, null);
try {
Application application = context.getApplication();
application.publishEvent(context, PreValidateEvent.class, this);
// Process all the facets and children of this component
Iterator kids = getFacetsAndChildren();
while (kids.hasNext()) {
UIComponent kid = kids.next();
kid.processValidators(context);
}
application.publishEvent(context, PostValidateEvent.class, this);
} finally {
popComponentFromEL(context);
}
}
/**
* @throws NullPointerException {@inheritDoc}
*/
@Override
public void processUpdates(FacesContext context) {
if (context == null) {
throw new NullPointerException();
}
// Skip processing if our rendered flag is false
if (!isRendered()) {
return;
}
pushComponentToEL(context, null);
try {
// Process all facets and children of this component
Iterator kids = getFacetsAndChildren();
while (kids.hasNext()) {
UIComponent kid = kids.next();
kid.processUpdates(context);
}
} finally {
popComponentFromEL(context);
}
}
/**
* @throws NullPointerException {@inheritDoc}
*/
@Override
public Object processSaveState(FacesContext context) {
if (context == null) {
throw new NullPointerException();
}
if (isTransient()) {
return null;
}
Object[] stateStruct = new Object[2];
Object[] childState = EMPTY_ARRAY;
pushComponentToEL(context, null);
try {
// Process this component itself
stateStruct[MY_STATE] = saveState(context);
// Determine if we have any children to store
int count = getChildCount() + getFacetCount();
if (count > 0) {
// This arraylist will store state
List