javax.faces.component.UIComponent Maven / Gradle / Ivy
/*
* $Id: UIComponent.java,v 1.150.4.7 2008/09/30 16:19:56 rlubke Exp $
*/
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can obtain
* a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
* or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
* Sun designates this particular file as subject to the "Classpath" exception
* as provided by Sun in the GPL Version 2 section of the License file that
* accompanied this code. If applicable, add the following below the License
* Header, with the fields enclosed by brackets [] replaced by your own
* identifying information: "Portions Copyrighted [year]
* [name of copyright owner]"
*
* Contributor(s):
*
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
package javax.faces.component;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.el.ELContext;
import javax.el.ELException;
import javax.el.ValueExpression;
import javax.faces.FacesException;
import javax.faces.context.FacesContext;
import javax.faces.el.ValueBinding;
import javax.faces.event.AbortProcessingException;
import javax.faces.event.FacesEvent;
import javax.faces.event.FacesListener;
import javax.faces.render.Renderer;
/**
* UIComponent is the base class for all user interface
* components in JavaServer Faces. The set of {@link UIComponent} instances
* associated with a particular request and response are organized into a
* component tree under a {@link UIViewRoot} that represents
* the entire content of the request or response.
*
* For the convenience of component developers,
* {@link UIComponentBase} provides the default
* behavior that is specified for a {@link UIComponent}, and is the base class
* for all of the concrete {@link UIComponent} "base" implementations.
* Component writers are encouraged to subclass
* {@link UIComponentBase}, instead of directly
* implementing this abstract class, to reduce the impact of any future changes
* to the method signatures.
*/
public abstract class UIComponent implements StateHolder {
/**
* Components within this base package are considered optimizable
* with respect to attributes processing.
*/
private static final String OPTIMIZED_PACKAGE = "javax.faces.component.";
/**
* List of attributes that have been set on the component (this
* may be from setValueExpression, the attributes map, or setters
* from the concrete HTML components. This allows
* for faster rendering of attributes as this list is authoratative
* on what has been set.
*/
List attributesThatAreSet;
// -------------------------------------------------------------- Attributes
/**
* Return a mutable Map
representing the attributes
* (and properties, see below) associated wth this {@link UIComponent},
* keyed by attribute name (which must be a String). The returned
* implementation must support all of the standard and optional
* Map
methods, plus support the following additional
* requirements:
*
* - The
Map
implementation must implement
* the java.io.Serializable
interface.
* - Any attempt to add a
null
key or value must
* throw a NullPointerException
.
* - Any attempt to add a key that is not a String must throw
* a
ClassCastException
.
* - If the attribute name specified as a key matches a property
* of this {@link UIComponent}'s implementation class, the following
* methods will have special behavior:
*
* containsKey
- Return false
.
* get()
- If the property is readable, call
* the getter method and return the returned value (wrapping
* primitive values in their corresponding wrapper classes);
* otherwise throw IllegalArgumentException
.
* put()
- If the property is writeable, call
* the setter method to set the corresponding value (unwrapping
* primitive values in their corresponding wrapper classes).
* If the property is not writeable, or an attempt is made to
* set a property of primitive type to null
,
* throw IllegalArgumentException
.
* remove
- Throw
* IllegalArgumentException
.
*
*
*/
public abstract Map getAttributes();
// ---------------------------------------------------------------- Bindings
/**
*
* Call through to {@link #getValueExpression} and examine the
* result. If the result is an instance of the wrapper class
* mandated in {@link #setValueBinding}, extract the
* ValueBinding
instance and return it. Otherwise,
* wrap the result in an implementation of
* ValueBinding
, and return it.
*
* @param name Name of the attribute or property for which to retrieve a
* {@link ValueBinding}
*
* @throws NullPointerException if name
* is null
*
* @deprecated This has been replaced by {@link #getValueExpression}.
*/
public abstract ValueBinding getValueBinding(String name);
/**
* Wrap the argument binding
in an implementation of
* {@link ValueExpression} and call through to {@link
* #setValueExpression}.
*
* @param name Name of the attribute or property for which to set a
* {@link ValueBinding}
* @param binding The {@link ValueBinding} to set, or null
* to remove any currently set {@link ValueBinding}
*
* @throws IllegalArgumentException if name
is one of
* id
or parent
* @throws NullPointerException if name
* is null
*
* @deprecated This has been replaced by {@link #setValueExpression}.
*/
public abstract void setValueBinding(String name, ValueBinding binding);
// The set of ValueExpressions for this component, keyed by property
// name This collection is lazily instantiated
// The set of ValueExpressions for this component, keyed by property
// name This collection is lazily instantiated
protected Map bindings = null;
/**
* Return the {@link ValueExpression} used to calculate the value for the
* specified attribute or property name, if any.
*
* This method must be overridden and implemented for components that
* comply with JSF 1.2 and later.
*
* @since 1.2
*
* @param name Name of the attribute or property for which to retrieve a
* {@link ValueExpression}
*
* @throws NullPointerException if name
* is null
*
*/
public ValueExpression getValueExpression(String name) {
ValueExpression result = null;
if (name == null) {
throw new NullPointerException();
}
if (bindings == null) {
if (!isUIComponentBase()) {
ValueBinding binding = getValueBinding(name);
if (null != binding) {
result = new ValueExpressionValueBindingAdapter(binding);
// Cache this for future reference.
//noinspection CollectionWithoutInitialCapacity
bindings = new HashMap();
bindings.put(name, result);
}
}
return (result);
} else {
return (bindings.get(name));
}
}
/**
* Set the {@link ValueExpression} used to calculate the value
* for the specified attribute or property name, if any.
*
* The implementation must call {@link
* ValueExpression#isLiteralText} on the argument
* expression
. If isLiteralText()
returns
* true
, invoke {@link ValueExpression#getValue} on the
* argument expression and pass the result as the value
* parameter in a call to this.{@link
* #getAttributes()}.put(name, value)
where name
* is the argument name
. If an exception is thrown as
* a result of calling {@link ValueExpression#getValue}, wrap it in
* a {@link javax.faces.FacesException} and re-throw it. If
* isLiteralText()
returns false
, simply
* store the un-evaluated expression
argument in the
* collection of ValueExpression
s under the key given
* by the argument name
.
*
* This method must be overridden and implemented for components that
* comply with JSF 1.2 and later.
*
* @since 1.2
*
* @param name Name of the attribute or property for which to set a
* {@link ValueExpression}
* @param binding The {@link ValueExpression} to set, or null
* to remove any currently set {@link ValueExpression}
*
* @throws IllegalArgumentException if name
is one of
* id
or parent
* @throws NullPointerException if name
* is null
*
*/
public void setValueExpression(String name, ValueExpression binding) {
if (name == null) {
throw new NullPointerException();
} else if ("id".equals(name) || "parent".equals(name)) {
throw new IllegalArgumentException();
}
if (binding != null) {
if (!binding.isLiteralText()) {
if (bindings == null) {
//noinspection CollectionWithoutInitialCapacity
bindings = new HashMap();
}
// add this binding name to the 'attributesThatAreSet' list
List sProperties = getAttributesThatAreSet(true);
if (sProperties != null && !sProperties.contains(name)) {
sProperties.add(name);
}
bindings.put(name, binding);
} else {
ELContext context =
FacesContext.getCurrentInstance().getELContext();
try {
getAttributes().put(name, binding.getValue(context));
} catch (ELException ele) {
throw new FacesException(ele);
}
}
} else {
if (bindings != null) {
// remove this binding name from the 'attributesThatAreSet' list
List sProperties = getAttributesThatAreSet(false);
if (sProperties != null) {
sProperties.remove(name);
}
bindings.remove(name);
if (bindings.isEmpty()) {
bindings = null;
}
}
}
}
// -------------------------------------------------------------- Properties
/**
* Return a client-side identifier for this component, generating
* one if necessary. The associated {@link Renderer}, if any,
* will be asked to convert the clientId to a form suitable for
* transmission to the client.
*
* The return from this method must be the same value throughout
* the lifetime of the instance, unless the id
property
* of the component is changed, or the component is placed in
* a {@link NamingContainer} whose client ID changes (for example,
* {@link UIData}). However, even in these cases, consecutive
* calls to this method must always return the same value. The
* implementation must follow these steps in determining the
* clientId:
*
* Find the closest ancestor to this component in the view
* hierarchy that implements NamingContainer
. Call
* getContainerClientId()
on it and save the result as
* the parentId
local variable. Call {@link #getId} on
* this component and save the result as the
* myId
local variable. If myId
is
* null
, call
* context.getViewRoot().createUniqueId()
and assign
* the result to myId. If parentId
is
* non-null
, let myId
equal parentId
* + NamingContainer.SEPARATOR_CHAR + myId
. Call {@link
* Renderer#convertClientId}, passing myId
, and return
* the result.
*
* @param context The {@link FacesContext} for the current request
*
* @throws NullPointerException if context
* is null
*/
public abstract String getClientId(FacesContext context);
/**
* Allow components that implement {@link NamingContainer} to
* selectively disable prepending their clientId to their
* descendent's clientIds by breaking the prepending logic into a
* seperately callable method. See {@link #getClientId} for usage.
*
* By default, this method will call through to {@link
* #getClientId} and return the result.
*
* @since 1.2
*
* @throws NullPointerException if context
is
* null
*/
public String getContainerClientId(FacesContext context) {
if (context == null) {
throw new NullPointerException();
}
return this.getClientId(context);
}
/**
*
Return the identifier of the component family to which this
* component belongs. This identifier, in conjunction with the value
* of the rendererType
property, may be used to select
* the appropriate {@link Renderer} for this component instance.
*/
public abstract String getFamily();
/**
* Return the component identifier of this {@link UIComponent}.
*/
public abstract String getId();
/**
* Set the component identifier of this {@link UIComponent} (if any).
* Component identifiers must obey the following syntax restrictions:
*
* - Must not be a zero-length String.
* - First character must be a letter or an underscore ('_').
* - Subsequent characters must be a letter, a digit,
* an underscore ('_'), or a dash ('-').
* -
*
*
* Component identifiers must also obey the following semantic
* restrictions (note that this restriction is NOT
* enforced by the setId()
implementation):
*
* - The specified identifier must be unique among all the components
* (including facets) that are descendents of the nearest ancestor
* {@link UIComponent} that is a {@link NamingContainer}, or within
* the scope of the entire component tree if there is no such
* ancestor that is a {@link NamingContainer}.
*
*
* @param id The new component identifier, or null
to indicate
* that this {@link UIComponent} does not have a component identifier
*
* @throws IllegalArgumentException if id
is not
* syntactically valid
*/
public abstract void setId(String id);
/**
* Return the parent {@link UIComponent} of this
* UIComponent
, if any. A component must allow child
* components to be added to and removed from the list of children
* of this component, even though the child component returns null
* from getParent( )
.
*/
public abstract UIComponent getParent();
/**
* Set the parent UIComponent
of this
* UIComponent
. This method must
* never be called by developers; a {@link UIComponent}'s internal
* implementation will call it as components are added to or
* removed from a parent's child List
or
* facet Map
.
*
* @param parent The new parent, or null
for the root node
* of a component tree
*/
public abstract void setParent(UIComponent parent);
/**
* Return true
if this component (and its children)
* should be rendered during the Render Response phase
* of the request processing lifecycle.
*/
public abstract boolean isRendered();
/**
* Set the rendered
property of this
* {@link UIComponent}.
*
* @param rendered If true
render this component;
* otherwise, do not render this component
*/
public abstract void setRendered(boolean rendered);
/**
* Return the {@link Renderer} type for this {@link UIComponent}
* (if any).
*/
public abstract String getRendererType();
/**
* Set the {@link Renderer} type for this {@link UIComponent},
* or null
for components that render themselves.
*
* @param rendererType Logical identifier of the type of
* {@link Renderer} to use, or null
for components
* that render themselves
*/
public abstract void setRendererType(String rendererType);
/**
* Return a flag indicating whether this component is responsible
* for rendering its child components. The default implementation
* in {@link UIComponentBase#getRendersChildren} tries to find the
* renderer for this component. If it does, it calls {@link
* Renderer#getRendersChildren} and returns the result. If it
* doesn't, it returns false. As of version 1.2 of the JavaServer
* Faces Specification, component authors are encouraged to return
* true
from this method and rely on {@link
* UIComponentBase#encodeChildren}.
*/
public abstract boolean getRendersChildren();
// This is necessary for JSF components that extend from UIComponent
// directly rather than extending from UIComponentBase. Such components
// may need to have implementations provided for methods that originated
// from a spec version more recent than the version with which the component
// complies. Currently this private property is only consulted in the
// getValueExpression() method.
private boolean isUIComponentBase;
private boolean isUIComponentBaseIsSet = false;
private boolean isUIComponentBase() {
if (!isUIComponentBaseIsSet) {
isUIComponentBase = (this instanceof UIComponentBase);
}
return isUIComponentBase;
}
// ------------------------------------------------- Tree Management Methods
/**
* Return a mutable List
representing the child
* {@link UIComponent}s associated with this component. The returned
* implementation must support all of the standard and optional
* List
methods, plus support the following additional
* requirements:
*
* - The
List
implementation must implement
* the java.io.Serializable
interface.
* - Any attempt to add a
null
must throw
* a NullPointerException
* - Any attempt to add an object that does not implement
* {@link UIComponent} must throw a ClassCastException.
* - Whenever a new child component is added, the
parent
* property of the child must be set to this component instance.
* If the parent
property of the child was already
* non-null, the child must first be removed from its previous
* parent (where it may have been either a child or a facet).
* - Whenever an existing child component is removed, the
*
parent
property of the child must be set to
* null
.
*
*/
public abstract List getChildren();
/**
* Return the number of child {@link UIComponent}s that are
* associated with this {@link UIComponent}. If there are no
* children, this method must return 0. The method must not cause
* the creation of a child component list.
*/
public abstract int getChildCount();
/**
* Search for and return the {@link UIComponent} with an id
* that matches the specified search expression (if any), according to the
* algorithm described below.
*
* For a method to find a component given a simple
* clientId
, see {@link #invokeOnComponent}.
*
* Component identifiers are required to be unique within the scope of
* the closest ancestor {@link NamingContainer} that encloses this
* component (which might be this component itself). If there are no
* {@link NamingContainer} components in the ancestry of this component,
* the root component in the tree is treated as if it were a
* {@link NamingContainer}, whether or not its class actually implements
* the {@link NamingContainer} interface.
*
* A search expression consists of either an
* identifier (which is matched exactly against the id
* property of a {@link UIComponent}, or a series of such identifiers
* linked by the {@link NamingContainer#SEPARATOR_CHAR} character value.
* The search algorithm should operates as follows, though alternate
* alogrithms may be used as long as the end result is the same:
*
* - Identify the {@link UIComponent} that will be the base for searching,
* by stopping as soon as one of the following conditions is met:
*
* - If the search expression begins with the the separator character
* (called an "absolute" search expression),
* the base will be the root {@link UIComponent} of the component
* tree. The leading separator character will be stripped off,
* and the remainder of the search expression will be treated as
* a "relative" search expression as described below.
* - Otherwise, if this {@link UIComponent} is a
* {@link NamingContainer} it will serve as the basis.
* - Otherwise, search up the parents of this component. If
* a {@link NamingContainer} is encountered, it will be the base.
*
* - Otherwise (if no {@link NamingContainer} is encountered)
* the root {@link UIComponent} will be the base.
*
* - The search expression (possibly modified in the previous step) is now
* a "relative" search expression that will be used to locate the
* component (if any) that has an
id
that matches, within
* the scope of the base component. The match is performed as follows:
*
* - If the search expression is a simple identifier, this value is
* compared to the
id
property, and then recursively
* through the facets and children of the base {@link UIComponent}
* (except that if a descendant {@link NamingContainer} is found,
* its own facets and children are not searched).
* - If the search expression includes more than one identifier
* separated by the separator character, the first identifier is
* used to locate a {@link NamingContainer} by the rules in the
* previous bullet point. Then, the
findComponent()
* method of this {@link NamingContainer} will be called, passing
* the remainder of the search expression.
*
*
*
* @param expr Search expression identifying the {@link UIComponent}
* to be returned
*
* @return the found {@link UIComponent}, or null
* if the component was not found.
*
* @throws IllegalArgumentException if an intermediate identifier
* in a search expression identifies a {@link UIComponent} that is
* not a {@link NamingContainer}
* @throws NullPointerException if expr
* is null
*/
public abstract UIComponent findComponent(String expr);
/**
*
* Starting at this component in the View hierarchy, search for a
* component with a clientId
equal to the argument
* clientId
and, if found, call the {@link
* ContextCallback#invokeContextCallback} method on the argument
* callback
, passing the current {@link FacesContext}
* and the found component as arguments. This method is similar to
* {@link #findComponent} but it does not support the leading
* {@link NamingContainer#SEPARATOR_CHAR} syntax for searching from the
* root of the View.
*
* The default implementation will first check if
* this.getClientId()
is equal to the argument
* clientId
. If so, call the {@link
* ContextCallback#invokeContextCallback} method on the argument callback,
* passing through the FacesContext
argument and
* passing this as the component argument. If an
* Exception
is thrown by the callback, wrap it in a
* {@link FacesException} and re-throw it. Otherwise, return
* true
.
*
* Otherwise, for each component returned by {@link
* #getFacetsAndChildren}, call invokeOnComponent()
* passing the arguments to this method, in order. The first time
* invokeOnComponent()
returns true, abort traversing
* the rest of the Iterator
and return
* true
.
*
* When calling {@link ContextCallback#invokeContextCallback}
* the implementation of this method must guarantee that the state
* of the component passed to the callback correctly reflects the
* component's position in the View hierarchy with respect to any
* state found in the argument clientId
. For example,
* an iterating component such as {@link UIData} will need to set
* its row index to correctly reflect the argument
* clientId
before finding the appropriate child
* component backed by the correct row. When the callback returns,
* either normally or by throwing an Exception
the
* implementation of this method must restore the state of the view
* to the way it was before invoking the callback.
*
* If none of the elements from {@link
* #getFacetsAndChildren} returned true
from
* invokeOnComponent()
, return false
.
*
* Simple usage example to find a component by
* clientId
.
*
private UIComponent found = null;
private void doFind(FacesContext context, String clientId) {
context.getViewRoot().invokeOnComponent(context, clientId,
new ContextCallback() {
public void invokeContextCallback(FacesContext context,
UIComponent component) {
found = component;
}
});
}
*
*
*
* @since 1.2
*
* @param context the {@link FacesContext} for the current request
*
* @param clientId the client identifier of the component to be passed
* to the argument callback.
*
* @param callback an implementation of the Callback interface.
*
* @throws NullPointerException if any of the arguments are null
*
* @throws FacesException if the argument Callback throws an
* Exception, it is wrapped in a FacesException
and re-thrown.
*
* @return true
if the a component with the given
* clientId
is found, the callback method was
* successfully invoked passing that component as an argument, and
* no Exception was thrown. Returns false
if no
* component with the given clientId
is found.
*
*/
public boolean invokeOnComponent(FacesContext context, String clientId,
ContextCallback callback) throws FacesException {
if (null == context || null == clientId || null == callback) {
throw new NullPointerException();
}
boolean found = false;
if (clientId.equals(this.getClientId(context))) {
try {
callback.invokeContextCallback(context, this);
return true;
} catch (Exception e) {
throw new FacesException(e);
}
} else {
Iterator itr = this.getFacetsAndChildren();
while (itr.hasNext() && !found) {
found = itr.next().invokeOnComponent(context, clientId,
callback);
}
}
return found;
}
// ------------------------------------------------ Facet Management Methods
/**
* Return a mutable Map
representing the facet
* {@link UIComponent}s associated with this {@link UIComponent},
* keyed by facet name (which must be a String). The returned
* implementation must support all of the standard and optional
* Map
methods, plus support the following additional
* requirements:
*
* - The
Map
implementation must implement
* the java.io.Serializable
interface.
* - Any attempt to add a
null
key or value must
* throw a NullPointerException.
* - Any attempt to add a key that is not a String must throw
* a ClassCastException.
* - Any attempt to add a value that is not a {@link UIComponent}
* must throw a ClassCastException.
* - Whenever a new facet {@link UIComponent} is added:
*
* - The
parent
property of the component must be set to
* this component instance.
* - If the
parent
property of the component was already
* non-null, the component must first be removed from its previous
* parent (where it may have been either a child or a facet).
*
* - Whenever an existing facet {@link UIComponent} is removed:
*
* - The
parent
property of the facet must be
* set to null
.
*
*
*/
public abstract Map getFacets();
/**
* Return the number of facet {@link UIComponent}s that are
* associated with this {@link UIComponent}. If there are no
* facets, this method must return 0. The method must not cause
* the creation of a facet component map.
*
* For backwards compatability with classes that extend UIComponent
* directly, a default implementation is provided that simply calls
* {@link #getFacets} and then calls the size()
method on the
* returned Map
. A more optimized version of this method is
* provided in {@link UIComponentBase#getFacetCount}.
*
* @since 1.2
*/
public int getFacetCount() {
return (getFacets().size());
}
/**
*
Convenience method to return the named facet, if it exists, or
* null
otherwise. If the requested facet does not
* exist, the facets Map must not be created.
*
* @param name Name of the desired facet
*/
public abstract UIComponent getFacet(String name);
/**
* Return an Iterator
over the facet followed by child
* {@link UIComponent}s of this {@link UIComponent}.
* Facets are returned in an undefined order, followed by
* all the children in the order they are stored in the child list. If this
* component has no facets or children, an empty Iterator
* is returned.
*
* The returned Iterator
must not support the
* remove()
operation.
*/
public abstract Iterator getFacetsAndChildren();
// -------------------------------------------- Lifecycle Processing Methods
/**
* Broadcast the specified {@link FacesEvent} to all registered
* event listeners who have expressed an interest in events of this
* type. Listeners are called in the order in which they were
* added.
*
* @param event The {@link FacesEvent} to be broadcast
*
* @throws AbortProcessingException Signal the JavaServer Faces
* implementation that no further processing on the current event
* should be performed
* @throws IllegalArgumentException if the implementation class
* of this {@link FacesEvent} is not supported by this component
* @throws NullPointerException if event
is
* null
*/
public abstract void broadcast(FacesEvent event)
throws AbortProcessingException;
/**
* Decode any new state of this {@link UIComponent} from the
* request contained in the specified {@link FacesContext}, and store
* this state as needed.
*
* During decoding, events may be enqueued for later processing
* (by event listeners who have registered an interest), by calling
* queueEvent()
.
*
* @param context {@link FacesContext} for the request we are processing
*
* @throws NullPointerException if context
* is null
*/
public abstract void decode(FacesContext context);
/**
* If our rendered
property is true
,
* render the beginning of the current state of this
* {@link UIComponent} to the response contained in the specified
* {@link FacesContext}.
*
*
* If a {@link Renderer} is associated with this {@link UIComponent},
* the actual encoding will be delegated to
* {@link Renderer#encodeBegin(FacesContext, UIComponent)}.
*
* @param context {@link FacesContext} for the response we are creating
*
* @throws IOException if an input/output error occurs while rendering
* @throws NullPointerException if context
* is null
*/
public abstract void encodeBegin(FacesContext context) throws IOException;
/**
* If our rendered
property is true
,
* render the child {@link UIComponent}s of this {@link UIComponent}.
* This method will only be called
* if the rendersChildren
property is true
.
*
* If a {@link Renderer} is associated with this {@link UIComponent},
* the actual encoding will be delegated to
* {@link Renderer#encodeChildren(FacesContext, UIComponent)}.
*
* @param context {@link FacesContext} for the response we are creating
*
* @throws IOException if an input/output error occurs while rendering
* @throws NullPointerException if context
* is null
*/
public abstract void encodeChildren(FacesContext context) throws IOException;
/**
* If our rendered
property is true
,
* render the ending of the current state of this
* {@link UIComponent}.
*
* If a {@link Renderer} is associated with this {@link UIComponent},
* the actual encoding will be delegated to
* {@link Renderer#encodeEnd(FacesContext, UIComponent)}.
*
* @param context {@link FacesContext} for the response we are creating
*
* @throws IOException if an input/output error occurs while rendering
* @throws NullPointerException if context
* is null
*/
public abstract void encodeEnd(FacesContext context) throws IOException;
/**
* If this component returns true
from {@link
* #isRendered}, render this component and all its children that
* return true
from isRendered()
,
* regardless of the value of the {@link #getRendersChildren} flag.
*
*
* @since 1.2
*
* @throws IOException if an input/output error occurs while rendering
* @throws NullPointerException if context
* is null
*/
public void encodeAll(FacesContext context) throws IOException {
if (context == null) {
throw new NullPointerException();
}
if (!isRendered()) {
return;
}
encodeBegin(context);
if (getRendersChildren()) {
encodeChildren(context);
} else if (this.getChildCount() > 0) {
for (UIComponent kid : getChildren()) {
kid.encodeAll(context);
}
}
encodeEnd(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:
*
* public class FooEvent extends FacesEvent { ... }
*
* public interface FooListener extends FacesListener {
* public void processFoo(FooEvent event);
* }
*
* public class FooComponent extends UIComponentBase {
* ...
* public void addFooListener(FooListener listener) {
* addFacesListener(listener);
* }
* public void removeFooListener(FooListener listener) {
* removeFacesListener(listener);
* }
* ...
* }
*
*
* @param listener The {@link FacesListener} to be registered
*
* @throws NullPointerException if listener
* is null
*/
protected abstract void addFacesListener(FacesListener listener);
/**
* Return an array of registered {@link FacesListener}s that are
* instances of the specified class. If there are no such registered
* listeners, a zero-length array is returned. The returned
* array can be safely be cast to an array strongly typed to
* an element type of clazz
.
*
* @param clazz Class that must be implemented by a {@link FacesListener}
* for it to be returned
*
* @throws IllegalArgumentException if class
is not,
* and does not implement, {@link FacesListener}
* @throws NullPointerException if clazz
* is null
*/
protected abstract FacesListener[] getFacesListeners(Class clazz);
/**
* 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
*/
protected abstract void removeFacesListener(FacesListener listener);
/**
*
Queue an event for broadcast at the end of the current request
* processing lifecycle phase. The default implementation in
* {@link UIComponentBase} must delegate this call to the
* queueEvent()
method of the parent {@link UIComponent}.
*
* @param event {@link FacesEvent} to be queued
*
* @throws IllegalStateException if this component is not a
* descendant of a {@link UIViewRoot}
* @throws NullPointerException if event
* is null
*/
public abstract void queueEvent(FacesEvent event);
// ------------------------------------------------ Lifecycle Phase Handlers
/**
* Perform the component tree processing required by the
* Restore View phase of the request processing
* lifecycle for all facets of this component, all children of this
* component, and this component itself, as follows.
*
* - Call the
processRestoreState()
method of all
* facets and children of this {@link UIComponent} in the order
* determined by a call to getFacetsAndChildren()
.
* - Call the
restoreState()
method of this component.
*
*
* This method may not be called if the state saving method is
* set to server.
*
* @param context {@link FacesContext} for the request we are processing
*
* @throws NullPointerException if context
* is null
*/
public abstract void processRestoreState(FacesContext context,
Object state);
/**
* Perform the component tree processing required by the
* Apply Request Values phase of the request processing
* lifecycle for all facets of this component, all children of this
* component, and this component itself, as follows.
*
* - If the
rendered
property of this {@link UIComponent}
* is false
, skip further processing.
* - Call the
processDecodes()
method of all facets
* and children of this {@link UIComponent}, in the order determined
* by a call to getFacetsAndChildren()
.
* - Call the
decode()
method of this component.
* - If a
RuntimeException
is thrown during
* decode processing, call {@link FacesContext#renderResponse}
* and re-throw the exception.
*
*
* @param context {@link FacesContext} for the request we are processing
*
* @throws NullPointerException if context
* is null
*/
public abstract void processDecodes(FacesContext context);
/**
* Perform the component tree processing required by the
* Process Validations phase of the request processing
* lifecycle for all facets of this component, all children of this
* component, and this component itself, as follows.
*
* - If the
rendered
property of this {@link UIComponent}
* is false
, skip further processing.
* - Call the
processValidators()
method of all facets
* and children of this {@link UIComponent}, in the order determined
* by a call to getFacetsAndChildren()
.
*
*
* @param context {@link FacesContext} for the request we are processing
*
* @throws NullPointerException if context
* is null
*/
public abstract void processValidators(FacesContext context);
/**
* Perform the component tree processing required by the
* Update Model Values phase of the request processing
* lifecycle for all facets of this component, all children of this
* component, and this component itself, as follows.
*
* - If the
rendered
property of this {@link UIComponent}
* is false
, skip further processing.
* - Call the
processUpdates()
method of all facets
* and children of this {@link UIComponent}, in the order determined
* by a call to getFacetsAndChildren()
.
*
*
* @param context {@link FacesContext} for the request we are processing
*
* @throws NullPointerException if context
* is null
*/
public abstract void processUpdates(FacesContext context);
/**
* Perform the component tree processing required by the state
* saving portion of the Render Response phase of the
* request processing lifecycle for all facets of this component,
* all children of this component, and this component itself, as
* follows.
*
* - consult the
transient
property of this
* component. If true, just return null
.
*
* - Call the
processSaveState()
method of all facets
* and children of this {@link UIComponent} in the order determined
* by a call to getFacetsAndChildren()
, skipping
* children and facets that are transient.
*
* - Call the
saveState()
method of this component.
*
* - Encapsulate the child state and your state into a
* Serializable Object and return it.
*
*
*
* This method may not be called if the state saving method is
* set to server.
*
* @param context {@link FacesContext} for the request we are processing
*
* @throws NullPointerException if context
* is null
*/
public abstract Object processSaveState(FacesContext context);
// ----------------------------------------------------- Convenience Methods
/**
* Convenience method to return the {@link FacesContext} instance
* for the current request.
*/
protected abstract FacesContext getFacesContext();
/**
* Convenience method to return the {@link Renderer} instance
* associated with this component, if any; otherwise, return
* null
.
*
* @param context {@link FacesContext} for the current request
*/
protected abstract Renderer getRenderer(FacesContext context);
// --------------------------------------------------------- Package Private
/**
* @param create true
if the list should be created
* @return A List of Strings of all the attributes that have been set
* against this component. If the component isn't in the default
* javax.faces.component or javax.faces.component.html packages, or
* create is false
, this will return null;
*/
List getAttributesThatAreSet(boolean create) {
String name = this.getClass().getName();
if (name != null && name.startsWith(OPTIMIZED_PACKAGE)) {
if (create && attributesThatAreSet == null) {
attributesThatAreSet = new ArrayList(6);
}
}
return attributesThatAreSet;
}
}