Home » Mojarra-2.0.1 » javax » faces » component » [javadoc | source]

    1   /*
    2    * $Id: UIComponent.java,v 1.153.8.13 2008/04/17 18:51:28 edburns 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.io.InputStream;
   46   import java.util.ArrayList;
   47   import java.util.Collections;
   48   import java.util.Enumeration;
   49   import java.util.HashMap;
   50   import java.util.HashSet;
   51   import java.util.Iterator;
   52   import java.util.List;
   53   import java.util.Locale;
   54   import java.util.Map;
   55   
   56   import java.util.MissingResourceException;
   57   import java.util.PropertyResourceBundle;
   58   import java.util.ResourceBundle;
   59   import java.util.Set;
   60   import java.util.logging.Level;
   61   import java.util.logging.Logger;
   62   import javax.el.ELContext;
   63   import javax.el.ELException;
   64   import javax.el.ValueExpression;
   65   import javax.faces.FacesException;
   66   import javax.faces.FacesWrapper;
   67   import javax.faces.application.Resource;
   68   import javax.faces.component.visit.VisitCallback;
   69   import javax.faces.component.visit.VisitContext;
   70   import javax.faces.component.visit.VisitHint;
   71   import javax.faces.component.visit.VisitResult;
   72   import javax.faces.context.FacesContext;
   73   import javax.faces.el.ValueBinding;
   74   import javax.faces.event.AbortProcessingException;
   75   import javax.faces.event.PostRestoreStateEvent;
   76   import javax.faces.event.ComponentSystemEvent;
   77   import javax.faces.event.ComponentSystemEventListener;
   78   import javax.faces.event.FacesEvent;
   79   import javax.faces.event.SystemEvent;
   80   import javax.faces.event.SystemEventListener;
   81   import javax.faces.event.FacesListener;
   82   import javax.faces.event.SystemEventListenerHolder;
   83   import javax.faces.render.Renderer;
   84   
   85   /**
   86    * <p><strong class="changed_modified_2_0">UIComponent</strong> is the
   87    * base class for all user interface components in JavaServer Faces.
   88    * The set of {@link UIComponent} instances associated with a particular
   89    * request and response are organized into a component tree under a
   90    * {@link UIViewRoot} that represents the entire content of the request
   91    * or response.</p>
   92    *
   93    * <p>For the convenience of component developers,
   94    * {@link UIComponentBase} provides the default
   95    * behavior that is specified for a {@link UIComponent}, and is the base class
   96    * for all of the concrete {@link UIComponent} "base" implementations.
   97    * Component writers are encouraged to subclass
   98    * {@link UIComponentBase}, instead of directly
   99    * implementing this abstract class, to reduce the impact of any future changes
  100    * to the method signatures.</p>
  101    *
  102    * <p class="changed_added_2_0">If the {@link
  103    * javax.faces.event.ListenerFor} annotation is attached to the class
  104    * definition of a <code>Component</code>, that class must also
  105    * implement {@link javax.faces.event.ComponentSystemEventListener}.
  106    * </p>
  107   
  108    */
  109   
  110   public abstract class UIComponent implements PartialStateHolder, SystemEventListenerHolder,
  111           ComponentSystemEventListener {
  112   
  113       private static Logger LOGGER = Logger.getLogger("javax.faces.component",
  114               "javax.faces.LogStrings");
  115       
  116       /**
  117        * <p class="changed_added_2_0">The key to which the
  118        * <code>UIComponent</code> currently being processed will be
  119        * associated with within the {@link FacesContext} attributes map.</p>
  120        *
  121        * @see javax.faces.context.FacesContext#getAttributes()
  122        *
  123        * @since 2.0
  124        */
  125       public static final String CURRENT_COMPONENT = "javax.faces.component.CURRENT_COMPONENT";
  126   
  127       /**
  128        * <p class="changed_added_2_0">The key to which the
  129        * <em>composite</em> <code>UIComponent</code> currently being
  130        * processed will be associated with within the {@link FacesContext}
  131        * attributes map.</p>
  132        *
  133        * @see javax.faces.context.FacesContext#getAttributes()
  134        *
  135        * @since 2.0
  136        */
  137       public static final String CURRENT_COMPOSITE_COMPONENT = "javax.faces.component.CURRENT_COMPOSITE_COMPONENT";
  138   
  139       /**
  140        * <p class="changed_added_2_0">The value of this constant is used as the key in the
  141        * component attribute map, the value for which is a
  142        * <code>java.beans.BeanInfo</code> implementation describing the composite
  143        * component.  This <code>BeanInfo</code> is known as the 
  144        * <em>composite component BeanInfo</em>.</p>
  145        *
  146        * @since 2.0
  147        */
  148       public static final String BEANINFO_KEY = "javax.faces.component.BEANINFO_KEY";
  149   
  150   
  151       /**
  152        * <p class="changed_added_2_0">The value of this constant is used as the key
  153        * in the <em>composite component BeanDescriptor</em> for the 
  154        * <code>Map&lt;PropertyDescriptor&gt;</code> that contains meta-information
  155        * for the declared facets for this composite component.
  156        * This map must contain an entry under the key {@link #COMPOSITE_FACET_NAME}, even
  157        * if no facets were explicitly declared.  See {@link #COMPOSITE_FACET_NAME}.</p>
  158        *
  159        * @since 2.0
  160        */
  161       public static final String FACETS_KEY = "javax.faces.component.FACETS_KEY";
  162       
  163       /**
  164        * <p class="changed_added_2_0">The value of this constant is used as the key
  165        * in the component attributes <code>Map</code> for the 
  166        * {@link javax.faces.view.Location} in the view at which this component 
  167        * instance resides.</p>
  168        *
  169        * @since 2.0
  170        */
  171       public static final String VIEW_LOCATION_KEY = "javax.faces.component.VIEW_LOCATION_KEY";
  172       
  173       /**
  174        * <p class="changed_added_2_0">The value of this constant is used as the key
  175        * in the <em>composite component BeanDescriptor</em> for a 
  176        * <code>ValueExpression</code> that evaluates to the 
  177        * <code>component-type</code> of the <em>composite component root</em>
  178        * <code>UIComponent</code> for this composite component, if
  179        * one was declared by the composite component author.</p>
  180        *
  181        * @since 2.0
  182        */
  183       public static final String COMPOSITE_COMPONENT_TYPE_KEY = "javax.faces.component.COMPOSITE_COMPONENT_TYPE";
  184       
  185       /**
  186        * <p class="changed_added_2_0">The value of this constant is used as the key
  187        * in the <code>Map</code> returned as described in {@link #FACETS_KEY}
  188        * for the 
  189        * <code>PropertyDescriptor</code> describing the composite component facet.
  190        * The value of this constant is also used as the key in the <code>Map</code>
  191        * returned from {@link #getFacets}.  In this case, it refers to the actual
  192        * facet that is the {@link javax.faces.component.UIPanel} that is the parent of the all
  193        * of the components in the <code>&lt;composite:implementation&gt;</code>
  194        * section of the <em>composite component VDL file</em>.</p>
  195        *
  196        * @since 2.0
  197        */
  198       public static final String COMPOSITE_FACET_NAME = "javax.faces.component.COMPOSITE_FACET_NAME";
  199   
  200       enum PropertyKeysPrivate {
  201           attributesThatAreSet
  202       }
  203   
  204       /**
  205        * Properties that are tracked by state saving.
  206        */
  207       enum PropertyKeys {
  208           rendered,
  209           attributes,
  210           bindings,
  211           rendererType,
  212           systemEventListeners,
  213           behaviors
  214       }
  215   
  216       /**
  217        * List of attributes that have been set on the component (this
  218        * may be from setValueExpression, the attributes map, or setters
  219        * from the concrete HTML components.  This allows
  220        * for faster rendering of attributes as this list is authoratative
  221        * on what has been set.
  222        */
  223       List<String> attributesThatAreSet;
  224       StateHelper stateHelper = null;
  225       UIComponent compositeParent;
  226   
  227   
  228       // -------------------------------------------------------------- Attributes
  229   
  230   
  231       /**
  232        * <p>Return a mutable 
  233        * <code>Map</code> representing the attributes
  234        * (and properties, see below) associated wth this {@link UIComponent},
  235        * keyed by attribute name (which must be a String).  The returned
  236        * implementation must support all of the standard and optional
  237        * <code>Map</code> methods, plus support the following additional
  238        * requirements:</p>
  239        * <ul>
  240        * <li>The <code>Map</code> implementation must implement
  241        *     the <code>java.io.Serializable</code> interface.</li>
  242        * <li>Any attempt to add a <code>null</code> key or value must
  243        *     throw a <code>NullPointerException</code>.</li>
  244        * <li>Any attempt to add a key that is not a String must throw
  245        *     a <code>ClassCastException</code>.</li>
  246        * <li>If the attribute name specified as a key matches a property
  247        *     of this {@link UIComponent}'s implementation class, the following
  248        *     methods will have special behavior:
  249        *     <ul>
  250        *     <li><code>containsKey</code> - Return <code>false</code>.</li>
  251        *     <li><code>get()</code> - If the property is readable, call
  252        *         the getter method and return the returned value (wrapping
  253        *         primitive values in their corresponding wrapper classes);
  254        *         otherwise throw <code>IllegalArgumentException</code>.</li>
  255        *     <li><code>put()</code> - If the property is writeable, call
  256        *         the setter method to set the corresponding value (unwrapping
  257        *         primitive values in their corresponding wrapper classes).
  258        *         If the property is not writeable, or an attempt is made to
  259        *         set a property of primitive type to <code>null</code>,
  260        *         throw <code>IllegalArgumentException</code>.</li>
  261        *     <li><code>remove</code> - Throw
  262        *         <code>IllegalArgumentException</code>.</li>
  263        *     </ul></li>
  264        * </ul>
  265        * 
  266        */
  267       public abstract Map<String, Object> getAttributes();
  268       
  269       
  270       // ---------------------------------------------------------------- Bindings
  271   
  272   
  273       /**
  274        *
  275        * <p>Call through to {@link #getValueExpression} and examine the
  276        * result.  If the result is an instance of the wrapper class
  277        * mandated in {@link #setValueBinding}, extract the
  278        * <code>ValueBinding</code> instance and return it.  Otherwise,
  279        * wrap the result in an implementation of
  280        * <code>ValueBinding</code>, and return it.</p>
  281        *
  282        * @param name Name of the attribute or property for which to retrieve a
  283        *  {@link ValueBinding}
  284        *
  285        * @throws NullPointerException if <code>name</code>
  286        *  is <code>null</code>
  287        *
  288        * @deprecated This has been replaced by {@link #getValueExpression}.
  289        */
  290       public abstract ValueBinding getValueBinding(String name);
  291   
  292   
  293       /**
  294        * <p>Wrap the argument <code>binding</code> in an implementation of
  295        * {@link ValueExpression} and call through to {@link
  296        * #setValueExpression}.</p>
  297        *
  298        * @param name Name of the attribute or property for which to set a
  299        *  {@link ValueBinding}
  300        * @param binding The {@link ValueBinding} to set, or <code>null</code>
  301        *  to remove any currently set {@link ValueBinding}
  302        *
  303        * @throws IllegalArgumentException if <code>name</code> is one of
  304        *  <code>id</code> or <code>parent</code>
  305        * @throws NullPointerException if <code>name</code>
  306        *  is <code>null</code>
  307        *
  308        * @deprecated This has been replaced by {@link #setValueExpression}.
  309        */
  310       public abstract void setValueBinding(String name, ValueBinding binding);
  311   
  312       // The set of ValueExpressions for this component, keyed by property
  313       // name This collection is lazily instantiated
  314       // The set of ValueExpressions for this component, keyed by property
  315       // name This collection is lazily instantiated
  316       @Deprecated
  317       protected Map<String,ValueExpression> bindings = null;
  318   
  319       /**
  320        * <p>Return the {@link ValueExpression} used to calculate the value for the
  321        * specified attribute or property name, if any.</p>
  322        *
  323        * <p>This method must be overridden and implemented for components that
  324        * comply with JSF 1.2 and later.</p>
  325        *
  326        * @since 1.2
  327        *
  328        * @param name Name of the attribute or property for which to retrieve a
  329        *  {@link ValueExpression}
  330        *
  331        * @throws NullPointerException if <code>name</code>
  332        *  is <code>null</code>
  333        *
  334        */
  335       public ValueExpression getValueExpression(String name) {
  336   
  337           if (name == null) {
  338               throw new NullPointerException();
  339           }
  340   
  341           Map<String,ValueExpression> map = (Map<String,ValueExpression>)
  342                 getStateHelper().get(UIComponentBase.PropertyKeys.bindings);
  343           return ((map != null) ? map.get(name) : null);
  344   
  345       }
  346   
  347       /**
  348        * <p>Set the {@link ValueExpression} used to calculate the value
  349        * for the specified attribute or property name, if any.</p>
  350        *
  351        * <p>The implementation must call {@link
  352        * ValueExpression#isLiteralText} on the argument
  353        * <code>expression</code>.  If <code>isLiteralText()</code> returns
  354        * <code>true</code>, invoke {@link ValueExpression#getValue} on the
  355        * argument expression and pass the result as the <code>value</code>
  356        * parameter in a call to <code>this.{@link
  357        * #getAttributes()}.put(name, value)</code> where <code>name</code>
  358        * is the argument <code>name</code>.  If an exception is thrown as
  359        * a result of calling {@link ValueExpression#getValue}, wrap it in
  360        * a {@link javax.faces.FacesException} and re-throw it.  If
  361        * <code>isLiteralText()</code> returns <code>false</code>, simply
  362        * store the un-evaluated <code>expression</code> argument in the
  363        * collection of <code>ValueExpression</code>s under the key given
  364        * by the argument <code>name</code>.</p>
  365        *
  366        * <p>This method must be overridden and implemented for components that
  367        * comply with JSF 1.2 and later.</p>
  368        *
  369        * @since 1.2
  370        *
  371        * @param name Name of the attribute or property for which to set a
  372        *  {@link ValueExpression}
  373        * @param binding The {@link ValueExpression} to set, or <code>null</code>
  374        *  to remove any currently set {@link ValueExpression}
  375        *
  376        * @throws IllegalArgumentException if <code>name</code> is one of
  377        *  <code>id</code> or <code>parent</code>
  378        * @throws NullPointerException if <code>name</code>
  379        *  is <code>null</code>
  380        *
  381        */
  382       public void setValueExpression(String name, ValueExpression binding) {
  383   
  384           if (name == null) {
  385               throw new NullPointerException();
  386           } else if ("id".equals(name) || "parent".equals(name)) {
  387               throw new IllegalArgumentException();
  388           }
  389   
  390           if (binding != null) {
  391               if (!binding.isLiteralText()) {
  392                   //if (bindings == null) {
  393                   //    //noinspection CollectionWithoutInitialCapacity
  394                   //    bindings = new HashMap<String, ValueExpression>();
  395                   //}
  396                   // add this binding name to the 'attributesThatAreSet' list
  397                   //List<String> sProperties = (List<String>)
  398                   //      getStateHelper().get(PropertyKeysPrivate.attributesThatAreSet);
  399   
  400                    List<String> sProperties =
  401                         (List<String>) getStateHelper().get(PropertyKeysPrivate.attributesThatAreSet);
  402                   if (sProperties == null) {
  403                       getStateHelper().add(PropertyKeysPrivate.attributesThatAreSet, name);
  404                   } else if (!sProperties.contains(name)) {
  405                       getStateHelper().add(PropertyKeysPrivate.attributesThatAreSet, name);
  406                   }
  407                   getStateHelper().put(UIComponentBase.PropertyKeys.bindings,
  408                                        name,
  409                                        binding);
  410                   //bindings.put(name, binding);
  411               } else {
  412                   ELContext context =
  413                       FacesContext.getCurrentInstance().getELContext();
  414                   try {
  415                       getAttributes().put(name, binding.getValue(context));
  416                   } catch (ELException ele) {
  417                       throw new FacesException(ele);
  418                   }
  419               }
  420           } else {
  421               //if (bindings != null) {
  422                   // remove this binding name from the 'attributesThatAreSet' list
  423   //                List<String> sProperties = getAttributesThatAreSet(false);
  424   //                if (sProperties != null) {
  425   //                    sProperties.remove(name);
  426   //                }
  427                   getStateHelper().remove(PropertyKeysPrivate.attributesThatAreSet,
  428                                           name);
  429                   getStateHelper().remove(UIComponentBase.PropertyKeys.bindings, name);
  430                   //bindings.remove(name);
  431                  // if (bindings.isEmpty()) {
  432                  //     bindings = null;
  433                  // }
  434               }
  435          // }
  436   
  437       }
  438   
  439       // -------------------------------------------------------------- Properties
  440   
  441       boolean initialState;
  442   
  443       /**
  444        * <p class="changed_added_2_0">An implementation of {@link
  445        * PartialStateHolder#markInitialState}, this method is called by
  446        * the runtime to indicate that the instance should start tracking
  447        * changes to its state.</p>
  448        * @since 2.0
  449        */
  450       public void markInitialState() {
  451           initialState = true;
  452       }
  453   
  454   
  455       /**
  456        * <p class="changed_added_2_0">An implementation of {@link
  457        * PartialStateHolder#initialStateMarked}, this method is called by
  458        * the runtime to test if the {@link
  459        * PartialStateHolder#markInitialState} method was called.</p>
  460        * @since 2.0
  461        */
  462       public boolean initialStateMarked() {
  463           return initialState;
  464       }
  465   
  466   
  467       /**
  468        * <p class="changed_added_2_0">An implementation of {@link
  469        * PartialStateHolder#clearInitialState}, this method is called by
  470        * the runtime to tell the instance to stop tracking state
  471        * changes.</p>
  472        * @since 2.0
  473        */
  474       public void clearInitialState() {
  475           initialState = false;
  476       }
  477   
  478   
  479       /**
  480        * <p class="changed_added_2_0">Return the {@link StateHelper}
  481        * instance used to help this component implement {@link
  482        * PartialStateHolder}.</p>
  483        * @since 2.0
  484        */
  485       protected StateHelper getStateHelper() {
  486           return getStateHelper(true);
  487       }
  488   
  489   
  490       /**
  491        * <p class="changed_added_2_0">Like {@link #getStateHelper()}, but
  492        * only create a state helper instance if the argument
  493        * <code>creat</code> is <code>true</code>.</p>
  494        * @param create if <code>true</code>, a new {@link StateHelper}
  495        * instance will be created if it does not exist already.  If
  496        * <code>false</code>, and there is no existing
  497        * <code>StateHelper</code> instance, one will not be created and
  498        * <code>null</code> will be returned.
  499        * @since 2.0
  500        */
  501       protected StateHelper getStateHelper(boolean create) {
  502   
  503           if (create && stateHelper == null) {
  504               stateHelper = new ComponentStateHelper(this);
  505           }
  506           return stateHelper;
  507   
  508       }
  509   
  510   
  511       private boolean isInView;
  512   
  513   
  514       /**
  515        * <p class="changed_added_2_0">Return <code>true</code> if this
  516        * component is within the view hierarchy otherwise
  517        * <code>false</code></code>
  518        *
  519        * @since 2.0
  520        */
  521       public boolean isInView() {
  522           return isInView;
  523       }
  524   
  525   
  526       /**
  527        * <p class="changed_added_2_0">Updates the status as to whether or
  528        * not this component is currently within the view hierarchy.
  529        * <strong>This method must never be called by developers; a {@link
  530        * UIComponent}'s internal implementation will call it as components
  531        * are added to or removed from a parent's child <code>List</code>
  532        * or facet <code>Map</code></strong>.</p>
  533        *
  534        * @param isInView flag indicating whether or not this component is within
  535        *  the view hierachy
  536        *
  537        * @since 2.0
  538        */
  539       public void setInView(boolean isInView) {
  540           this.isInView = isInView;
  541       }
  542   
  543   
  544       /**
  545        * <p class="changed_added_2_0">Enable EL to access the <code>clientId</code>
  546        * of a component.  This is particularly useful in combination with the 
  547        * <code>component</code> and <code>cc</code> implicit
  548        * objects.  A default implementation is provided that simply calls
  549        * {@link FacesContext#getCurrentInstance} and then calls through to
  550        * {@link #getClientId(FacesContext)}.</p>
  551        * 
  552        * @since 2.0
  553        */
  554       
  555       public String getClientId() {
  556           FacesContext context = FacesContext.getCurrentInstance();
  557           return getClientId(context);
  558       }
  559   
  560   
  561       /**
  562        * <p>Return a client-side identifier for this component, generating
  563        * one if necessary.  The associated {@link Renderer}, if any,
  564        * will be asked to convert the clientId to a form suitable for
  565        * transmission to the client.</p>
  566        *
  567        * <p>The return from this method must be the same value throughout
  568        * the lifetime of the instance, unless the <code>id</code> property
  569        * of the component is changed, or the component is placed in
  570        * a {@link NamingContainer} whose client ID changes (for example,
  571        * {@link UIData}).  However, even in these cases, consecutive
  572        * calls to this method must always return the same value.  The
  573        * implementation must follow these steps in determining the
  574        * clientId:</p>
  575        *
  576        * <p>Find the closest ancestor to <b>this</b> component in the view
  577        * hierarchy that implements <code>NamingContainer</code>.  Call
  578        * <code>getContainerClientId()</code> on it and save the result as
  579        * the <code>parentId</code> local variable.  Call {@link #getId} on
  580        * <b>this</b> component and save the result as the
  581        * <code>myId</code> local variable.  If <code>myId</code> is
  582        * <code>null</code>, call
  583        * <code>context.getViewRoot().createUniqueId()</code> and assign
  584        * the result to myId.  If <code>parentId</code> is
  585        * non-<code>null</code>, let <code>myId</code> equal <code>parentId
  586        * + {@link UINamingContainer#getSeparatorChar} + myId</code>.  Call
  587        * {@link Renderer#convertClientId}, passing <code>myId</code>, and
  588        * return the result.</p>
  589        *
  590        * @param context The {@link FacesContext} for the current request
  591        *
  592        * @throws NullPointerException if <code>context</code>
  593        *  is <code>null</code>
  594        */
  595       public abstract String getClientId(FacesContext context);
  596   
  597       /**
  598        * <p>Allow components that implement {@link NamingContainer} to
  599        * selectively disable prepending their clientId to their
  600        * descendent's clientIds by breaking the prepending logic into a
  601        * seperately callable method.  See {@link #getClientId} for usage.</p>
  602        *
  603        * <p>By default, this method will call through to {@link
  604        * #getClientId} and return the result.
  605        *
  606        * @since 1.2
  607        *
  608        *  @throws NullPointerException if <code>context</code> is
  609        *  <code>null</code>
  610        */
  611       public String getContainerClientId(FacesContext context) {
  612           if (context == null) {
  613               throw new NullPointerException();
  614           }
  615           return this.getClientId(context);
  616       }
  617   
  618       /**
  619        * <p>Return the identifier of the component family to which this
  620        * component belongs.  This identifier, in conjunction with the value
  621        * of the <code>rendererType</code> property, may be used to select
  622        * the appropriate {@link Renderer} for this component instance.</p>
  623        */
  624       public abstract String getFamily();
  625   
  626   
  627       /**
  628        * <p>Return the component identifier of this {@link UIComponent}.</p>
  629        */
  630       public abstract String getId();
  631   
  632   
  633       /**
  634        * <p>Set the component identifier of this {@link UIComponent} (if any).
  635        * Component identifiers must obey the following syntax restrictions:</p>
  636        * <ul>
  637        * <li>Must not be a zero-length String.</li>
  638        * <li>First character must be a letter or an underscore ('_').</li>
  639        * <li>Subsequent characters must be a letter, a digit,
  640        *     an underscore ('_'), or a dash ('-').</li>
  641        * <li>
  642        * </ul>
  643        *
  644        * <p>Component identifiers must also obey the following semantic
  645        * restrictions (note that this restriction is <strong>NOT</strong>
  646        * enforced by the <code>setId()</code> implementation):</p>
  647        * <ul>
  648        * <li>The specified identifier must be unique among all the components
  649        *     (including facets) that are descendents of the nearest ancestor
  650        *     {@link UIComponent} that is a {@link NamingContainer}, or within
  651        *     the scope of the entire component tree if there is no such
  652        *     ancestor that is a {@link NamingContainer}.</li>
  653        * </ul>
  654        *
  655        * @param id The new component identifier, or <code>null</code> to indicate
  656        *  that this {@link UIComponent} does not have a component identifier
  657        *
  658        * @throws IllegalArgumentException if <code>id</code> is not
  659        *  syntactically valid
  660        */
  661       public abstract void setId(String id);
  662   
  663   
  664       /**
  665        * <p>Return the parent {@link UIComponent} of this
  666        * <code>UIComponent</code>, if any.  A component must allow child
  667        * components to be added to and removed from the list of children
  668        * of this component, even though the child component returns null
  669        * from <code>getParent( )</code>.</p>
  670        */
  671       public abstract UIComponent getParent();
  672   
  673   
  674       /**
  675        * <p class="changed_modified_2_0">Set the parent
  676        * <code>UIComponent</code> of this <code>UIComponent</code>.  <span
  677        * class="changed_added_2_0">This method will cause an {@link
  678        * javax.faces.event.PostAddToViewEvent} to be published and if
  679        * <code>parent.isInView()</code> returns <code>true</code> an
  680        * {@link javax.faces.event.PostAddToViewEvent} will be published as
  681        * well.  <strong>This method must never be called by developers; a
  682        * {@link UIComponent}'s internal implementation will call it as
  683        * components are added to or removed from a parent's child
  684        * <code>List</code> or facet <code>Map</code></strong></span>.</p>
  685        *
  686        * @param parent The new parent, or <code>null</code> for the root node
  687        *  of a component tree
  688        */
  689       public abstract void setParent(UIComponent parent);
  690   
  691   
  692       /**
  693        * <p>Return <code>true</code> if this component (and its children)
  694        * should be rendered during the <em>Render Response</em> phase
  695        * of the request processing lifecycle.</p>
  696        */
  697       public abstract boolean isRendered();
  698   
  699   
  700       /**
  701        * <p>Set the <code>rendered</code> property of this
  702        * {@link UIComponent}.</p>
  703        *
  704        * @param rendered If <code>true</code> render this component;
  705        *  otherwise, do not render this component
  706        */
  707       public abstract void setRendered(boolean rendered);
  708   
  709   
  710       /**
  711        * <p>Return the {@link Renderer} type for this {@link UIComponent}
  712        * (if any).</p>
  713        */
  714       public abstract String getRendererType();
  715   
  716   
  717       /**
  718        * <p>Set the {@link Renderer} type for this {@link UIComponent},
  719        * or <code>null</code> for components that render themselves.</p>
  720        *
  721        * @param rendererType Logical identifier of the type of
  722        *  {@link Renderer} to use, or <code>null</code> for components
  723        *  that render themselves
  724        */
  725       public abstract void setRendererType(String rendererType);
  726   
  727   
  728       /**
  729        * <p>Return a flag indicating whether this component is responsible
  730        * for rendering its child components.  The default implementation
  731        * in {@link UIComponentBase#getRendersChildren} tries to find the
  732        * renderer for this component.  If it does, it calls {@link
  733        * Renderer#getRendersChildren} and returns the result.  If it
  734        * doesn't, it returns false.  As of version 1.2 of the JavaServer
  735        * Faces Specification, component authors are encouraged to return
  736        * <code>true</code> from this method and rely on {@link
  737        * UIComponentBase#encodeChildren}.</p>
  738        */
  739       public abstract boolean getRendersChildren();
  740       
  741   
  742       
  743       private Map<String, String> resourceBundleMap = null;
  744       
  745       /**
  746        * <p class="changed_added_2_0">Return a
  747        * <code>Map&lt;String,String&gt;</code> of the
  748        * <code>ResourceBundle</code> for this component.  A component may
  749        * have a <code>ResourceBundle</code> associated with it.  This
  750        * bundle may contain localized properties relating to instances of
  751        * this component.  The default implementation first looks for a
  752        * <code>ResourceBundle</code> with a base name equal to the fully
  753        * qualified class name of the current <code>UIComponent this</code>
  754        * and <code>Locale</code> equal to the <code>Locale</code> of the
  755        * current <code>UIViewRoot</code>.  If no such bundle is found, and
  756        * the component is a composite component, let <em>resourceName</em>
  757        * be the <em>resourceName</em> of the {@link Resource} for this
  758        * composite component, replacing the file extension with
  759        * ".properties".  Let <em>libraryName</em> be the
  760        * <em>libraryName</em> of the the {@link Resource} for this
  761        * composite component.  Call {@link
  762        * javax.faces.application.ResourceHandler#createResource(java.lang.String,java.lang.String)},
  763        * passing the derived <em>resourceName</em> and
  764        * <em>libraryName</em>.  Note that this will automatically allow
  765        * for the localization of the <code>ResourceBundle</code> due to
  766        * the localization facility implemented in
  767        * <code>createResource</code>, which is specified in section
  768        * JSF.2.6.1.3 of the spec prose document.  If the resultant {@link
  769        * Resource} exists and can be found, the <code>InputStream</code>
  770        * for the resource is used to create a <code>ResourceBundle</code>.
  771        * If either of the two previous steps for obtaining the
  772        * <code>ResourceBundle</code> for this component is successful, the
  773        * <code>ResourceBundle</code> is wrapped in a
  774        * <code>Map&lt;String,String&gt;</code> and returned.  Otherwise
  775        * <code>Collections.EMPTY_MAP</code> is returned.</p>
  776        *
  777        * @since 2.0
  778        */
  779       public Map<String,String> getResourceBundleMap() {
  780           
  781           if (null == resourceBundleMap) {
  782               // See if there is a ResourceBundle under the FQCN for this class
  783               String className = this.getClass().getName();
  784               Locale currentLocale = null;
  785               FacesContext context = null;
  786               UIViewRoot root = null;
  787               ResourceBundle resourceBundle = null;
  788               
  789               // Step 1: look for a ResourceBundle under the FQCN of this instance
  790               if (null != (context = FacesContext.getCurrentInstance())) {
  791                   if (null != (root = context.getViewRoot())) {
  792                       currentLocale = root.getLocale();
  793                   }
  794               }
  795               if (null == currentLocale) {
  796                   currentLocale = Locale.getDefault();
  797               }
  798               try {
  799                   resourceBundle = 
  800                           ResourceBundle.getBundle(className, currentLocale);
  801               } catch (MissingResourceException e) {
  802                   // It is not an error if there is no ResourceBundle
  803               }
  804               
  805               // Step 2: if this is a composite component, look for a 
  806               // ResourceBundle as a Resource
  807               if (null == resourceBundle) {
  808                   if (this.getAttributes().containsKey(Resource.COMPONENT_RESOURCE_KEY)) {
  809                       Resource ccResource = (Resource)
  810                               this.getAttributes().get(Resource.COMPONENT_RESOURCE_KEY);
  811                       if (null != ccResource) {
  812                           if (null != (ccResource = 
  813                                   findComponentResourceBundleLocaleMatch(context, 
  814                                   ccResource.getResourceName(), 
  815                                   ccResource.getLibraryName()))) {
  816                               try {
  817                                   InputStream propertiesInputStream = ccResource.getInputStream();
  818                                   resourceBundle = new PropertyResourceBundle(propertiesInputStream);
  819                               } catch (IOException ex) {
  820                                   Logger.getLogger(UIComponent.class.getName()).log(Level.SEVERE, null, ex);
  821                               }
  822                           }
  823                       }
  824                   }
  825               }
  826               
  827               // Step 3: if the previous steps yielded a ResourceBundle, wrap it
  828               // with a Map
  829               
  830               if (null != resourceBundle) {
  831                   final ResourceBundle bundle = resourceBundle;
  832                   resourceBundleMap = 
  833                           new Map() {
  834                               // this is an immutable Map
  835   
  836                               public String toString() {
  837                                   StringBuffer sb = new StringBuffer();
  838                                   Iterator<Map.Entry<String, Object>> entries =
  839                                           this.entrySet().iterator();
  840                                   Map.Entry<String, Object> cur;
  841                                   while (entries.hasNext()) {
  842                                       cur = entries.next();
  843                                       sb.append(cur.getKey()).append(": ").append(cur.getValue()).append('\n');
  844                                   }
  845   
  846                                   return sb.toString();
  847                               }
  848   
  849                               // Do not need to implement for immutable Map
  850                               public void clear() {
  851                                   throw new UnsupportedOperationException();
  852                               }
  853   
  854   
  855                               public boolean containsKey(Object key) {
  856                                   boolean result = false;
  857                                   if (null != key) {
  858                                       result = (null != bundle.getObject(key.toString()));
  859                                   }
  860                                   return result;
  861                               }
  862   
  863   
  864                               public boolean containsValue(Object value) {
  865                                   Enumeration<String> keys = bundle.getKeys();
  866                                   boolean result = false;
  867                                   while (keys.hasMoreElements()) {
  868                                       Object curObj = bundle.getObject(keys.nextElement());
  869                                       if ((curObj == value) ||
  870                                               ((null != curObj) && curObj.equals(value))) {
  871                                           result = true;
  872                                           break;
  873                                       }
  874                                   }
  875                                   return result;
  876                               }
  877   
  878   
  879                               public Set<Map.Entry<String, Object>> entrySet() {
  880                                   HashMap<String, Object> mappings = new HashMap<String, Object>();
  881                                   Enumeration<String> keys = bundle.getKeys();
  882                                   while (keys.hasMoreElements()) {
  883                                       String key = keys.nextElement();
  884                                       Object value = bundle.getObject(key);
  885                                       mappings.put(key, value);
  886                                   }
  887                                   return mappings.entrySet();
  888                               }
  889   
  890   
  891                               @Override
  892                               public boolean equals(Object obj) {
  893                                   return !((obj == null) || !(obj instanceof Map))
  894                                            && entrySet().equals(((Map) obj).entrySet());
  895   
  896                               }
  897   
  898   
  899                               public Object get(Object key) {
  900                                   if (null == key) {
  901                                       return null;
  902                                   }
  903                                   try {
  904                                       return bundle.getObject(key.toString());
  905                                   } catch (MissingResourceException e) {
  906                                       return "???" + key + "???";
  907                                   }
  908                               }
  909   
  910   
  911                               public int hashCode() {
  912                                   return bundle.hashCode();
  913                               }
  914   
  915   
  916                               public boolean isEmpty() {
  917                                   Enumeration<String> keys = bundle.getKeys();
  918                                   return !keys.hasMoreElements();
  919                               }
  920   
  921   
  922                               public Set keySet() {
  923                                   Set<String> keySet = new HashSet<String>();
  924                                   Enumeration<String> keys = bundle.getKeys();
  925                                   while (keys.hasMoreElements()) {
  926                                       keySet.add(keys.nextElement());
  927                                   }
  928                                   return keySet;
  929                               }
  930   
  931   
  932                               // Do not need to implement for immutable Map
  933                               public Object put(Object k, Object v) {
  934                                   throw new UnsupportedOperationException();
  935                               }
  936   
  937   
  938                               // Do not need to implement for immutable Map
  939                               public void putAll(Map t) {
  940                                   throw new UnsupportedOperationException();
  941                               }
  942   
  943   
  944                               // Do not need to implement for immutable Map
  945                               public Object remove(Object k) {
  946                                   throw new UnsupportedOperationException();
  947                               }
  948   
  949   
  950                               public int size() {
  951                                   int result = 0;
  952                                   Enumeration<String> keys = bundle.getKeys();
  953                                   while (keys.hasMoreElements()) {
  954                                       keys.nextElement();
  955                                       result++;
  956                                   }
  957                                   return result;
  958                               }
  959   
  960   
  961                               public java.util.Collection values() {
  962                                   ArrayList<Object> result = new ArrayList<Object>();
  963                                   Enumeration<String> keys = bundle.getKeys();
  964                                   while (keys.hasMoreElements()) {
  965                                       result.add(
  966                                               bundle.getObject(keys.nextElement()));
  967                                   }
  968                                   return result;
  969                               }
  970                           };
  971   
  972               }
  973   
  974               if (null == resourceBundleMap) {
  975                   resourceBundleMap = Collections.EMPTY_MAP;
  976               }
  977   
  978           }
  979           
  980           return resourceBundleMap;
  981       }
  982   
  983       // PENDING(rlubke): I'm sure there's a more efficient
  984       // way to handle this.
  985       private Resource findComponentResourceBundleLocaleMatch(FacesContext context, 
  986               String resourceName, String libraryName) {
  987           Resource result = null;
  988           ResourceBundle resourceBundle = null;
  989           int i;
  990           if (-1 != (i = resourceName.lastIndexOf("."))) {
  991               resourceName = resourceName.substring(0, i) +
  992                       ".properties";
  993               if (null != context) {
  994                   result = context.getApplication().getResourceHandler().
  995                           createResource(resourceName, libraryName);
  996                   try {
  997                       InputStream propertiesInputStream = result.getInputStream();
  998                       resourceBundle = new PropertyResourceBundle(propertiesInputStream);
  999                   } catch (IOException ex) {
 1000                       Logger.getLogger(UIComponent.class.getName()).log(Level.SEVERE, null, ex);
 1001                   }
 1002               }
 1003           }
 1004           result = (null != resourceBundle) ? result : null;
 1005           
 1006           return result;
 1007       }
 1008       
 1009       
 1010       // This is necessary for JSF components that extend from UIComponent
 1011       // directly rather than extending from UIComponentBase.  Such components
 1012       // may need to have implementations provided for methods that originated
 1013       // from a spec version more recent than the version with which the component
 1014       // complies.  Currently this private property is only consulted in the
 1015       // getValueExpression() method.
 1016       private boolean isUIComponentBase;
 1017       private boolean isUIComponentBaseIsSet = false;
 1018   
 1019       private boolean isUIComponentBase() {
 1020           if (!isUIComponentBaseIsSet) {
 1021               isUIComponentBase = (this instanceof UIComponentBase);
 1022           }
 1023   
 1024           return isUIComponentBase;
 1025       }
 1026   
 1027   
 1028       // ------------------------------------------------- Tree Management Methods
 1029   
 1030   
 1031       /**
 1032        * <p><span class="changed_modified_2_0">Return</span> a mutable
 1033        * <code>List</code> representing the child {@link UIComponent}s
 1034        * associated with this component.  The returned implementation must
 1035        * support all of the standard and optional <code>List</code>
 1036        * methods, plus support the following additional requirements:</p>
 1037        * <ul> <li>The <code>List</code> implementation must implement the
 1038        * <code>java.io.Serializable</code> interface.</li> <li>Any attempt
 1039        * to add a <code>null</code> must throw a NullPointerException</li>
 1040        * <li>Any attempt to add an object that does not implement {@link
 1041        * UIComponent} must throw a ClassCastException.</li> <li>Whenever a
 1042        * new child component is added, the <code>parent</code> property of
 1043        * the child must be set to this component instance.  If the
 1044        * <code>parent</code> property of the child was already non-null,
 1045        * the child must first be removed from its previous parent (where
 1046        * it may have been either a child or a facet).</li> <li>Whenever an
 1047        * existing child component is removed, the <code>parent</code>
 1048        * property of the child must be set to <code>null</code>.</li>
 1049   
 1050        * <li class="changed_added_2_0"><p>After the child component has
 1051        *     been added to the view, if the following condition is
 1052        *     <strong>not</strong> met:</p>
 1053        *
 1054        *     <ul><p>{@link javax.faces.context.FacesContext#isPostback}
 1055        *     returns <code>true</code> and {@link
 1056        *     javax.faces.context.FacesContext#getCurrentPhaseId} returns {@link
 1057        *     javax.faces.event.PhaseId#RESTORE_VIEW}</p></ul>
 1058   
 1059        *     <p>{@link javax.faces.application.Application#publishEvent}
 1060        *     must be called, passing {@link
 1061        *     javax.faces.event.PostAddToViewEvent}<code>.class</code>
 1062        *     as the first argument and the newly added component as the
 1063        *     second argument.</p>
 1064   
 1065        * </li>
 1066   
 1067        * </ul>
 1068        */
 1069       public abstract List<UIComponent> getChildren();
 1070   
 1071   
 1072       /**
 1073        * <p>Return the number of child {@link UIComponent}s that are
 1074        * associated with this {@link UIComponent}.  If there are no
 1075        * children, this method must return 0.  The method must not cause
 1076        * the creation of a child component list.</p>
 1077        */
 1078       public abstract int getChildCount();
 1079   
 1080   
 1081       /**
 1082        * <p>Search for and return the {@link UIComponent} with an <code>id</code>
 1083        * that matches the specified search expression (if any), according to the
 1084        * algorithm described below.</p>
 1085        *
 1086        * <p>For a method to find a component given a simple
 1087        * <code>clientId</code>, see {@link #invokeOnComponent}.</p>
 1088        *
 1089        * <p>Component identifiers are required to be unique within the scope of
 1090        * the closest ancestor {@link NamingContainer} that encloses this
 1091        * component (which might be this component itself).  If there are no
 1092        * {@link NamingContainer} components in the ancestry of this component,
 1093        * the root component in the tree is treated as if it were a
 1094        * {@link NamingContainer}, whether or not its class actually implements
 1095        * the {@link NamingContainer} interface.</p>
 1096        *
 1097        * <p>A <em>search expression</em> consists of either an identifier
 1098        * (which is matched exactly against the <code>id</code> property of
 1099        * a {@link UIComponent}, or a series of such identifiers linked by
 1100        * the {@link UINamingContainer#getSeparatorChar} character value.
 1101        * The search algorithm should operates as follows, though alternate
 1102        * alogrithms may be used as long as the end result is the same:</p>
 1103   
 1104        * <ul>
 1105        * <li>Identify the {@link UIComponent} that will be the base for searching,
 1106        *     by stopping as soon as one of the following conditions is met:
 1107        *     <ul>
 1108        *     <li>If the search expression begins with the the separator character
 1109        *         (called an "absolute" search expression),
 1110        *         the base will be the root {@link UIComponent} of the component
 1111        *         tree.  The leading separator character will be stripped off,
 1112        *         and the remainder of the search expression will be treated as
 1113        *         a "relative" search expression as described below.</li>
 1114        *     <li>Otherwise, if this {@link UIComponent} is a
 1115        *         {@link NamingContainer} it will serve as the basis.</li>
 1116        *     <li>Otherwise, search up the parents of this component.  If
 1117        *         a {@link NamingContainer} is encountered, it will be the base.
 1118        *         </li>
 1119        *     <li>Otherwise (if no {@link NamingContainer} is encountered)
 1120        *         the root {@link UIComponent} will be the base.</li>
 1121        *     </ul></li>
 1122        * <li>The search expression (possibly modified in the previous step) is now
 1123        *     a "relative" search expression that will be used to locate the
 1124        *     component (if any) that has an <code>id</code> that matches, within
 1125        *     the scope of the base component.  The match is performed as follows:
 1126        *     <ul>
 1127        *     <li>If the search expression is a simple identifier, this value is
 1128        *         compared to the <code>id</code> property, and then recursively
 1129        *         through the facets and children of the base {@link UIComponent}
 1130        *         (except that if a descendant {@link NamingContainer} is found,
 1131        *         its own facets and children are not searched).</li>
 1132        *     <li>If the search expression includes more than one identifier
 1133        *         separated by the separator character, the first identifier is
 1134        *         used to locate a {@link NamingContainer} by the rules in the
 1135        *         previous bullet point.  Then, the <code>findComponent()</code>
 1136        *         method of this {@link NamingContainer} will be called, passing
 1137        *         the remainder of the search expression.</li>
 1138        *     </ul></li>
 1139        * </ul>
 1140        *
 1141        * @param expr Search expression identifying the {@link UIComponent}
 1142        *  to be returned
 1143        *
 1144        * @return the found {@link UIComponent}, or <code>null</code>
 1145        *  if the component was not found.
 1146        *
 1147        * @throws IllegalArgumentException if an intermediate identifier
 1148        *  in a search expression identifies a {@link UIComponent} that is
 1149        *  not a {@link NamingContainer}
 1150        * @throws NullPointerException if <code>expr</code>
 1151        *  is <code>null</code>
 1152        */
 1153       public abstract UIComponent findComponent(String expr);
 1154   
 1155       /**
 1156        * <p>Starting at this component in the View hierarchy, search for a
 1157        * component with a <code>clientId</code> equal to the argument
 1158        * <code>clientId</code> and, if found, call the {@link
 1159        * ContextCallback#invokeContextCallback} method on the argument
 1160        * <code>callback</code>, passing the current {@link FacesContext}
 1161        * and the found component as arguments. This method is similar to
 1162        * {@link #findComponent} but it does not support the leading {@link
 1163        * UINamingContainer#getSeparatorChar} syntax for searching from the
 1164        * root of the View.</p>
 1165        *
 1166        * <p>The default implementation will first check if
 1167        * <code>this.getClientId()</code> is equal to the argument
 1168        * <code>clientId</code>.  If so, call the {@link
 1169        * ContextCallback#invokeContextCallback} method on the argument callback,
 1170        * passing through the <code>FacesContext</code> argument and
 1171        * passing this as the component argument.  If an
 1172        * <code>Exception</code> is thrown by the callback, wrap it in a
 1173        * {@link FacesException} and re-throw it.  Otherwise, return
 1174        * <code>true</code>.</p>
 1175        *
 1176        * <p>Otherwise, for each component returned by {@link
 1177        * #getFacetsAndChildren}, call <code>invokeOnComponent()</code>
 1178        * passing the arguments to this method, in order.  The first time
 1179        * <code>invokeOnComponent()</code> returns true, abort traversing
 1180        * the rest of the <code>Iterator</code> and return
 1181        * <code>true</code>.</p>
 1182        *
 1183        * <p>When calling {@link ContextCallback#invokeContextCallback}
 1184        * the implementation of this method must guarantee that the state
 1185        * of the component passed to the callback correctly reflects the
 1186        * component's position in the View hierarchy with respect to any
 1187        * state found in the argument <code>clientId</code>.  For example,
 1188        * an iterating component such as {@link UIData} will need to set
 1189        * its row index to correctly reflect the argument
 1190        * <code>clientId</code> before finding the appropriate child
 1191        * component backed by the correct row.  When the callback returns,
 1192        * either normally or by throwing an <code>Exception</code> the
 1193        * implementation of this method must restore the state of the view
 1194        * to the way it was before invoking the callback.</p>
 1195        *
 1196        * <p>If none of the elements from {@link
 1197        * #getFacetsAndChildren} returned <code>true</code> from
 1198        * <code>invokeOnComponent()</code>, return <code>false</code>.</p>
 1199        *
 1200        * <p>Simple usage example to find a component by
 1201        * <code>clientId</code>.</p>
 1202   
 1203   * <pre><code>
 1204   private UIComponent found = null;
 1205   
 1206   private void doFind(FacesContext context, String clientId) {
 1207     context.getViewRoot().invokeOnComponent(context, clientId,
 1208         new ContextCallback() {
 1209            public void invokeContextCallback(FacesContext context,
 1210                                          UIComponent component) {
 1211              found = component;
 1212            }
 1213         });
 1214   }
 1215   * </code></pre>
 1216   
 1217        *
 1218        *
 1219        * @since 1.2
 1220        *
 1221        * @param context the {@link FacesContext} for the current request
 1222        *
 1223        * @param clientId the client identifier of the component to be passed
 1224        * to the argument callback.
 1225        *
 1226        * @param callback an implementation of the Callback interface.
 1227        *
 1228        * @throws NullPointerException if any of the arguments are null
 1229        *
 1230        * @throws FacesException if the argument Callback throws an
 1231        * Exception, it is wrapped in a <code>FacesException</code> and re-thrown.
 1232        *
 1233        * @return <code>true</code> if the a component with the given
 1234        * <code>clientId</code> is found, the callback method was
 1235        * successfully invoked passing that component as an argument, and
 1236        * no Exception was thrown.  Returns <code>false</code> if no
 1237        * component with the given <code>clientId</code> is found.
 1238        *
 1239        */
 1240   
 1241       public boolean invokeOnComponent(FacesContext context, String clientId,
 1242               ContextCallback callback) throws FacesException {
 1243           if (null == context || null == clientId || null == callback) {
 1244               throw new NullPointerException();
 1245           }
 1246   
 1247           boolean found = false;
 1248           if (clientId.equals(this.getClientId(context))) {
 1249               try {
 1250                   callback.invokeContextCallback(context, this);
 1251                   return true;
 1252               } catch (Exception e) {
 1253                   throw new FacesException(e);
 1254               }
 1255           } else {
 1256               Iterator<UIComponent> itr = this.getFacetsAndChildren();
 1257   
 1258               while (itr.hasNext() && !found) {
 1259                   found = itr.next().invokeOnComponent(context, clientId,
 1260                           callback);
 1261               }
 1262           }
 1263           return found;
 1264       }
 1265   
 1266       // ------------------------------------------------ Facet Management Methods
 1267   
 1268   
 1269       /**
 1270        * <p>Return a mutable <code>Map</code> representing the facet
 1271        * {@link UIComponent}s associated with this {@link UIComponent},
 1272        * keyed by facet name (which must be a String).  The returned
 1273        * implementation must support all of the standard and optional
 1274        * <code>Map</code> methods, plus support the following additional
 1275        * requirements:</p>
 1276   
 1277        * <ul>
 1278        * <li>The <code>Map</code> implementation must implement
 1279        *     the <code>java.io.Serializable</code> interface.</li>
 1280        * <li>Any attempt to add a <code>null</code> key or value must
 1281        *     throw a NullPointerException.</li>
 1282        * <li>Any attempt to add a key that is not a String must throw
 1283        *     a ClassCastException.</li>
 1284        * <li>Any attempt to add a value that is not a {@link UIComponent}
 1285        *     must throw a ClassCastException.</li>
 1286        * <li>Whenever a new facet {@link UIComponent} is added:
 1287        *     <ul>
 1288        *     <li>The <code>parent</code> property of the component must be set to
 1289        *         this component instance.</li>
 1290        *     <li>If the <code>parent</code> property of the component was already
 1291        *     non-null, the component must first be removed from its previous
 1292        *     parent (where it may have been either a child or a facet).</li>
 1293        *     </ul></li>
 1294   
 1295        * <li>Whenever an existing facet {@link UIComponent} is removed:
 1296        *     <ul>
 1297        *     <li>The <code>parent</code> property of the facet must be
 1298        *         set to <code>null</code>.</li>
 1299        *     </ul></li>
 1300        * </ul>
 1301        */
 1302       public abstract Map<String, UIComponent> getFacets();
 1303   
 1304       /**
 1305        * <p>Return the number of facet {@link UIComponent}s that are
 1306        * associated with this {@link UIComponent}.  If there are no
 1307        * facets, this method must return 0.  The method must not cause
 1308        * the creation of a facet component map.</p>
 1309        *
 1310        * <p>For backwards compatability with classes that extend UIComponent
 1311        * directly, a default implementation is provided that simply calls
 1312        * {@link #getFacets} and then calls the <code>size()</code> method on the
 1313        * returned <code>Map</code>.  A more optimized version of this method is
 1314        * provided in {@link UIComponentBase#getFacetCount}.
 1315        *
 1316        * @since 1.2
 1317        */
 1318       public int getFacetCount() {
 1319           return (getFacets().size());
 1320       }
 1321   
 1322   
 1323   
 1324       /**
 1325        * <p>Convenience method to return the named facet, if it exists, or
 1326        * <code>null</code> otherwise.  If the requested facet does not
 1327        * exist, the facets Map must not be created.</p>
 1328        *
 1329        * @param name Name of the desired facet
 1330        */
 1331       public abstract UIComponent getFacet(String name);
 1332   
 1333   
 1334       /**
 1335        * <p>Return an <code>Iterator</code> over the facet followed by child
 1336        * {@link UIComponent}s of this {@link UIComponent}.
 1337        * Facets are returned in an undefined order, followed by
 1338        * all the children in the order they are stored in the child list. If this
 1339        * component has no facets or children, an empty <code>Iterator</code>
 1340        * is returned.</p>
 1341        *
 1342        * <p>The returned <code>Iterator</code> must not support the
 1343        * <code>remove()</code> operation.</p>
 1344        */
 1345       public abstract Iterator<UIComponent> getFacetsAndChildren();
 1346   
 1347   
 1348       // -------------------------------------------- Lifecycle Processing Methods
 1349   
 1350   
 1351       /**
 1352        * <p>Broadcast the specified {@link FacesEvent} to all registered
 1353        * event listeners who have expressed an interest in events of this
 1354        * type.  Listeners are called in the order in which they were
 1355        * added.</p>  
 1356        * <p class="changed_added_2_0">If the <code>event</code> is an instance of 
 1357        * {@link javax.faces.event.BehaviorEvent} and the current 
 1358        * <code>component</code> is the source of the <code>event</code>
 1359        * call {@link javax.faces.event.BehaviorEvent#getBehavior} to get the
 1360        * {@link javax.faces.component.behavior.Behavior} for the event.  If the
 1361        * behavior implements {@link javax.faces.component.behavior.ClientBehavior},
 1362        * call {@link javax.faces.component.behavior.ClientBehavior#broadcast(javax.faces.event.BehaviorEvent)}}.</p>
 1363        *
 1364        * @param event The {@link FacesEvent} to be broadcast
 1365        *
 1366        * @throws AbortProcessingException Signal the JavaServer Faces
 1367        *  implementation that no further processing on the current event
 1368        *  should be performed
 1369        * @throws IllegalArgumentException if the implementation class
 1370        *  of this {@link FacesEvent} is not supported by this component
 1371        * @throws NullPointerException if <code>event</code> is
 1372        * <code>null</code>
 1373        */
 1374       public abstract void broadcast(FacesEvent event)
 1375           throws AbortProcessingException;
 1376   
 1377   
 1378       /**
 1379        * <p>Decode any new state of this {@link UIComponent} from the
 1380        * request contained in the specified {@link FacesContext}, and store
 1381        * this state as needed.</p>
 1382        * <p>During decoding, events may be enqueued for later processing
 1383        * (by event listeners who have registered an interest),  by calling
 1384        * <code>queueEvent()</code>.</p>
 1385        *
 1386        * @param context {@link FacesContext} for the request we are processing
 1387        *
 1388        * @throws NullPointerException if <code>context</code>
 1389        *  is <code>null</code>
 1390        */
 1391       public abstract void decode(FacesContext context);
 1392       
 1393       /**
 1394        * <p class="changed_added_2_0">Perform a tree visit starting at
 1395        * this node in the tree.</p>
 1396        *
 1397        * <div class="changed_added_2_0">
 1398        *
 1399        * <p>UIComponent.visitTree() implementations do not invoke the
 1400        * {@link VisitCallback} directly, but instead call {@link
 1401        * VisitContext#invokeVisitCallback} to invoke the callback.  This
 1402        * allows {@code VisitContext} implementations to provide optimized
 1403        * tree traversals, for example by only calling the {@code
 1404        * VisitCallback} for a subset of components.</p>
 1405        *
 1406        * <p>UIComponent.visitTree() implementations must call
 1407        * UIComponent.pushComponentToEL() before performing the
 1408        * visit and UIComponent.popComponentFromEL() after the
 1409        * visit.</p>
 1410        *
 1411        * @param context the <code>VisitContext</code> for this visit
 1412        * @param callback the <code>VisitCallback</code> instance
 1413        * whose <code>visit</code> method will be called
 1414        * for each node visited.
 1415        * @return component implementations may return <code>true</code> 
 1416        *   to indicate that the tree visit is complete (eg. all components
 1417        *   that need to be visited have been visited).  This results in
 1418        *   the tree visit being short-circuited such that no more components
 1419        *   are visited.
 1420        *
 1421        * </div>
 1422        *
 1423        * @see VisitContext#invokeVisitCallback VisitContext.invokeVisitCallback()
 1424        *
 1425        * @since 2.0
 1426        */
 1427       public boolean visitTree(VisitContext context, 
 1428                                VisitCallback callback) {
 1429   
 1430           // First check to see whether we are visitable.  If not
 1431           // short-circuit out of this subtree, though allow the
 1432           // visit to proceed through to other subtrees.
 1433           if (!isVisitable(context))
 1434               return false;
 1435   
 1436           // Push ourselves to EL before visiting
 1437           FacesContext facesContext = context.getFacesContext();
 1438           pushComponentToEL(facesContext, null);
 1439   
 1440           try {
 1441               // Visit ourselves.  Note that we delegate to the 
 1442               // VisitContext to actually perform the visit.
 1443               VisitResult result = context.invokeVisitCallback(this, callback);
 1444   
 1445               // If the visit is complete, short-circuit out and end the visit
 1446               if (result == VisitResult.COMPLETE)
 1447                 return true;
 1448   
 1449               // Visit children if necessary
 1450               if (result == VisitResult.ACCEPT) {
 1451                   Iterator<UIComponent> kids = this.getFacetsAndChildren();
 1452   
 1453                   while(kids.hasNext()) {
 1454                       boolean done = kids.next().visitTree(context, callback);
 1455   
 1456                       // If any kid visit returns true, we are done.
 1457                       if (done)
 1458                           return true;
 1459                   }
 1460               }
 1461           }
 1462           finally {
 1463               // Pop ourselves off the EL stack
 1464               popComponentFromEL(facesContext);
 1465           }
 1466   
 1467           // Return false to allow the visit to continue
 1468           return false;
 1469       }
 1470   
 1471       /**
 1472        * <p class="changed_added_2_0">Return <code>true</code> if this
 1473        * component should be visited, <code>false</code> otherwise.
 1474        * Called by {@link UIComponent#visitTree UIComponent.visitTree()}
 1475        * to determine whether this component satisfies the hints returned
 1476        * by {@link javax.faces.component.visit.VisitContext#getHints}.</p>
 1477   
 1478        * <div class="changed_added_2_0">
 1479   
 1480        * <p>If this method returns false, the tree visited is
 1481        * short-circuited such that neither the component nor any of its
 1482        * descendents will be visited></p> 
 1483   
 1484        * <p>Custom {@code visitTree()} implementations may call this
 1485        * method to determine whether the component is visitable before
 1486        * performing any visit-related processing.</p>
 1487        *
 1488        * </div>
 1489        *
 1490        * @since 2.0
 1491        */
 1492       protected boolean isVisitable(VisitContext context) {
 1493   
 1494           // VisitHints currently defines two hints that affect 
 1495           // visitability: VIIST_RENDERED and VISIT_TRANSIENT.
 1496           // Check for both of these and if set, verify that 
 1497           // we comply.
 1498           Set<VisitHint> hints = context.getHints();
 1499   
 1500           if ((hints.contains(VisitHint.SKIP_UNRENDERED) && 
 1501                   !this.isRendered())                    ||
 1502               (hints.contains(VisitHint.SKIP_TRANSIENT)  && 
 1503                   this.isTransient())) {
 1504               return false;
 1505           }
 1506   
 1507           return true;
 1508       }
 1509   
 1510       /**
 1511        * <p><span class="changed_modified_2_0">If</span> our
 1512        * <code>rendered</code> property is <code>true</code>, render the
 1513        * beginning of the current state of this {@link UIComponent} to the
 1514        * response contained in the specified {@link FacesContext}. 
 1515        * Call {@link #pushComponentToEL(javax.faces.context.FacesContext,javax.faces.component.UIComponent)}.
 1516        * Call {@link javax.faces.application.Application#publishEvent}, passing
 1517        * {@link javax.faces.event.PreRenderComponentEvent}<code>.class</code> as the
 1518        * first argument and the component instance to be rendered as the
 1519        * second argument.</p></li>
 1520   
 1521        * <p>If a {@link Renderer} is associated with this {@link
 1522        * UIComponent}, the actual encoding will be delegated to
 1523        * {@link Renderer#encodeBegin(FacesContext, UIComponent)}.
 1524        * </p>
 1525        *
 1526        * <p class="changed_added_2_0">If our <code>rendered</code> property is
 1527        * <code>false</code>, call {@link #pushComponentToEL(javax.faces.context.FacesContext,javax.faces.component.UIComponent)}
 1528        * and return immediately.</p>
 1529        *
 1530        * @param context {@link FacesContext} for the response we are creating
 1531        *
 1532        * @throws IOException if an input/output error occurs while rendering
 1533        * @throws NullPointerException if <code>context</code>
 1534        *  is <code>null</code>
 1535        */
 1536       public abstract void encodeBegin(FacesContext context) throws IOException;
 1537   
 1538   
 1539       /**
 1540        * <p>If our <code>rendered</code> property is <code>true</code>,
 1541        * render the child {@link UIComponent}s of this {@link UIComponent}.
 1542        * This method will only be called
 1543        * if the <code>rendersChildren</code> property is <code>true</code>.</p>
 1544        *
 1545        * <p>If a {@link Renderer} is associated with this {@link UIComponent},
 1546        * the actual encoding will be delegated to
 1547        * {@link Renderer#encodeChildren(FacesContext, UIComponent)}.
 1548        * <span class="changed_modified_2_0">If no {@link Renderer} is associated
 1549        * with this {@link UIComponent}, iterate over each of the children of this
 1550        * component and call 
 1551        * {@link #encodeAll(javax.faces.context.FacesContext)}.</span></p>
 1552        *
 1553        * @param context {@link FacesContext} for the response we are creating
 1554        *
 1555        * @throws IOException if an input/output error occurs while rendering
 1556        * @throws NullPointerException if <code>context</code>
 1557        *  is <code>null</code>
 1558        */
 1559       public abstract void encodeChildren(FacesContext context) throws IOException;
 1560   
 1561   
 1562       /**
 1563        * <p><span class="changed_modified_2_0">If</span> our
 1564        * <code>rendered</code> property is <code>true</code>, render the
 1565        * ending of the current state of this {@link UIComponent}.</p>
 1566        *
 1567        * <p>If a {@link Renderer} is associated with this {@link UIComponent},
 1568        * the actual encoding will be delegated to
 1569        * {@link Renderer#encodeEnd(FacesContext, UIComponent)}.</p>
 1570        *
 1571        * <p class="changed_added_2_0">Call {@link
 1572        * UIComponent#popComponentFromEL}. before returning regardless of the value
 1573        *  of the <code>rendered</code> property.</p>
 1574        *
 1575        * @param context {@link FacesContext} for the response we are creating
 1576        *
 1577        * @throws IOException if an input/output error occurs while rendering
 1578        * @throws NullPointerException if <code>context</code>
 1579        *  is <code>null</code>
 1580        */
 1581       public abstract void encodeEnd(FacesContext context) throws IOException;
 1582   
 1583       /**
 1584        * <p>If this component
 1585        * returns <code>true</code> from {@link #isRendered}, take the
 1586        * following action.</p>
 1587        *
 1588        * <p>Render this component and all its children that return
 1589        * <code>true</code> from <code>isRendered()</code>, regardless of
 1590        * the value of the {@link #getRendersChildren} flag.</p></li>
 1591   
 1592        * @since 1.2
 1593        *
 1594        * @throws IOException if an input/output error occurs while rendering
 1595        * @throws NullPointerException if <code>context</code>
 1596        *  is <code>null</code>
 1597        */
 1598       public void encodeAll(FacesContext context) throws IOException {
 1599   
 1600           if (context == null) {
 1601               throw new NullPointerException();
 1602           }
 1603   
 1604           if (!isRendered()) {
 1605               return;
 1606           }
 1607   
 1608           encodeBegin(context);
 1609           if (getRendersChildren()) {
 1610               encodeChildren(context);
 1611           } else if (this.getChildCount() > 0) {
 1612               for (UIComponent kid : getChildren()) {
 1613                   kid.encodeAll(context);
 1614               }
 1615           }
 1616   
 1617           encodeEnd(context);
 1618   
 1619       }
 1620   
 1621   
 1622       private UIComponent previouslyPushed = null;
 1623       private UIComponent previouslyPushedCompositeComponent = null;
 1624       private boolean pushed;
 1625       private int depth;
 1626   
 1627       /**
 1628        * <p class="changed_added_2_0">Push the current
 1629        * <code>UIComponent</code> <code>this</code> to the {@link FacesContext}
 1630        * attribute map using the key {@link #CURRENT_COMPONENT} saving the previous
 1631        * <code>UIComponent</code> associated with {@link #CURRENT_COMPONENT} for a
 1632        * subsequent call to {@link #popComponentFromEL}.</p>
 1633        *
 1634        * <pclass="changed_added_2_0">This method and <code>popComponentFromEL()</code> form the basis for
 1635        * the contract that enables the EL Expression "<code>#{component}</code>" to
 1636        * resolve to the "current" component that is being processed in the
 1637        * lifecycle.  The requirements for when <code>pushComponentToEL()</code> and
 1638        * <code>popComponentFromEL()</code> must be called are specified as
 1639        * needed in the javadoc for this class.</p>
 1640        *
 1641        * <p class="changed_added_2_0">After
 1642        * <code>pushComponentToEL()</code> returns, a call to {@link
 1643        * #getCurrentComponent} must return <code>this</code>
 1644        * <code>UIComponent</code> instance until
 1645        * <code>popComponentFromEL()</code> is called, after which point
 1646        * the previous <code>UIComponent</code> instance will be returned
 1647        * from <code>getCurrentComponent()</code></p>
 1648        *
 1649        * @param context the {@link FacesContext} for the current request
 1650        * @param component the <code>component</code> to push to the EL.  If
 1651        *  <code>component</code> is <code>null</code> the <code>UIComponent</code>
 1652        *  instance that this call was invoked upon will be pushed to the EL.
 1653        *
 1654        * @throws NullPointerException if <code>context</code> is <code>null</code>
 1655        *
 1656        * @see javax.faces.context.FacesContext#getAttributes()
 1657        *
 1658        * @since 2.0
 1659        */
 1660       public final void pushComponentToEL(FacesContext context, UIComponent component) {
 1661   
 1662           if (context == null) {
 1663               throw new NullPointerException();
 1664           }
 1665   
 1666           if (null == component) {
 1667               component = this;
 1668           }
 1669   
 1670           Map<Object,Object> contextMap = context.getAttributes();
 1671   
 1672           if (contextMap.get(CURRENT_COMPONENT) == component) {
 1673               depth++;
 1674               return;
 1675           }
 1676           if (contextMap.get(CURRENT_COMPOSITE_COMPONENT) == component) {
 1677               depth++;
 1678               return;
 1679           }
 1680   
 1681           pushed = true;
 1682           previouslyPushed = (UIComponent) contextMap.put(CURRENT_COMPONENT, component);
 1683           // If this is a composite component...
 1684           if (UIComponent.isCompositeComponent(component)) {
 1685               // make it so #{cc} resolves to this composite
 1686               // component, preserving the previous value if present
 1687               previouslyPushedCompositeComponent =
 1688                       (UIComponent) contextMap.put(CURRENT_COMPOSITE_COMPONENT, component);
 1689           }
 1690   
 1691       }
 1692   
 1693   
 1694       /**
 1695        * <p class="changed_added_2_0">Pop the current
 1696        * <code>UIComponent</code> from the {@link FacesContext} attributes map
 1697        * so that the previous <code>UIComponent</code>, if any, becomes the current
 1698        * component.</p>
 1699        *
 1700        * @param context the {@link FacesContext} for the current request
 1701        * 
 1702        * @throws NullPointerException if <code>context</code> is <code>null</code>
 1703        *
 1704        * @see javax.faces.context.FacesContext#getAttributes()
 1705        *
 1706        * @since 2.0
 1707        */
 1708       public final void popComponentFromEL(FacesContext context) {
 1709   
 1710           if (context == null) {
 1711               throw new NullPointerException();
 1712           }
 1713   
 1714           if (depth > 0) {
 1715               depth--;
 1716               return;
 1717           }
 1718           
 1719           Map<Object,Object> contextMap = context.getAttributes();
 1720           if (contextMap != null) {
 1721   
 1722               if (!pushed) {
 1723                   return;
 1724               }
 1725               UIComponent c;
 1726               pushed = false;
 1727               if (previouslyPushed != null) {
 1728                   c = (UIComponent) contextMap.put(CURRENT_COMPONENT, previouslyPushed);
 1729               } else {
 1730                   c = (UIComponent) contextMap.remove(CURRENT_COMPONENT);
 1731               }
 1732   
 1733               if (c != null && UIComponent.isCompositeComponent(c)) {
 1734                   if (previouslyPushedCompositeComponent != null) {
 1735                       contextMap.put(CURRENT_COMPOSITE_COMPONENT,
 1736                                      previouslyPushedCompositeComponent);
 1737                   } else {
 1738                       contextMap.remove(CURRENT_COMPOSITE_COMPONENT);
 1739                   }
 1740               }
 1741           }
 1742   
 1743       }
 1744   
 1745   
 1746       /**
 1747        * <p class="changed_added_2_0">Return <code>true</code> if
 1748        * <code>component</code> is a composite component, otherwise
 1749        * <code>false</code>.</p>
 1750        *
 1751        * @param component the {@link UIComponent} to test
 1752        *
 1753        * @throws NullPointerException if <code>component</code> is <code>null</code>
 1754        * @since 2.0
 1755        */
 1756       public static boolean isCompositeComponent(UIComponent component) {
 1757   
 1758           if (component == null) {
 1759               throw new NullPointerException();
 1760           }
 1761           return (component.getAttributes().containsKey(Resource.COMPONENT_RESOURCE_KEY));
 1762   
 1763       }
 1764   
 1765   
 1766       /**
 1767        * <p>
 1768        * Finds the nearest composite component parent of the specified component.
 1769        * </p>
 1770        *
 1771        * @param component the component from which to start the search from
 1772        *
 1773        * @return if <code>component</code> is <code>null</code>, return
 1774        *  <code>null</code>, otherwise search the component's parent hierachy
 1775        *  for the nearest parent composite component.  If no parent composite
 1776        *  component is found, return <code>null</code>
 1777        *
 1778        * @since 2.0
 1779        */
 1780       public static UIComponent getCompositeComponentParent(UIComponent component) {
 1781   
 1782           if (component == null) {
 1783               return null;
 1784           } else {
 1785               if (component.compositeParent != null) {
 1786                   return component.compositeParent;
 1787               }
 1788               UIComponent parent = component.getParent();
 1789               while (parent != null) {
 1790                   if (UIComponent.isCompositeComponent(parent)) {
 1791                       if (component.isInView()) {
 1792                           component.compositeParent = parent;
 1793                       }
 1794                       return parent;
 1795                   }
 1796                   parent = parent.getParent();
 1797               }
 1798               return null;
 1799           }
 1800           
 1801       }
 1802   
 1803   
 1804       /**
 1805        * <p class="changed_added_2_0">Return the <code>UIComponent</code>
 1806        * instance that is currently processing.  This is equivalent to
 1807        * evaluating the EL expression "<code>#{component}</code>" and
 1808        * doing a <code>getValue</code> operation on the resultant
 1809        * <code>ValueExpression</code>.</p>
 1810        *
 1811        * <p class="changed_added_2_0">This method must return
 1812        * <code>null</code> if there is no currently processing
 1813        * <code>UIComponent</code></p>
 1814        *
 1815        * @param context {@link FacesContext} for the request we are processing
 1816        *
 1817        * @throws NullPointerException if <code>context</code>
 1818        *  is <code>null</code>
 1819        *
 1820        * @since 2.0
 1821        */
 1822       public static UIComponent getCurrentComponent(FacesContext context) {
 1823           if (context == null) {
 1824               throw new NullPointerException();
 1825           }
 1826           Map<Object, Object> contextMap = context.getAttributes();
 1827           return (UIComponent) contextMap.get(CURRENT_COMPONENT);
 1828   
 1829       }
 1830   
 1831   
 1832       /**
 1833        * <p class="changed_added_2_0">Return the closest ancestor
 1834        * component, relative to the component returned from {@link
 1835        * #getCurrentComponent}, that is a composite component, or
 1836        * <code>null</code> if no such component exists.</p>
 1837        *
 1838        * @param context {@link FacesContext} for the request we are processing
 1839        * 
 1840        * @throws NullPointerException if <code>context</code>
 1841        *  is <code>null</code>
 1842        *
 1843        * @since 2.0
 1844        */
 1845       public static UIComponent getCurrentCompositeComponent(FacesContext context) {
 1846           if (context == null) {
 1847               throw new NullPointerException();
 1848           }
 1849   
 1850           Map<Object, Object> contextMap = context.getAttributes();
 1851           return (UIComponent) contextMap.get(CURRENT_COMPOSITE_COMPONENT);
 1852   
 1853       }
 1854       
 1855       // -------------------------------------------------- Event Listener Methods
 1856   
 1857   
 1858       /**
 1859        * <p>Add the specified {@link FacesListener} to the set of listeners
 1860        * registered to receive event notifications from this {@link UIComponent}.
 1861        * It is expected that {@link UIComponent} classes acting as event sources
 1862        * will have corresponding typesafe APIs for registering listeners of the
 1863        * required type, and the implementation of those registration methods
 1864        * will delegate to this method.  For example:</p>
 1865        * <pre>
 1866        * public class FooEvent extends FacesEvent { ... }
 1867        *
 1868        * public interface FooListener extends FacesListener {
 1869        *   public void processFoo(FooEvent event);
 1870        * }
 1871        *
 1872        * public class FooComponent extends UIComponentBase {
 1873        *   ...
 1874        *   public void addFooListener(FooListener listener) {
 1875        *     addFacesListener(listener);
 1876        *   }
 1877        *   public void removeFooListener(FooListener listener) {
 1878        *     removeFacesListener(listener);
 1879        *   }
 1880        *   ...
 1881        * }
 1882        * </pre>
 1883        *
 1884        * @param listener The {@link FacesListener} to be registered
 1885        *
 1886        * @throws NullPointerException if <code>listener</code>
 1887        *  is <code>null</code>
 1888        */
 1889       protected abstract void addFacesListener(FacesListener listener);
 1890   
 1891   
 1892       /**
 1893        * <p>Return an array of registered {@link FacesListener}s that are
 1894        * instances of the specified class.  If there are no such registered
 1895        * listeners, a zero-length array is returned.  The returned
 1896        * array can be safely be cast to an array strongly typed to
 1897        * an element type of <code>clazz</code>.</p>
 1898        *
 1899        * @param clazz Class that must be implemented by a {@link FacesListener}
 1900        *  for it to be returned
 1901        *
 1902        * @throws IllegalArgumentException if <code>class</code> is not,
 1903        *  and does not implement, {@link FacesListener}
 1904        * @throws NullPointerException if <code>clazz</code>
 1905        *  is <code>null</code>
 1906        */
 1907       protected abstract FacesListener[] getFacesListeners(Class clazz);
 1908   
 1909   
 1910       /**
 1911        * <p>Remove the specified {@link FacesListener} from the set of listeners
 1912        * registered to receive event notifications from this {@link UIComponent}.
 1913        *
 1914        * @param listener The {@link FacesListener} to be deregistered
 1915        *
 1916        * @throws NullPointerException if <code>listener</code>
 1917        *  is <code>null</code>
 1918        */
 1919       protected abstract void removeFacesListener(FacesListener listener);
 1920   
 1921   
 1922       /**
 1923        * <p>Queue an event for broadcast at the end of the current request
 1924        * processing lifecycle phase.  The default implementation in
 1925        * {@link UIComponentBase} must delegate this call to the
 1926        * <code>queueEvent()</code> method of the parent {@link UIComponent}.</p>
 1927        *
 1928        * @param event {@link FacesEvent} to be queued
 1929        *
 1930        * @throws IllegalStateException if this component is not a
 1931        *  descendant of a {@link UIViewRoot}
 1932        * @throws NullPointerException if <code>event</code>
 1933        *  is <code>null</code>
 1934        */
 1935       public abstract void queueEvent(FacesEvent event);
 1936   
 1937       /**
 1938        * <p class="changed_added_2_0">Install the listener instance
 1939        * referenced by argument <code>componentListener</code> as a
 1940        * listener for events of type <code>eventClass</code> originating
 1941        * from this specific instance of <code>UIComponent</code>.  The
 1942        * default implementation creates an inner {@link
 1943        * SystemEventListener} instance that wraps argument
 1944        * <code>componentListener</code> as the <code>listener</code>
 1945        * argument.  This inner class must call through to the argument
 1946        * <code>componentListener</code> in its implementation of {@link
 1947        * SystemEventListener#processEvent} and its implementation of
 1948        * {@link SystemEventListener#isListenerForSource} must return
 1949        * true if the instance class of this <code>UIComponent</code> is
 1950        * assignable from the argument to
 1951        * <code>isListenerForSource</code>.</p>
 1952        *
 1953        * @param eventClass the <code>Class</code> of event for which
 1954        * <code>listener</code> must be fired.
 1955        * @param componentListener the implementation of {@link
 1956        * ComponentSystemEventListener} whose {@link
 1957        * ComponentSystemEventListener#processEvent} method must be called
 1958        * when events of type <code>facesEventClass</code> are fired.
 1959        *
 1960        * @throws <code>NullPointerException</code> if any of the
 1961        * arguments are <code>null</code>.
 1962        *
 1963        * @since 2.0                                             
 1964        */
 1965       public void subscribeToEvent(Class<? extends SystemEvent> eventClass,
 1966                                    ComponentSystemEventListener componentListener) {
 1967   
 1968           if (eventClass == null) {
 1969               throw new NullPointerException();
 1970           }
 1971           if (componentListener == null) {
 1972               throw new NullPointerException();
 1973           }
 1974   
 1975           if (initialStateMarked()) {
 1976               initialState = false;
 1977           }
 1978           if (null == listenersByEventClass) {
 1979               listenersByEventClass = new HashMap<Class<? extends SystemEvent>,
 1980                                                   List<SystemEventListener>>(3, 1.0f);
 1981           }
 1982           SystemEventListener facesLifecycleListener =
 1983                 new ComponentSystemEventListenerAdapter(componentListener, this);
 1984           List<SystemEventListener> listenersForEventClass =
 1985                 listenersByEventClass.get(eventClass);
 1986           if (listenersForEventClass == null) {
 1987               listenersForEventClass = new ArrayList<SystemEventListener>(3);
 1988               listenersByEventClass.put(eventClass, listenersForEventClass);
 1989           }
 1990           if (!listenersForEventClass.contains(facesLifecycleListener)) {
 1991               listenersForEventClass.add(facesLifecycleListener);
 1992           }
 1993   
 1994       }
 1995   
 1996       /**
 1997        * <p class="changed_added_2_0">Remove the listener instance
 1998        *     referenced by argument <code>componentListener</code> as a
 1999        *     listener for events of type <code>eventClass</code>
 2000        *     originating from this specific instance of
 2001        *     <code>UIComponent</code>.  When doing the comparison to
 2002        *     determine if an existing listener is equal to the argument
 2003        *     <code>componentListener</code> (and thus must be removed),
 2004        *     the <code>equals()</code> method on the <em>existing
 2005        *     listener</em> must be invoked, passing the argument
 2006        *     <code>componentListener</code>, rather than the other way
 2007        *     around.</p>
 2008        *
 2009        * @param eventClass the <code>Class</code> of event for which
 2010        * <code>listener</code> must be removed.
 2011        * @param componentListener the implementation of {@link
 2012        * ComponentSystemEventListener} whose {@link
 2013        * ComponentSystemEventListener#processEvent} method must no longer be called
 2014        * when events of type <code>eventClass</code> are fired.
 2015        *
 2016        * @throws <code>NullPointerException</code> if any of the
 2017        * arguments are <code>null</code>.
 2018        *
 2019        * @since 2.0
 2020        */
 2021       public void unsubscribeFromEvent(Class<? extends SystemEvent> eventClass,
 2022                                        ComponentSystemEventListener componentListener) {
 2023   
 2024           if (eventClass == null) {
 2025               throw new NullPointerException();
 2026           }
 2027           if (componentListener == null) {
 2028               throw new NullPointerException();
 2029           }
 2030   
 2031           List<SystemEventListener> listeners =
 2032                 getListenersForEventClass(eventClass);
 2033           if (listeners != null && !listeners.isEmpty()) {
 2034               for (Iterator<SystemEventListener> i = listeners.iterator(); i.hasNext();) {
 2035                   SystemEventListener item = i.next();
 2036                   ComponentSystemEventListenerAdapter csla =
 2037                         (ComponentSystemEventListenerAdapter) item;
 2038                   ComponentSystemEventListener l = csla.getWrapped();
 2039                   if (l.equals(componentListener)) {
 2040                       i.remove();
 2041                       break;
 2042                   }
 2043               }
 2044           }
 2045   
 2046       }
 2047   
 2048       Map<Class<? extends SystemEvent>, List<SystemEventListener>> listenersByEventClass;
 2049   
 2050       /**
 2051        * <p class="changed_added_2_0">Return the
 2052        * <code>SystemEventListener</code> instances registered on this
 2053        * <code>UIComponent</code> instance that are interested in events
 2054        * of type <code>eventClass</code>.</p>
 2055        *
 2056        * @param eventClass the <code>Class</code> of event for which the
 2057        * listeners must be returned.
 2058   
 2059        * @throws NullPointerException if argument <code>eventClass</code> is <code>null</code>.
 2060        *
 2061        * @since 2.0
 2062        */
 2063       public List<SystemEventListener> getListenersForEventClass(Class<? extends SystemEvent> eventClass) {
 2064   
 2065           if (eventClass == null) {
 2066               throw new NullPointerException();
 2067           }
 2068           List<SystemEventListener> result = null;
 2069           if (listenersByEventClass != null) {
 2070               result = listenersByEventClass.get(eventClass);
 2071           }
 2072           return result;
 2073   
 2074       }
 2075   
 2076   
 2077       /**
 2078        * <p class="changed_added_2_0">Starting with "this", return the closest 
 2079        * component in the ancestry that is a <code>NamingContainer</code>
 2080        * or <code>null</code> if none can be found.</p>
 2081        *
 2082        * @since 2.0
 2083        */
 2084       public UIComponent getNamingContainer() {
 2085           UIComponent namingContainer = this;
 2086           while (namingContainer != null) {
 2087               if (namingContainer instanceof NamingContainer) {
 2088                   return namingContainer;
 2089               }
 2090               namingContainer = namingContainer.getParent();
 2091           }
 2092           return null;
 2093       }
 2094   
 2095       // ------------------------------------------------ Lifecycle Phase Handlers
 2096   
 2097   
 2098       /**
 2099        * <p><span class="changed_modified_2_0">Perform</span> the
 2100        * component tree processing required by the <em>Restore View</em>
 2101        * phase of the request processing lifecycle for all facets of this
 2102        * component, all children of this component, and this component
 2103        * itself, as follows.</p> <ul> <li
 2104        * class="changed_modified_2_0">Call the <code>restoreState()</code>
 2105        * method of this component.</li> 
 2106        *
 2107        * <li class="changed_added_2_0">Call
 2108        * {@link UIComponent#pushComponentToEL}.  </li>
 2109   
 2110        * <li>Call the <code>processRestoreState()</code> method of all
 2111        * facets and children of this {@link UIComponent} in the order
 2112        * determined by a call to <code>getFacetsAndChildren()</code>.
 2113        * <span class="changed_added_2_0">After returning from the
 2114        * <code>processRestoreState()</code> method on a child or facet,
 2115        * call {@link UIComponent#popComponentFromEL}</span></li>
 2116   
 2117        * </ul>
 2118        *
 2119        * <p>This method may not be called if the state saving method is
 2120        * set to server.</p>
 2121        *
 2122        * @param context {@link FacesContext} for the request we are processing
 2123        *
 2124        * @throws NullPointerException if <code>context</code>
 2125        *  is <code>null</code>
 2126        */
 2127       public abstract void processRestoreState(FacesContext context,
 2128                                                Object state);
 2129   
 2130   
 2131       /**
 2132        * <p><span class="changed_modified_2_0">Perform</span> the
 2133        * component tree processing required by the <em>Apply Request
 2134        * Values</em> phase of the request processing lifecycle for all
 2135        * facets of this component, all children of this component, and
 2136        * this component itself, as follows.</p>
 2137   
 2138        * <ul>
 2139        * <li>If the <code>rendered</code> property of this {@link UIComponent}
 2140        *     is <code>false</code>, skip further processing.</li>
 2141        * <li class="changed_added_2_0">Call {@link #pushComponentToEL}.</li>
 2142        * <li>Call the <code>processDecodes()</code> method of all facets
 2143        *     and children of this {@link UIComponent}, in the order determined
 2144        *     by a call to <code>getFacetsAndChildren()</code>.</li>
 2145   
 2146        * <li>Call the <code>decode()</code> method of this component.</li>
 2147   
 2148        * <li>Call {@link #popComponentFromEL} from inside of a
 2149        * <code>finally block, just before returning.</code></li>
 2150   
 2151   
 2152   
 2153        * <li>If a <code>RuntimeException</code> is thrown during
 2154        *     decode processing, call {@link FacesContext#renderResponse}
 2155        *     and re-throw the exception.</li>
 2156        * </ul>
 2157        *
 2158        * @param context {@link FacesContext} for the request we are processing
 2159        *
 2160        * @throws NullPointerException if <code>context</code>
 2161        *  is <code>null</code>
 2162        */
 2163       public abstract void processDecodes(FacesContext context);
 2164   
 2165       /**
 2166        * <p class="changed_added_2_0">The default implementation performs
 2167        * the following action.  If the argument <code>event</code> is an
 2168        * instance of {@link PostRestoreStateEvent}, call
 2169        * <code>this.</code>{@link #getValueExpression} passing the literal
 2170        * string &#8220;binding&#8221;, without the quotes, as the
 2171        * argument.  If the result is non-<code>null</code>, set the value
 2172        * of the <code>ValueExpression</code> to be <code>this</code>.</p>
 2173        */ 
 2174   
 2175       public void processEvent(ComponentSystemEvent event) throws AbortProcessingException {
 2176           if (event instanceof PostRestoreStateEvent) {
 2177   	    assert(this == event.getComponent());
 2178               // if this component has a component value reference expression,
 2179               // make sure to populate the ValueExpression for it.
 2180               ValueExpression valueExpression;
 2181               if (null != (valueExpression = this.getValueExpression("binding"))) {
 2182                   valueExpression.setValue(FacesContext.getCurrentInstance().getELContext(), 
 2183                           this);
 2184               }
 2185   
 2186           }
 2187       }
 2188       
 2189       
 2190   
 2191   
 2192       /**
 2193        * <p><span class="changed_modified_2_0">Perform</span> the
 2194        * component tree processing required by the <em>Process
 2195        * Validations</em> phase of the request processing lifecycle for
 2196        * all facets of this component, all children of this component, and
 2197        * this component itself, as follows.</p>
 2198   
 2199        * <ul>
 2200        * <li>If the <code>rendered</code> property of this {@link UIComponent}
 2201        *     is <code>false</code>, skip further processing.</li>
 2202        * <li class="changed_added_2_0">Call {@link #pushComponentToEL}.</li>
 2203        * <li>Call the <code>processValidators()</code> method of all facets
 2204        *     and children of this {@link UIComponent}, in the order determined
 2205        *     by a call to <code>getFacetsAndChildren()</code>.</li>
 2206        * </ul>
 2207        *
 2208        * @param context {@link FacesContext} for the request we are processing
 2209        *
 2210        * @throws NullPointerException if <code>context</code>
 2211        *  is <code>null</code>
 2212        */
 2213       public abstract void processValidators(FacesContext context);
 2214   
 2215   
 2216       /**
 2217        * <p><span class="changed_modified_2_0">Perform</span> the
 2218        * component tree processing required by the <em>Update Model
 2219        * Values</em> phase of the request processing lifecycle for all
 2220        * facets of this component, all children of this component, and
 2221        * this component itself, as follows.</p> 
 2222   
 2223        * <ul> 
 2224   
 2225        * <li>If the <code>rendered</code> property of this {@link
 2226        * UIComponent} is <code>false</code>, skip further processing.</li>
 2227   
 2228        * <li class="changed_added_2_0">Call {@link
 2229        * #pushComponentToEL}.</li>
 2230   
 2231        * <li>Call the <code>processUpdates()</code> method of all facets
 2232        * and children of this {@link UIComponent}, in the order determined
 2233        * by a call to <code>getFacetsAndChildren()</code>.  <span
 2234        * class="changed_added_2_0">After returning from the
 2235        * <code>processUpdates()</code> method on a child or facet, call
 2236        * {@link UIComponent#popComponentFromEL}</span></li>
 2237    
 2238       * </ul>
 2239        *
 2240        * @param context {@link FacesContext} for the request we are processing
 2241        *
 2242        * @throws NullPointerException if <code>context</code>
 2243        *  is <code>null</code>
 2244        */
 2245       public abstract void processUpdates(FacesContext context);
 2246   
 2247   
 2248       /**
 2249        * <p><span class="changed_modified_2_0">Perform</span> the
 2250        * component tree processing required by the state saving portion of
 2251        * the <em>Render Response</em> phase of the request processing
 2252        * lifecycle for all facets of this component, all children of this
 2253        * component, and this component itself, as follows.</p>
 2254   
 2255        * <ul>
 2256        *
 2257        * <li>consult the <code>transient</code> property of this
 2258        * component.  If true, just return <code>null</code>.</li>
 2259   
 2260        * <li class="changed_added_2_0">Call {@link
 2261        * #pushComponentToEL}.</li>
 2262   
 2263        * <li>Call the <code>processSaveState()</code> method of all facets
 2264        * and children of this {@link UIComponent} in the order determined
 2265        * by a call to <code>getFacetsAndChildren()</code>, skipping
 2266        * children and facets that are transient.  Ensure that {@link
 2267        * #popComponentFromEL} is called correctly after each child or
 2268        * facet.</li>
 2269        *
 2270        * <li>Call the <code>saveState()</code> method of this component.</li>
 2271        *
 2272        * <li>Encapsulate the child state and your state into a
 2273        * Serializable Object and return it.</li> 
 2274        *
 2275        * </ul>
 2276        *
 2277        * <p>This method may not be called if the state saving method is
 2278        * set to server.</p>
 2279        *
 2280        * @param context {@link FacesContext} for the request we are processing
 2281        *
 2282        * @throws NullPointerException if <code>context</code>
 2283        *  is <code>null</code>
 2284        */
 2285       public abstract Object processSaveState(FacesContext context);
 2286   
 2287   
 2288       // ----------------------------------------------------- Convenience Methods
 2289   
 2290   
 2291       /**
 2292        * <p>Convenience method to return the {@link FacesContext} instance
 2293        * for the current request.</p>
 2294        */
 2295       protected abstract FacesContext getFacesContext();
 2296   
 2297   
 2298       /**
 2299        * <p>Convenience method to return the {@link Renderer} instance
 2300        * associated with this component, if any; otherwise, return
 2301        * <code>null</code>.</p>
 2302        *
 2303        * @param context {@link FacesContext} for the current request
 2304        */
 2305       protected abstract Renderer getRenderer(FacesContext context);
 2306   
 2307   
 2308       // --------------------------------------------------------- Package Private
 2309   
 2310   
 2311       static final class ComponentSystemEventListenerAdapter
 2312          implements SystemEventListener, StateHolder, FacesWrapper<ComponentSystemEventListener> {
 2313   
 2314           ComponentSystemEventListener wrapped;
 2315           Class<?> instanceClass;
 2316   
 2317   
 2318           // -------------------------------------------------------- Constructors
 2319   
 2320   
 2321           ComponentSystemEventListenerAdapter() {
 2322   
 2323               // necessary for state saving
 2324   
 2325           }
 2326   
 2327   
 2328           ComponentSystemEventListenerAdapter(ComponentSystemEventListener wrapped,
 2329                                               UIComponent component) {
 2330   
 2331               this.wrapped = wrapped;
 2332               this.instanceClass = component.getClass();
 2333   
 2334           }
 2335   
 2336   
 2337           // ------------------------------------ Methods from SystemEventListener
 2338   
 2339   
 2340           public void processEvent(SystemEvent event) throws AbortProcessingException {
 2341   
 2342               wrapped.processEvent((ComponentSystemEvent) event);
 2343   
 2344           }
 2345   
 2346   
 2347           public boolean isListenerForSource(Object component) {
 2348   
 2349               if (wrapped instanceof SystemEventListener) {
 2350                   return ((SystemEventListener) wrapped).isListenerForSource(component);
 2351               } else {
 2352                   return instanceClass.isAssignableFrom(component.getClass());
 2353               }
 2354   
 2355           }
 2356   
 2357   
 2358           // -------------------------------------------- Methods from StateHolder
 2359   
 2360           public Object saveState(FacesContext context) {
 2361   
 2362               if (context == null) {
 2363                   throw new NullPointerException();
 2364               }
 2365               return new Object[] {
 2366                     ((wrapped instanceof UIComponent) ? null : new StateHolderSaver(context, wrapped)),
 2367                     instanceClass
 2368               };
 2369   
 2370           }
 2371   
 2372   
 2373           public void restoreState(FacesContext context, Object state) {
 2374   
 2375               if (context == null) {
 2376                   throw new NullPointerException();
 2377               }
 2378               if (state == null) {
 2379                   return;
 2380               }
 2381               Object[] s = (Object[]) state;
 2382               Object listener = s[0];
 2383               wrapped = (ComponentSystemEventListener) ((listener == null)
 2384                                                         ? UIComponent .getCurrentComponent(context)
 2385                                                         : ((StateHolderSaver) listener).restore(context));
 2386               instanceClass = (Class<?>) s[1];
 2387               
 2388           }
 2389   
 2390   
 2391           public boolean isTransient() {
 2392   
 2393               if (wrapped instanceof StateHolder) {
 2394                   return ((StateHolder) wrapped).isTransient();
 2395               }
 2396               return false;
 2397   
 2398           }
 2399   
 2400   
 2401           public void setTransient(boolean newTransientValue) {
 2402   
 2403               // no-op
 2404   
 2405           }
 2406   
 2407   
 2408           // ------------------------------------------- Methods from FacesWrapper
 2409   
 2410   
 2411           public ComponentSystemEventListener getWrapped() {
 2412   
 2413               return wrapped;
 2414   
 2415           }
 2416   
 2417   
 2418           // ------------------------------------------------------ Public Methods
 2419   
 2420   
 2421           @Override
 2422           public int hashCode() {
 2423   
 2424               return (wrapped.hashCode() ^ instanceClass.hashCode());
 2425   
 2426           }
 2427   
 2428           @Override
 2429           public boolean equals(Object obj) {
 2430   
 2431               if (!(obj instanceof ComponentSystemEventListenerAdapter)) {
 2432                   return false;
 2433               }
 2434               ComponentSystemEventListenerAdapter in =
 2435                     (ComponentSystemEventListenerAdapter) obj;
 2436               return (wrapped.equals(in.wrapped)
 2437                       && instanceClass.equals(in.instanceClass));
 2438               
 2439           }
 2440       } // END ComponentSystemEventListenerAdapter
 2441   
 2442   }

Home » Mojarra-2.0.1 » javax » faces » component » [javadoc | source]