Save This Page
Home » mojarra-1.2_09-b02-FCS-source » javax.faces.component » [javadoc | source]
    1   /*
    2    * $Id: UIComponent.java,v 1.150.4.4 2008/04/17 21:17:00 rlubke Exp $
    3    */
    4   
    5   /*
    6    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    7    * 
    8    * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
    9    * 
   10    * The contents of this file are subject to the terms of either the GNU
   11    * General Public License Version 2 only ("GPL") or the Common Development
   12    * and Distribution License("CDDL") (collectively, the "License").  You
   13    * may not use this file except in compliance with the License. You can obtain
   14    * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
   15    * or glassfish/bootstrap/legal/LICENSE.txt.  See the License for the specific
   16    * language governing permissions and limitations under the License.
   17    * 
   18    * When distributing the software, include this License Header Notice in each
   19    * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
   20    * Sun designates this particular file as subject to the "Classpath" exception
   21    * as provided by Sun in the GPL Version 2 section of the License file that
   22    * accompanied this code.  If applicable, add the following below the License
   23    * Header, with the fields enclosed by brackets [] replaced by your own
   24    * identifying information: "Portions Copyrighted [year]
   25    * [name of copyright owner]"
   26    * 
   27    * Contributor(s):
   28    * 
   29    * If you wish your version of this file to be governed by only the CDDL or
   30    * only the GPL Version 2, indicate your decision by adding "[Contributor]
   31    * elects to include this software in this distribution under the [CDDL or GPL
   32    * Version 2] license."  If you don't indicate a single choice of license, a
   33    * recipient has the option to distribute your version of this file under
   34    * either the CDDL, the GPL Version 2 or to extend the choice of license to
   35    * its licensees as provided above.  However, if you add GPL Version 2 code
   36    * and therefore, elected the GPL Version 2 license, then the option applies
   37    * only if the new code is made subject to such option by the copyright
   38    * holder.
   39    */
   40   
   41   package javax.faces.component;
   42   
   43   
   44   import java.io.IOException;
   45   import java.util.ArrayList;
   46   import java.util.Arrays;
   47   import java.util.HashMap;
   48   import java.util.Iterator;
   49   import java.util.List;
   50   import java.util.Map;
   51   
   52   import javax.el.ELContext;
   53   import javax.el.ELException;
   54   import javax.el.ValueExpression;
   55   import javax.faces.FacesException;
   56   import javax.faces.context.FacesContext;
   57   import javax.faces.el.ValueBinding;
   58   import javax.faces.event.AbortProcessingException;
   59   import javax.faces.event.FacesEvent;
   60   import javax.faces.event.FacesListener;
   61   import javax.faces.render.Renderer;
   62   
   63   /**
   64    * <p><strong>UIComponent</strong> is the base class for all user interface
   65    * components in JavaServer Faces.  The set of {@link UIComponent} instances
   66    * associated with a particular request and response are organized into a
   67    * component tree under a {@link UIViewRoot} that represents
   68    * the entire content of the request or response.</p>
   69    *
   70    * <p>For the convenience of component developers,
   71    * {@link UIComponentBase} provides the default
   72    * behavior that is specified for a {@link UIComponent}, and is the base class
   73    * for all of the concrete {@link UIComponent} "base" implementations.
   74    * Component writers are encouraged to subclass
   75    * {@link UIComponentBase}, instead of directly
   76    * implementing this abstract class, to reduce the impact of any future changes
   77    * to the method signatures.</p>
   78    */
   79   
   80   public abstract class UIComponent implements StateHolder {
   81   
   82       /**
   83        * This array represents the packages that can leverage the
   84        * <code>attributesThatAreSet</code> List for optimized attribute
   85        * rendering.
   86        *
   87        * Hopefully JSF 2.0 will remove the need for this.
   88        */
   89       private static final String[] OPTIMIZED_PACKAGES = {
   90             "javax.faces.component",
   91             "javax.faces.component.html"
   92       };
   93   
   94       static {
   95           // Sort the array for use with Arrays.binarySearch()
   96           Arrays.sort(OPTIMIZED_PACKAGES);
   97       }
   98   
   99       /**
  100        * List of attributes that have been set on the component (this
  101        * may be from setValueExpression, the attributes map, or setters
  102        * from the concrete HTML components.  This allows
  103        * for faster rendering of attributes as this list is authoratative
  104        * on what has been set.
  105        */
  106       List<String> attributesThatAreSet;
  107   
  108   
  109       // -------------------------------------------------------------- Attributes
  110   
  111   
  112       /**
  113        * <p>Return a mutable <code>Map</code> representing the attributes
  114        * (and properties, see below) associated wth this {@link UIComponent},
  115        * keyed by attribute name (which must be a String).  The returned
  116        * implementation must support all of the standard and optional
  117        * <code>Map</code> methods, plus support the following additional
  118        * requirements:</p>
  119        * <ul>
  120        * <li>The <code>Map</code> implementation must implement
  121        *     the <code>java.io.Serializable</code> interface.</li>
  122        * <li>Any attempt to add a <code>null</code> key or value must
  123        *     throw a <code>NullPointerException</code>.</li>
  124        * <li>Any attempt to add a key that is not a String must throw
  125        *     a <code>ClassCastException</code>.</li>
  126        * <li>If the attribute name specified as a key matches a property
  127        *     of this {@link UIComponent}'s implementation class, the following
  128        *     methods will have special behavior:
  129        *     <ul>
  130        *     <li><code>containsKey</code> - Return <code>false</code>.</li>
  131        *     <li><code>get()</code> - If the property is readable, call
  132        *         the getter method and return the returned value (wrapping
  133        *         primitive values in their corresponding wrapper classes);
  134        *         otherwise throw <code>IllegalArgumentException</code>.</li>
  135        *     <li><code>put()</code> - If the property is writeable, call
  136        *         the setter method to set the corresponding value (unwrapping
  137        *         primitive values in their corresponding wrapper classes).
  138        *         If the property is not writeable, or an attempt is made to
  139        *         set a property of primitive type to <code>null</code>,
  140        *         throw <code>IllegalArgumentException</code>.</li>
  141        *     <li><code>remove</code> - Throw
  142        *         <code>IllegalArgumentException</code>.</li>
  143        *     </ul></li>
  144        * </ul>
  145        */
  146       public abstract Map<String, Object> getAttributes();
  147   
  148   
  149       // ---------------------------------------------------------------- Bindings
  150   
  151   
  152       /**
  153        *
  154        * <p>Call through to {@link #getValueExpression} and examine the
  155        * result.  If the result is an instance of the wrapper class
  156        * mandated in {@link #setValueBinding}, extract the
  157        * <code>ValueBinding</code> instance and return it.  Otherwise,
  158        * wrap the result in an implementation of
  159        * <code>ValueBinding</code>, and return it.</p>
  160        *
  161        * @param name Name of the attribute or property for which to retrieve a
  162        *  {@link ValueBinding}
  163        *
  164        * @throws NullPointerException if <code>name</code>
  165        *  is <code>null</code>
  166        *
  167        * @deprecated This has been replaced by {@link #getValueExpression}.
  168        */
  169       public abstract ValueBinding getValueBinding(String name);
  170   
  171   
  172       /**
  173        * <p>Wrap the argument <code>binding</code> in an implementation of
  174        * {@link ValueExpression} and call through to {@link
  175        * #setValueExpression}.</p>
  176        *
  177        * @param name Name of the attribute or property for which to set a
  178        *  {@link ValueBinding}
  179        * @param binding The {@link ValueBinding} to set, or <code>null</code>
  180        *  to remove any currently set {@link ValueBinding}
  181        *
  182        * @throws IllegalArgumentException if <code>name</code> is one of
  183        *  <code>id</code> or <code>parent</code>
  184        * @throws NullPointerException if <code>name</code>
  185        *  is <code>null</code>
  186        *
  187        * @deprecated This has been replaced by {@link #setValueExpression}.
  188        */
  189       public abstract void setValueBinding(String name, ValueBinding binding);
  190       
  191       // The set of ValueExpressions for this component, keyed by property
  192       // name This collection is lazily instantiated
  193       // The set of ValueExpressions for this component, keyed by property
  194       // name This collection is lazily instantiated
  195       protected Map<String,ValueExpression> bindings = null;    
  196   
  197       /**
  198        * <p>Return the {@link ValueExpression} used to calculate the value for the
  199        * specified attribute or property name, if any.</p>
  200        *
  201        * <p>This method must be overridden and implemented for components that 
  202        * comply with JSF 1.2 and later.</p>
  203        *
  204        * @since 1.2
  205        *
  206        * @param name Name of the attribute or property for which to retrieve a
  207        *  {@link ValueExpression}
  208        *
  209        * @throws NullPointerException if <code>name</code>
  210        *  is <code>null</code>
  211        *
  212        */
  213       public ValueExpression getValueExpression(String name) {
  214           ValueExpression result = null;
  215   
  216           if (name == null) {
  217               throw new NullPointerException();
  218           }
  219           if (bindings == null) {
  220               if (!isUIComponentBase()) {
  221                   ValueBinding binding = getValueBinding(name);
  222                   if (null != binding) {
  223                       result = new ValueExpressionValueBindingAdapter(binding);
  224                       // Cache this for future reference.
  225                       //noinspection CollectionWithoutInitialCapacity
  226                       bindings = new HashMap<String, ValueExpression>();
  227                       bindings.put(name, result);
  228                   }
  229               }
  230               return (result);
  231           } else {
  232               return (bindings.get(name));
  233           }
  234   
  235       }
  236   
  237       /**
  238        * <p>Set the {@link ValueExpression} used to calculate the value
  239        * for the specified attribute or property name, if any.</p>
  240        *
  241        * <p>The implementation must call {@link
  242        * ValueExpression#isLiteralText} on the argument
  243        * <code>expression</code>.  If <code>isLiteralText()</code> returns
  244        * <code>true</code>, invoke {@link ValueExpression#getValue} on the
  245        * argument expression and pass the result as the <code>value</code>
  246        * parameter in a call to <code>this.{@link
  247        * #getAttributes()}.put(name, value)</code> where <code>name</code>
  248        * is the argument <code>name</code>.  If an exception is thrown as
  249        * a result of calling {@link ValueExpression#getValue}, wrap it in
  250        * a {@link javax.faces.FacesException} and re-throw it.  If
  251        * <code>isLiteralText()</code> returns <code>false</code>, simply
  252        * store the un-evaluated <code>expression</code> argument in the
  253        * collection of <code>ValueExpression</code>s under the key given
  254        * by the argument <code>name</code>.</p>
  255        *
  256        * <p>This method must be overridden and implemented for components that 
  257        * comply with JSF 1.2 and later.</p>
  258        *
  259        * @since 1.2
  260        *
  261        * @param name Name of the attribute or property for which to set a
  262        *  {@link ValueExpression}
  263        * @param binding The {@link ValueExpression} to set, or <code>null</code>
  264        *  to remove any currently set {@link ValueExpression}
  265        *
  266        * @throws IllegalArgumentException if <code>name</code> is one of
  267        *  <code>id</code> or <code>parent</code>
  268        * @throws NullPointerException if <code>name</code>
  269        *  is <code>null</code>
  270        *
  271        */
  272       public void setValueExpression(String name, ValueExpression binding) {
  273   
  274           if (name == null) {
  275               throw new NullPointerException();
  276           } else if ("id".equals(name) || "parent".equals(name)) {
  277               throw new IllegalArgumentException();
  278           }
  279           if (binding != null) {
  280               if (!binding.isLiteralText()) {
  281                   if (bindings == null) {
  282                       //noinspection CollectionWithoutInitialCapacity
  283                       bindings = new HashMap<String, ValueExpression>();
  284                   }
  285                   // add this binding name to the 'attributesThatAreSet' list
  286                   List<String> sProperties = getAttributesThatAreSet(true);
  287                   if (sProperties != null && !sProperties.contains(name)) {
  288                       sProperties.add(name);
  289                   }
  290   
  291                   bindings.put(name, binding);
  292               } else {
  293                   ELContext context =
  294                       FacesContext.getCurrentInstance().getELContext();
  295                   try {
  296                       getAttributes().put(name, binding.getValue(context));
  297                   } catch (ELException ele) {
  298                       throw new FacesException(ele);
  299                   }
  300               }
  301           } else {
  302               if (bindings != null) {
  303                   // remove this binding name from the 'attributesThatAreSet' list
  304                   List<String> sProperties = getAttributesThatAreSet(false);
  305                   if (sProperties != null) {
  306                       sProperties.remove(name);
  307                   }
  308                   bindings.remove(name);
  309                   if (bindings.isEmpty()) {
  310                       bindings = null;
  311                   }
  312               }
  313           }
  314   
  315       }
  316       
  317       // -------------------------------------------------------------- Properties
  318   
  319   
  320       /**
  321        * <p>Return a client-side identifier for this component, generating
  322        * one if necessary.  The associated {@link Renderer}, if any,
  323        * will be asked to convert the clientId to a form suitable for
  324        * transmission to the client.</p>
  325        * 
  326        * <p>The return from this method must be the same value throughout
  327        * the lifetime of the instance, unless the <code>id</code> property
  328        * of the component is changed, or the component is placed in
  329        * a {@link NamingContainer} whose client ID changes (for example,
  330        * {@link UIData}).  However, even in these cases, consecutive
  331        * calls to this method must always return the same value.  The
  332        * implementation must follow these steps in determining the
  333        * clientId:</p>
  334        * 
  335        * <p>Find the closest ancestor to <b>this</b> component in the view
  336        * hierarchy that implements <code>NamingContainer</code>.  Call
  337        * <code>getContainerClientId()</code> on it and save the result as
  338        * the <code>parentId</code> local variable.  Call {@link #getId} on
  339        * <b>this</b> component and save the result as the
  340        * <code>myId</code> local variable.  If <code>myId</code> is
  341        * <code>null</code>, call
  342        * <code>context.getViewRoot().createUniqueId()</code> and assign
  343        * the result to myId.  If <code>parentId</code> is
  344        * non-<code>null</code>, let <code>myId</code> equal <code>parentId
  345        * + NamingContainer.SEPARATOR_CHAR + myId</code>.  Call {@link
  346        * Renderer#convertClientId}, passing <code>myId</code>, and return
  347        * the result.</p>
  348        *
  349        * @param context The {@link FacesContext} for the current request
  350        *
  351        * @throws NullPointerException if <code>context</code>
  352        *  is <code>null</code>
  353        */
  354       public abstract String getClientId(FacesContext context);
  355       
  356       /**
  357        * <p>Allow components that implement {@link NamingContainer} to
  358        * selectively disable prepending their clientId to their
  359        * descendent's clientIds by breaking the prepending logic into a
  360        * seperately callable method.  See {@link #getClientId} for usage.</p>
  361        * 
  362        * <p>By default, this method will call through to {@link
  363        * #getClientId} and return the result.
  364        *
  365        * @since 1.2
  366        * 
  367        *  @throws NullPointerException if <code>context</code> is
  368        *  <code>null</code>
  369        */
  370       public String getContainerClientId(FacesContext context) {
  371           if (context == null) {
  372               throw new NullPointerException();
  373           }
  374           return this.getClientId(context);
  375       }
  376   
  377       /**
  378        * <p>Return the identifier of the component family to which this
  379        * component belongs.  This identifier, in conjunction with the value
  380        * of the <code>rendererType</code> property, may be used to select
  381        * the appropriate {@link Renderer} for this component instance.</p>
  382        */
  383       public abstract String getFamily();
  384   
  385   
  386       /**
  387        * <p>Return the component identifier of this {@link UIComponent}.</p>
  388        */
  389       public abstract String getId();
  390   
  391   
  392       /**
  393        * <p>Set the component identifier of this {@link UIComponent} (if any).
  394        * Component identifiers must obey the following syntax restrictions:</p>
  395        * <ul>
  396        * <li>Must not be a zero-length String.</li>
  397        * <li>First character must be a letter or an underscore ('_').</li>
  398        * <li>Subsequent characters must be a letter, a digit,
  399        *     an underscore ('_'), or a dash ('-').</li>
  400        * <li>
  401        * </ul>
  402        *
  403        * <p>Component identifiers must also obey the following semantic
  404        * restrictions (note that this restriction is <strong>NOT</strong>
  405        * enforced by the <code>setId()</code> implementation):</p>
  406        * <ul>
  407        * <li>The specified identifier must be unique among all the components
  408        *     (including facets) that are descendents of the nearest ancestor
  409        *     {@link UIComponent} that is a {@link NamingContainer}, or within
  410        *     the scope of the entire component tree if there is no such
  411        *     ancestor that is a {@link NamingContainer}.</li>
  412        * </ul>
  413        *
  414        * @param id The new component identifier, or <code>null</code> to indicate
  415        *  that this {@link UIComponent} does not have a component identifier
  416        *
  417        * @throws IllegalArgumentException if <code>id</code> is not
  418        *  syntactically valid
  419        */
  420       public abstract void setId(String id);
  421   
  422   
  423       /**
  424        * <p>Return the parent {@link UIComponent} of this
  425        * <code>UIComponent</code>, if any.  A component must allow child
  426        * components to be added to and removed from the list of children
  427        * of this component, even though the child component returns null
  428        * from <code>getParent( )</code>.</p>
  429        */
  430       public abstract UIComponent getParent();
  431   
  432   
  433       /**
  434        * <p>Set the parent <code>UIComponent</code> of this
  435        * <code>UIComponent</code>.  <strong>This method must
  436        * never be called by developers;  a {@link UIComponent}'s internal
  437        * implementation will call it as components are added to or
  438        * removed from a parent's child <code>List</code> or 
  439        * facet <code>Map</code></strong>.</p>
  440        * 
  441        * @param parent The new parent, or <code>null</code> for the root node
  442        *  of a component tree
  443        */
  444       public abstract void setParent(UIComponent parent);
  445   
  446   
  447       /**
  448        * <p>Return <code>true</code> if this component (and its children)
  449        * should be rendered during the <em>Render Response</em> phase
  450        * of the request processing lifecycle.</p>
  451        */
  452       public abstract boolean isRendered();
  453   
  454   
  455       /**
  456        * <p>Set the <code>rendered</code> property of this
  457        * {@link UIComponent}.</p>
  458        * 
  459        * @param rendered If <code>true</code> render this component;
  460        *  otherwise, do not render this component
  461        */
  462       public abstract void setRendered(boolean rendered);
  463   
  464       
  465       /**
  466        * <p>Return the {@link Renderer} type for this {@link UIComponent}
  467        * (if any).</p>
  468        */
  469       public abstract String getRendererType();
  470   
  471   
  472       /**
  473        * <p>Set the {@link Renderer} type for this {@link UIComponent},
  474        * or <code>null</code> for components that render themselves.</p>
  475        *
  476        * @param rendererType Logical identifier of the type of
  477        *  {@link Renderer} to use, or <code>null</code> for components
  478        *  that render themselves
  479        */
  480       public abstract void setRendererType(String rendererType);
  481   
  482   
  483       /**
  484        * <p>Return a flag indicating whether this component is responsible
  485        * for rendering its child components.  The default implementation
  486        * in {@link UIComponentBase#getRendersChildren} tries to find the
  487        * renderer for this component.  If it does, it calls {@link
  488        * Renderer#getRendersChildren} and returns the result.  If it
  489        * doesn't, it returns false.  As of version 1.2 of the JavaServer
  490        * Faces Specification, component authors are encouraged to return
  491        * <code>true</code> from this method and rely on {@link
  492        * UIComponentBase#encodeChildren}.</p>
  493        */
  494       public abstract boolean getRendersChildren();
  495       
  496       
  497       // This is necessary for JSF components that extend from UIComponent
  498       // directly rather than extending from UIComponentBase.  Such components
  499       // may need to have implementations provided for methods that originated
  500       // from a spec version more recent than the version with which the component
  501       // complies.  Currently this private property is only consulted in the
  502       // getValueExpression() method.
  503       private boolean isUIComponentBase;
  504       private boolean isUIComponentBaseIsSet = false;
  505       
  506       private boolean isUIComponentBase() {
  507           if (!isUIComponentBaseIsSet) {
  508               isUIComponentBase = (this instanceof UIComponentBase);
  509           }
  510   
  511           return isUIComponentBase;
  512       }
  513   
  514   
  515       // ------------------------------------------------- Tree Management Methods
  516   
  517   
  518       /**
  519        * <p>Return a mutable <code>List</code> representing the child
  520        * {@link UIComponent}s associated with this component.  The returned
  521        * implementation must support all of the standard and optional
  522        * <code>List</code> methods, plus support the following additional
  523        * requirements:</p>
  524        * <ul>
  525        * <li>The <code>List</code> implementation must implement
  526        *     the <code>java.io.Serializable</code> interface.</li>
  527        * <li>Any attempt to add a <code>null</code> must throw
  528        *     a NullPointerException</li>
  529        * <li>Any attempt to add an object that does not implement
  530        *     {@link UIComponent} must throw a ClassCastException.</li>
  531        * <li>Whenever a new child component is added, the <code>parent</code>
  532        *     property of the child must be set to this component instance.
  533        *     If the <code>parent</code> property of the child was already
  534        *     non-null, the child must first be removed from its previous
  535        *     parent (where it may have been either a child or a facet).</li>
  536        * <li>Whenever an existing child component is removed, the
  537        *     <code>parent</code> property of the child must be set to
  538        *     <code>null</code>.</li>
  539        * </ul>
  540        */
  541       public abstract List<UIComponent> getChildren();
  542   
  543   
  544       /**
  545        * <p>Return the number of child {@link UIComponent}s that are
  546        * associated with this {@link UIComponent}.  If there are no
  547        * children, this method must return 0.  The method must not cause
  548        * the creation of a child component list.</p>
  549        */
  550       public abstract int getChildCount();
  551   
  552   
  553       /**
  554        * <p>Search for and return the {@link UIComponent} with an <code>id</code>
  555        * that matches the specified search expression (if any), according to the
  556        * algorithm described below.</p>
  557        *
  558        * <p>For a method to find a component given a simple
  559        * <code>clientId</code>, see {@link #invokeOnComponent}.</p>
  560        *
  561        * <p>Component identifiers are required to be unique within the scope of
  562        * the closest ancestor {@link NamingContainer} that encloses this
  563        * component (which might be this component itself).  If there are no
  564        * {@link NamingContainer} components in the ancestry of this component,
  565        * the root component in the tree is treated as if it were a
  566        * {@link NamingContainer}, whether or not its class actually implements
  567        * the {@link NamingContainer} interface.</p>
  568        *
  569        * <p>A <em>search expression</em> consists of either an
  570        * identifier (which is matched exactly against the <code>id</code>
  571        * property of a {@link UIComponent}, or a series of such identifiers
  572        * linked by the {@link NamingContainer#SEPARATOR_CHAR} character value.
  573        * The search algorithm should operates as follows, though alternate 
  574        * alogrithms may be used as long as the end result is the same:</p>
  575        * <ul>
  576        * <li>Identify the {@link UIComponent} that will be the base for searching,
  577        *     by stopping as soon as one of the following conditions is met:
  578        *     <ul>
  579        *     <li>If the search expression begins with the the separator character
  580        *         (called an "absolute" search expression),
  581        *         the base will be the root {@link UIComponent} of the component
  582        *         tree.  The leading separator character will be stripped off,
  583        *         and the remainder of the search expression will be treated as
  584        *         a "relative" search expression as described below.</li>
  585        *     <li>Otherwise, if this {@link UIComponent} is a
  586        *         {@link NamingContainer} it will serve as the basis.</li>
  587        *     <li>Otherwise, search up the parents of this component.  If
  588        *         a {@link NamingContainer} is encountered, it will be the base.
  589        *         </li>
  590        *     <li>Otherwise (if no {@link NamingContainer} is encountered)
  591        *         the root {@link UIComponent} will be the base.</li>
  592        *     </ul></li>
  593        * <li>The search expression (possibly modified in the previous step) is now
  594        *     a "relative" search expression that will be used to locate the
  595        *     component (if any) that has an <code>id</code> that matches, within
  596        *     the scope of the base component.  The match is performed as follows:
  597        *     <ul>
  598        *     <li>If the search expression is a simple identifier, this value is
  599        *         compared to the <code>id</code> property, and then recursively
  600        *         through the facets and children of the base {@link UIComponent}
  601        *         (except that if a descendant {@link NamingContainer} is found,
  602        *         its own facets and children are not searched).</li>
  603        *     <li>If the search expression includes more than one identifier
  604        *         separated by the separator character, the first identifier is
  605        *         used to locate a {@link NamingContainer} by the rules in the
  606        *         previous bullet point.  Then, the <code>findComponent()</code>
  607        *         method of this {@link NamingContainer} will be called, passing
  608        *         the remainder of the search expression.</li>
  609        *     </ul></li>
  610        * </ul>
  611        *
  612        * @param expr Search expression identifying the {@link UIComponent}
  613        *  to be returned
  614        *
  615        * @return the found {@link UIComponent}, or <code>null</code>
  616        *  if the component was not found.
  617        *
  618        * @throws IllegalArgumentException if an intermediate identifier
  619        *  in a search expression identifies a {@link UIComponent} that is
  620        *  not a {@link NamingContainer}
  621        * @throws NullPointerException if <code>expr</code>
  622        *  is <code>null</code>
  623        */
  624       public abstract UIComponent findComponent(String expr);
  625       
  626       /**
  627        *
  628        * <p>Starting at this component in the View hierarchy, search for a
  629        * component with a <code>clientId</code> equal to the argument
  630        * <code>clientId</code> and, if found, call the {@link
  631        * ContextCallback#invokeContextCallback} method on the argument
  632        * <code>callback</code>, passing the current {@link FacesContext}
  633        * and the found component as arguments. This method is similar to
  634        * {@link #findComponent} but it does not support the leading 
  635        * {@link NamingContainer#SEPARATOR_CHAR} syntax for searching from the 
  636        * root of the View.</p>
  637        *
  638        * <p>The default implementation will first check if
  639        * <code>this.getClientId()</code> is equal to the argument
  640        * <code>clientId</code>.  If so, call the {@link
  641        * ContextCallback#invokeContextCallback} method on the argument callback,
  642        * passing through the <code>FacesContext</code> argument and
  643        * passing this as the component argument.  If an
  644        * <code>Exception</code> is thrown by the callback, wrap it in a
  645        * {@link FacesException} and re-throw it.  Otherwise, return
  646        * <code>true</code>.</p>
  647        *
  648        * <p>Otherwise, for each component returned by {@link
  649        * #getFacetsAndChildren}, call <code>invokeOnComponent()</code>
  650        * passing the arguments to this method, in order.  The first time
  651        * <code>invokeOnComponent()</code> returns true, abort traversing
  652        * the rest of the <code>Iterator</code> and return
  653        * <code>true</code>.</p>
  654        *
  655        * <p>When calling {@link ContextCallback#invokeContextCallback}
  656        * the implementation of this method must guarantee that the state
  657        * of the component passed to the callback correctly reflects the
  658        * component's position in the View hierarchy with respect to any
  659        * state found in the argument <code>clientId</code>.  For example,
  660        * an iterating component such as {@link UIData} will need to set
  661        * its row index to correctly reflect the argument
  662        * <code>clientId</code> before finding the appropriate child
  663        * component backed by the correct row.  When the callback returns,
  664        * either normally or by throwing an <code>Exception</code> the
  665        * implementation of this method must restore the state of the view
  666        * to the way it was before invoking the callback.</p>
  667        *
  668        * <p>If none of the elements from {@link
  669        * #getFacetsAndChildren} returned <code>true</code> from
  670        * <code>invokeOnComponent()</code>, return <code>false</code>.</p>
  671        *
  672        * <p>Simple usage example to find a component by
  673        * <code>clientId</code>.</p>
  674   
  675   * <pre><code>
  676   private UIComponent found = null;
  677   
  678   private void doFind(FacesContext context, String clientId) {
  679     context.getViewRoot().invokeOnComponent(context, clientId,
  680         new ContextCallback() {
  681            public void invokeContextCallback(FacesContext context,
  682                                          UIComponent component) {
  683              found = component;
  684            }
  685         });
  686   }
  687   * </code></pre>
  688   
  689        *
  690        *
  691        * @since 1.2
  692        *
  693        * @param context the {@link FacesContext} for the current request
  694        *
  695        * @param clientId the client identifier of the component to be passed
  696        * to the argument callback.
  697        *
  698        * @param callback an implementation of the Callback interface.
  699        *
  700        * @throws NullPointerException if any of the arguments are null
  701        *
  702        * @throws FacesException if the argument Callback throws an
  703        * Exception, it is wrapped in a <code>FacesException</code> and re-thrown.  
  704        *
  705        * @return <code>true</code> if the a component with the given
  706        * <code>clientId</code> is found, the callback method was
  707        * successfully invoked passing that component as an argument, and
  708        * no Exception was thrown.  Returns <code>false</code> if no
  709        * component with the given <code>clientId</code> is found.
  710        *
  711        */
  712       
  713       public boolean invokeOnComponent(FacesContext context, String clientId,
  714               ContextCallback callback) throws FacesException {
  715           if (null == context || null == clientId || null == callback) {
  716               throw new NullPointerException();
  717           }
  718           
  719           boolean found = false;
  720           if (clientId.equals(this.getClientId(context))) {
  721               try {
  722                   callback.invokeContextCallback(context, this);
  723                   return true;
  724               } catch (Exception e) {
  725                   throw new FacesException(e);
  726               }
  727           } else {
  728               Iterator<UIComponent> itr = this.getFacetsAndChildren();
  729               
  730               while (itr.hasNext() && !found) {
  731                   found = itr.next().invokeOnComponent(context, clientId,
  732                           callback);
  733               }
  734           }
  735           return found;
  736       }
  737   
  738   
  739       // ------------------------------------------------ Facet Management Methods
  740   
  741   
  742       /**
  743        * <p>Return a mutable <code>Map</code> representing the facet
  744        * {@link UIComponent}s associated with this {@link UIComponent},
  745        * keyed by facet name (which must be a String).  The returned
  746        * implementation must support all of the standard and optional
  747        * <code>Map</code> methods, plus support the following additional
  748        * requirements:</p>
  749        * <ul>
  750        * <li>The <code>Map</code> implementation must implement
  751        *     the <code>java.io.Serializable</code> interface.</li>
  752        * <li>Any attempt to add a <code>null</code> key or value must
  753        *     throw a NullPointerException.</li>
  754        * <li>Any attempt to add a key that is not a String must throw
  755        *     a ClassCastException.</li>
  756        * <li>Any attempt to add a value that is not a {@link UIComponent}
  757        *     must throw a ClassCastException.</li>
  758        * <li>Whenever a new facet {@link UIComponent} is added:
  759        *     <ul>
  760        *     <li>The <code>parent</code> property of the component must be set to
  761        *         this component instance.</li>
  762        *     <li>If the <code>parent</code> property of the component was already
  763        *     non-null, the component must first be removed from its previous
  764        *     parent (where it may have been either a child or a facet).</li>
  765        *     </ul></li>
  766        * <li>Whenever an existing facet {@link UIComponent} is removed:
  767        *     <ul>
  768        *     <li>The <code>parent</code> property of the facet must be
  769        *         set to <code>null</code>.</li>
  770        *     </ul></li>
  771        * </ul>
  772        */
  773       public abstract Map<String, UIComponent> getFacets();
  774       
  775       /**
  776        * <p>Return the number of facet {@link UIComponent}s that are
  777        * associated with this {@link UIComponent}.  If there are no
  778        * facets, this method must return 0.  The method must not cause
  779        * the creation of a facet component map.</p>
  780        *
  781        * <p>For backwards compatability with classes that extend UIComponent
  782        * directly, a default implementation is provided that simply calls 
  783        * {@link #getFacets} and then calls the <code>size()</code> method on the 
  784        * returned <code>Map</code>.  A more optimized version of this method is 
  785        * provided in {@link UIComponentBase#getFacetCount}.
  786        *
  787        * @since 1.2
  788        */
  789       public int getFacetCount() {
  790           return (getFacets().size());
  791       }
  792   
  793   
  794   
  795       /**
  796        * <p>Convenience method to return the named facet, if it exists, or
  797        * <code>null</code> otherwise.  If the requested facet does not
  798        * exist, the facets Map must not be created.</p>
  799        *
  800        * @param name Name of the desired facet
  801        */
  802       public abstract UIComponent getFacet(String name);
  803   
  804   
  805       /**
  806        * <p>Return an <code>Iterator</code> over the facet followed by child
  807        * {@link UIComponent}s of this {@link UIComponent}.
  808        * Facets are returned in an undefined order, followed by
  809        * all the children in the order they are stored in the child list. If this
  810        * component has no facets or children, an empty <code>Iterator</code>
  811        * is returned.</p>
  812        *
  813        * <p>The returned <code>Iterator</code> must not support the
  814        * <code>remove()</code> operation.</p>
  815        */
  816       public abstract Iterator<UIComponent> getFacetsAndChildren();
  817       
  818       
  819       // -------------------------------------------- Lifecycle Processing Methods
  820   
  821   
  822       /**
  823        * <p>Broadcast the specified {@link FacesEvent} to all registered
  824        * event listeners who have expressed an interest in events of this
  825        * type.  Listeners are called in the order in which they were
  826        * added.</p>
  827        *
  828        * @param event The {@link FacesEvent} to be broadcast
  829        *
  830        * @throws AbortProcessingException Signal the JavaServer Faces
  831        *  implementation that no further processing on the current event
  832        *  should be performed
  833        * @throws IllegalArgumentException if the implementation class
  834        *  of this {@link FacesEvent} is not supported by this component
  835        * @throws NullPointerException if <code>event</code> is
  836        * <code>null</code>
  837        */
  838       public abstract void broadcast(FacesEvent event)
  839           throws AbortProcessingException;
  840   
  841   
  842       /**
  843        * <p>Decode any new state of this {@link UIComponent} from the
  844        * request contained in the specified {@link FacesContext}, and store
  845        * this state as needed.</p>
  846        *
  847        * <p>During decoding, events may be enqueued for later processing
  848        * (by event listeners who have registered an interest),  by calling
  849        * <code>queueEvent()</code>.</p>
  850        *
  851        * @param context {@link FacesContext} for the request we are processing
  852        *
  853        * @throws NullPointerException if <code>context</code>
  854        *  is <code>null</code>
  855        */
  856       public abstract void decode(FacesContext context);
  857   
  858   
  859       /**
  860        * <p>If our <code>rendered</code> property is <code>true</code>,
  861        * render the beginning of the current state of this
  862        * {@link UIComponent} to the response contained in the specified
  863        * {@link FacesContext}.
  864        * </p>
  865        * 
  866        * <p>If a {@link Renderer} is associated with this {@link UIComponent}, 
  867        * the actual encoding will be delegated to 
  868        * {@link Renderer#encodeBegin(FacesContext, UIComponent)}.</p> 
  869        *
  870        * @param context {@link FacesContext} for the response we are creating
  871        *
  872        * @throws IOException if an input/output error occurs while rendering
  873        * @throws NullPointerException if <code>context</code>
  874        *  is <code>null</code>
  875        */
  876       public abstract void encodeBegin(FacesContext context) throws IOException;
  877   
  878   
  879       /**
  880        * <p>If our <code>rendered</code> property is <code>true</code>,
  881        * render the child {@link UIComponent}s of this {@link UIComponent}.
  882        * This method will only be called
  883        * if the <code>rendersChildren</code> property is <code>true</code>.</p>
  884        * 
  885        * <p>If a {@link Renderer} is associated with this {@link UIComponent}, 
  886        * the actual encoding will be delegated to 
  887        * {@link Renderer#encodeChildren(FacesContext, UIComponent)}.</p> 
  888        *
  889        * @param context {@link FacesContext} for the response we are creating
  890        *
  891        * @throws IOException if an input/output error occurs while rendering
  892        * @throws NullPointerException if <code>context</code>
  893        *  is <code>null</code>
  894        */
  895       public abstract void encodeChildren(FacesContext context) throws IOException;
  896   
  897   
  898       /**
  899        * <p>If our <code>rendered</code> property is <code>true</code>,
  900        * render the ending of the current state of this
  901        * {@link UIComponent}.</p>
  902        * 
  903        * <p>If a {@link Renderer} is associated with this {@link UIComponent}, 
  904        * the actual encoding will be delegated to 
  905        * {@link Renderer#encodeEnd(FacesContext, UIComponent)}.</p> 
  906        *
  907        * @param context {@link FacesContext} for the response we are creating
  908        *
  909        * @throws IOException if an input/output error occurs while rendering
  910        * @throws NullPointerException if <code>context</code>
  911        *  is <code>null</code>
  912        */
  913       public abstract void encodeEnd(FacesContext context) throws IOException;
  914   
  915       /**
  916        * <p>If this component returns <code>true</code> from {@link
  917        * #isRendered}, render this component and all its children that
  918        * return <code>true</code> from <code>isRendered()</code>,
  919        * regardless of the value of the {@link #getRendersChildren} flag.
  920        * </p>
  921        *
  922        * @since 1.2
  923        *
  924        * @throws IOException if an input/output error occurs while rendering
  925        * @throws NullPointerException if <code>context</code>
  926        *  is <code>null</code>
  927        */
  928       
  929       public void encodeAll(FacesContext context) throws IOException {
  930           if (!isRendered()) {
  931               return;
  932           }
  933   
  934           encodeBegin(context);
  935           if (getRendersChildren()) {
  936               encodeChildren(context);
  937           }
  938           else            if (this.getChildCount() > 0) {
  939                   Iterator kids = getChildren().iterator();
  940                   while (kids.hasNext()) {
  941                       UIComponent kid = (UIComponent) kids.next();
  942                       kid.encodeAll(context);
  943                   }
  944               }
  945           
  946           encodeEnd(context);
  947       }
  948   
  949   
  950   
  951       // -------------------------------------------------- Event Listener Methods
  952   
  953   
  954       /**
  955        * <p>Add the specified {@link FacesListener} to the set of listeners
  956        * registered to receive event notifications from this {@link UIComponent}.
  957        * It is expected that {@link UIComponent} classes acting as event sources
  958        * will have corresponding typesafe APIs for registering listeners of the
  959        * required type, and the implementation of those registration methods
  960        * will delegate to this method.  For example:</p>
  961        * <pre>
  962        * public class FooEvent extends FacesEvent { ... }
  963        *
  964        * public interface FooListener extends FacesListener {
  965        *   public void processFoo(FooEvent event);
  966        * }
  967        *
  968        * public class FooComponent extends UIComponentBase {
  969        *   ...
  970        *   public void addFooListener(FooListener listener) {
  971        *     addFacesListener(listener);
  972        *   }
  973        *   public void removeFooListener(FooListener listener) {
  974        *     removeFacesListener(listener);
  975        *   }
  976        *   ...
  977        * }
  978        * </pre>
  979        *
  980        * @param listener The {@link FacesListener} to be registered
  981        *
  982        * @throws NullPointerException if <code>listener</code>
  983        *  is <code>null</code>
  984        */
  985       protected abstract void addFacesListener(FacesListener listener);
  986   
  987   
  988       /**
  989        * <p>Return an array of registered {@link FacesListener}s that are
  990        * instances of the specified class.  If there are no such registered
  991        * listeners, a zero-length array is returned.  The returned 
  992        * array can be safely be cast to an array strongly typed to
  993        * an element type of <code>clazz</code>.</p>
  994        *
  995        * @param clazz Class that must be implemented by a {@link FacesListener}
  996        *  for it to be returned
  997        *
  998        * @throws IllegalArgumentException if <code>class</code> is not,
  999        *  and does not implement, {@link FacesListener}
 1000        * @throws NullPointerException if <code>clazz</code>
 1001        *  is <code>null</code>
 1002        */
 1003       protected abstract FacesListener[] getFacesListeners(Class clazz);
 1004   
 1005   
 1006       /**
 1007        * <p>Remove the specified {@link FacesListener} from the set of listeners
 1008        * registered to receive event notifications from this {@link UIComponent}.
 1009        *
 1010        * @param listener The {@link FacesListener} to be deregistered
 1011        *
 1012        * @throws NullPointerException if <code>listener</code>
 1013        *  is <code>null</code>
 1014        */
 1015       protected abstract void removeFacesListener(FacesListener listener);
 1016   
 1017   
 1018       /**
 1019        * <p>Queue an event for broadcast at the end of the current request
 1020        * processing lifecycle phase.  The default implementation in
 1021        * {@link UIComponentBase} must delegate this call to the
 1022        * <code>queueEvent()</code> method of the parent {@link UIComponent}.</p>
 1023        *
 1024        * @param event {@link FacesEvent} to be queued
 1025        *
 1026        * @throws IllegalStateException if this component is not a
 1027        *  descendant of a {@link UIViewRoot}
 1028        * @throws NullPointerException if <code>event</code>
 1029        *  is <code>null</code>
 1030        */
 1031       public abstract void queueEvent(FacesEvent event);
 1032   
 1033   
 1034       // ------------------------------------------------ Lifecycle Phase Handlers
 1035   
 1036   
 1037       /**
 1038        * <p>Perform the component tree processing required by the
 1039        * <em>Restore View</em> phase of the request processing
 1040        * lifecycle for all facets of this component, all children of this
 1041        * component, and this component itself, as follows.</p>
 1042        * <ul>
 1043        * <li>Call the <code>processRestoreState()</code> method of all
 1044        * facets and children of this {@link UIComponent} in the order
 1045        * determined by a call to <code>getFacetsAndChildren()</code>.</li>
 1046        * <li>Call the <code>restoreState()</code> method of this component.</li>
 1047        * </ul>
 1048        *
 1049        * <p>This method may not be called if the state saving method is
 1050        * set to server.</p>
 1051        *
 1052        * @param context {@link FacesContext} for the request we are processing
 1053        *
 1054        * @throws NullPointerException if <code>context</code>
 1055        *  is <code>null</code>
 1056        */
 1057       public abstract void processRestoreState(FacesContext context,
 1058                                                Object state);
 1059   
 1060   
 1061       /**
 1062        * <p>Perform the component tree processing required by the
 1063        * <em>Apply Request Values</em> phase of the request processing
 1064        * lifecycle for all facets of this component, all children of this
 1065        * component, and this component itself, as follows.</p>
 1066        * <ul>
 1067        * <li>If the <code>rendered</code> property of this {@link UIComponent}
 1068        *     is <code>false</code>, skip further processing.</li>
 1069        * <li>Call the <code>processDecodes()</code> method of all facets
 1070        *     and children of this {@link UIComponent}, in the order determined
 1071        *     by a call to <code>getFacetsAndChildren()</code>.</li>
 1072        * <li>Call the <code>decode()</code> method of this component.</li>
 1073        * <li>If a <code>RuntimeException</code> is thrown during
 1074        *     decode processing, call {@link FacesContext#renderResponse}
 1075        *     and re-throw the exception.</li>
 1076        * </ul>
 1077        *
 1078        * @param context {@link FacesContext} for the request we are processing
 1079        *
 1080        * @throws NullPointerException if <code>context</code>
 1081        *  is <code>null</code>
 1082        */
 1083       public abstract void processDecodes(FacesContext context);
 1084   
 1085   
 1086       /**
 1087        * <p>Perform the component tree processing required by the
 1088        * <em>Process Validations</em> phase of the request processing
 1089        * lifecycle for all facets of this component, all children of this
 1090        * component, and this component itself, as follows.</p>
 1091        * <ul>
 1092        * <li>If the <code>rendered</code> property of this {@link UIComponent}
 1093        *     is <code>false</code>, skip further processing.</li>
 1094        * <li>Call the <code>processValidators()</code> method of all facets
 1095        *     and children of this {@link UIComponent}, in the order determined
 1096        *     by a call to <code>getFacetsAndChildren()</code>.</li>
 1097        * </ul>
 1098        *
 1099        * @param context {@link FacesContext} for the request we are processing
 1100        *
 1101        * @throws NullPointerException if <code>context</code>
 1102        *  is <code>null</code>
 1103        */
 1104       public abstract void processValidators(FacesContext context);
 1105   
 1106   
 1107       /**
 1108        * <p>Perform the component tree processing required by the
 1109        * <em>Update Model Values</em> phase of the request processing
 1110        * lifecycle for all facets of this component, all children of this
 1111        * component, and this component itself, as follows.</p>
 1112        * <ul>
 1113        * <li>If the <code>rendered</code> property of this {@link UIComponent}
 1114        *     is <code>false</code>, skip further processing.</li>
 1115        * <li>Call the <code>processUpdates()</code> method of all facets
 1116        *     and children of this {@link UIComponent}, in the order determined
 1117        *     by a call to <code>getFacetsAndChildren()</code>.</li>
 1118        * </ul>
 1119        *
 1120        * @param context {@link FacesContext} for the request we are processing
 1121        *
 1122        * @throws NullPointerException if <code>context</code>
 1123        *  is <code>null</code>
 1124        */
 1125       public abstract void processUpdates(FacesContext context);
 1126   
 1127   
 1128       /**
 1129        * <p>Perform the component tree processing required by the state
 1130        * saving portion of the <em>Render Response</em> phase of the
 1131        * request processing lifecycle for all facets of this component,
 1132        * all children of this component, and this component itself, as
 1133        * follows.</p> <ul>
 1134        *
 1135        * <li>consult the <code>transient</code> property of this
 1136        * component.  If true, just return <code>null</code>.</li>
 1137        *
 1138        * <li>Call the <code>processSaveState()</code> method of all facets
 1139        * and children of this {@link UIComponent} in the order determined
 1140        * by a call to <code>getFacetsAndChildren()</code>, skipping
 1141        * children and facets that are transient.</li>
 1142        *
 1143        * <li>Call the <code>saveState()</code> method of this component.</li>
 1144        *
 1145        * <li>Encapsulate the child state and your state into a
 1146        * Serializable Object and return it.</li> 
 1147        *
 1148        * </ul>
 1149        *
 1150        * <p>This method may not be called if the state saving method is
 1151        * set to server.</p>
 1152        *
 1153        * @param context {@link FacesContext} for the request we are processing
 1154        *
 1155        * @throws NullPointerException if <code>context</code>
 1156        *  is <code>null</code>
 1157        */
 1158       public abstract Object processSaveState(FacesContext context);
 1159   
 1160   
 1161       // ----------------------------------------------------- Convenience Methods
 1162   
 1163   
 1164       /**
 1165        * <p>Convenience method to return the {@link FacesContext} instance
 1166        * for the current request.</p>
 1167        */
 1168       protected abstract FacesContext getFacesContext();
 1169   
 1170   
 1171       /**
 1172        * <p>Convenience method to return the {@link Renderer} instance
 1173        * associated with this component, if any; otherwise, return
 1174        * <code>null</code>.</p>
 1175        *
 1176        * @param context {@link FacesContext} for the current request
 1177        */
 1178       protected abstract Renderer getRenderer(FacesContext context);
 1179   
 1180   
 1181       // --------------------------------------------------------- Package Private
 1182   
 1183   
 1184       /**
 1185        * @param create <code>true</code> if the list should be created
 1186        * @return A List of Strings of all the attributes that have been set
 1187        *  against this component.  If the component isn't in the default
 1188        *  javax.faces.component or javax.faces.component.html packages, or
 1189        *  create is <code>false</code>, this will return null;
 1190        */
 1191       List<String> getAttributesThatAreSet(boolean create) {
 1192           // Class.getPackage() returns null for Groovy based-classes.
 1193           Package pkg = this.getClass().getPackage();
 1194           if (pkg != null) {
 1195               String pkgName = this.getClass().getPackage().getName();
 1196               if (create
 1197                   && Arrays.binarySearch(OPTIMIZED_PACKAGES, pkgName) >= 0) {
 1198                   if (attributesThatAreSet == null) {
 1199                       attributesThatAreSet = new ArrayList<String>(6);
 1200                   }
 1201               }
 1202           }
 1203           return attributesThatAreSet;
 1204           
 1205       }
 1206   
 1207   }

Save This Page
Home » mojarra-1.2_09-b02-FCS-source » javax.faces.component » [javadoc | source]