Coverage Report - javax.faces.component.UIComponent
 
Classes in this File Line Coverage Branch Coverage Complexity
UIComponent
0%
0/205
0%
0/139
0
UIComponent$1
0%
0/1
N/A
0
UIComponent$BundleMap
0%
0/34
0%
0/12
0
UIComponent$BundleMap$1
0%
0/4
N/A
0
UIComponent$EventListenerWrapper
0%
0/53
0%
0/48
0
UIComponent$PropertyKeys
0%
0/6
N/A
0
 
 1  
 /*
 2  
  * Licensed to the Apache Software Foundation (ASF) under one
 3  
  * or more contributor license agreements.  See the NOTICE file
 4  
  * distributed with this work for additional information
 5  
  * regarding copyright ownership.  The ASF licenses this file
 6  
  * to you under the Apache License, Version 2.0 (the
 7  
  * "License"); you may not use this file except in compliance
 8  
  * with the License.  You may obtain a copy of the License at
 9  
  *
 10  
  *   http://www.apache.org/licenses/LICENSE-2.0
 11  
  *
 12  
  * Unless required by applicable law or agreed to in writing,
 13  
  * software distributed under the License is distributed on an
 14  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 15  
  * KIND, either express or implied.  See the License for the
 16  
  * specific language governing permissions and limitations
 17  
  * under the License.
 18  
  */
 19  
 package javax.faces.component;
 20  
 
 21  
 import java.io.IOException;
 22  
 import java.util.ArrayList;
 23  
 import java.util.Collection;
 24  
 import java.util.Collections;
 25  
 import java.util.Enumeration;
 26  
 import java.util.HashMap;
 27  
 import java.util.HashSet;
 28  
 import java.util.Iterator;
 29  
 import java.util.LinkedList;
 30  
 import java.util.List;
 31  
 import java.util.Locale;
 32  
 import java.util.Map;
 33  
 import java.util.MissingResourceException;
 34  
 import java.util.PropertyResourceBundle;
 35  
 import java.util.ResourceBundle;
 36  
 import java.util.Set;
 37  
 
 38  
 import javax.el.ELException;
 39  
 import javax.el.ValueExpression;
 40  
 import javax.faces.FacesException;
 41  
 import javax.faces.application.Application;
 42  
 import javax.faces.application.Resource;
 43  
 import javax.faces.component.visit.VisitCallback;
 44  
 import javax.faces.component.visit.VisitContext;
 45  
 import javax.faces.component.visit.VisitHint;
 46  
 import javax.faces.component.visit.VisitResult;
 47  
 import javax.faces.context.FacesContext;
 48  
 import javax.faces.el.ValueBinding;
 49  
 import javax.faces.event.AbortProcessingException;
 50  
 import javax.faces.event.ComponentSystemEvent;
 51  
 import javax.faces.event.ComponentSystemEventListener;
 52  
 import javax.faces.event.FacesEvent;
 53  
 import javax.faces.event.FacesListener;
 54  
 import javax.faces.event.PostRestoreStateEvent;
 55  
 import javax.faces.event.SystemEvent;
 56  
 import javax.faces.event.SystemEventListener;
 57  
 import javax.faces.event.SystemEventListenerHolder;
 58  
 import javax.faces.render.Renderer;
 59  
 import javax.faces.view.ViewDeclarationLanguage;
 60  
 
 61  
 import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFComponent;
 62  
 
 63  
 /**
 64  
  * 
 65  
  * see Javadoc of <a href="http://java.sun.com/javaee/javaserverfaces/1.2/docs/api/index.html">J
 66  
  * SF Specification</a>
 67  
  * 
 68  
  * @author Manfred Geiler (latest modification by $Author: jakobk $)
 69  
  * @version $Revision: 911789 $ $Date: 2010-02-19 06:59:22 -0500 (Fri, 19 Feb 2010) $
 70  
  */
 71  
 @JSFComponent(type = "javax.faces.Component", family = "javax.faces.Component", desc = "abstract base component", configExcluded = true)
 72  
 public abstract class UIComponent implements PartialStateHolder, SystemEventListenerHolder, ComponentSystemEventListener {
 73  
     // TODO: Reorder methods, this class is a mess
 74  
     /**
 75  
      * Constant used in component attribute map to retrieve the BeanInfo of a composite
 76  
      * component.
 77  
      * 
 78  
      * @see ViewDeclarationLanguage#getComponentMetadata(FacesContext, Resource)
 79  
      * @see ViewDeclarationLanguage#retargetAttachedObjects(FacesContext, UIComponent, List)
 80  
      * @see ViewDeclarationLanguage#retargetMethodExpressions(FacesContext, UIComponent)
 81  
      * @see Application#createComponent(FacesContext, Resource)
 82  
      */
 83  
     public static final String BEANINFO_KEY = "javax.faces.component.BEANINFO_KEY";
 84  
     
 85  
     /**
 86  
      * Constant used in BeanInfo descriptor as a key for retrieve an alternate component type
 87  
      * for create the composite base component. 
 88  
      * 
 89  
      * @see Application#createComponent(FacesContext, Resource)
 90  
      */
 91  
     public static final String COMPOSITE_COMPONENT_TYPE_KEY = "javax.faces.component.COMPOSITE_COMPONENT_TYPE";
 92  
     
 93  
     /**
 94  
      * Constant used to define the facet inside this component that store the component hierarchy
 95  
      * generated by a composite component implementation, and then rendered. In other words, 
 96  
      * note that direct children of a component are not rendered, instead components inside 
 97  
      * this face are rendered.
 98  
      */
 99  
     public static final String COMPOSITE_FACET_NAME = "javax.faces.component.COMPOSITE_FACET_NAME";
 100  
     
 101  
     /**
 102  
      * Constant used to store the current component that is being processed.
 103  
      * 
 104  
      * @see #pushComponentToEL(FacesContext, UIComponent)
 105  
      * @see #popComponentFromEL(FacesContext)
 106  
      */
 107  
     public static final String CURRENT_COMPONENT = "javax.faces.component.CURRENT_COMPONENT";
 108  
     
 109  
     /**
 110  
      * Constant used to store the current composite component that is being processed. 
 111  
      * 
 112  
      * @see #pushComponentToEL(FacesContext, UIComponent)
 113  
      * @see #popComponentFromEL(FacesContext)
 114  
      */    
 115  
     public static final String CURRENT_COMPOSITE_COMPONENT = "javax.faces.component.CURRENT_COMPOSITE_COMPONENT";
 116  
     
 117  
     /**
 118  
      * This constant has two usages. The first one is in component attribute map to identify the 
 119  
      * facet name under this component is child of its parent. The second one is on BeanInfo descriptor
 120  
      * as a key for a Map&lt;String, PropertyDescriptor&gt; that contains metadata information defined
 121  
      * by composite:facet tag and composite:implementation(because this one fills the facet referenced
 122  
      * by COMPOSITE_FACET_NAME constant). 
 123  
      */
 124  
     public static final String FACETS_KEY = "javax.faces.component.FACETS_KEY";
 125  
     
 126  
     /**
 127  
      * Constant used in component attribute map to store the {@link javax.faces.view.Location} object
 128  
      * where the definition of this component is.
 129  
      */
 130  
     public static final String VIEW_LOCATION_KEY = "javax.faces.component.VIEW_LOCATION_KEY";
 131  
     
 132  
     /**
 133  
      * The key under which the component stack is stored in the FacesContext.
 134  
      * ATTENTION: this constant is duplicate in CompositeComponentExpressionUtils.
 135  
      */
 136  0
     private static final String _COMPONENT_STACK = "componentStack:" + UIComponent.class.getName();
 137  
     
 138  
     Map<Class<? extends SystemEvent>, List<SystemEventListener>> _systemEventListenerClassMap;
 139  
     
 140  
     /**
 141  
      * @deprecated
 142  
      */
 143  
     @Deprecated
 144  
     protected Map<String, ValueExpression> bindings;
 145  
     /**
 146  
      * Used to cache the map created using getResourceBundleMap() method, since this method could be called several
 147  
      * times when rendering the composite component. This attribute may not be serialized, so transient is used (There
 148  
      * are some very few special cases when UIComponent instances are serializable like t:schedule, so it is better if
 149  
      * transient is used).
 150  
      */
 151  0
     private transient Map<String, String> _resourceBundleMap = null;
 152  0
     private boolean _inView = false;
 153  0
     private StateHelper _stateHelper = null;
 154  
     
 155  
     /**
 156  
      * In JSF 2.0 bindings map was deprecated, and replaced with a map
 157  
      * inside stateHelper. We need this one here because stateHelper needs
 158  
      * to be implemented from here and internally it depends from this property.
 159  
      */
 160  0
     private boolean _initialStateMarked = false;
 161  
 
 162  0
     public UIComponent() {
 163  0
     }
 164  
 
 165  
     public abstract Map<String, Object> getAttributes();
 166  
 
 167  
     /**
 168  
      * 
 169  
      * {@inheritDoc}
 170  
      * 
 171  
      * @since 2.0
 172  
      */
 173  
     public boolean initialStateMarked()
 174  
     {
 175  0
         return _initialStateMarked;
 176  
     }
 177  
 
 178  
     /**
 179  
      * Invokes the <code>invokeContextCallback</code> method with the component, specified by <code>clientId</code>.
 180  
      * 
 181  
      * @param context
 182  
      *            <code>FacesContext</code> for the current request
 183  
      * @param clientId
 184  
      *            the id of the desired <code>UIComponent</code> clazz
 185  
      * @param callback
 186  
      *            Implementation of the <code>ContextCallback</code> to be called
 187  
      * @return has component been found ?
 188  
      * @throws javax.faces.FacesException
 189  
      */
 190  
     public boolean invokeOnComponent(FacesContext context, String clientId, ContextCallback callback)
 191  
             throws FacesException {
 192  
         // java.lang.NullPointerException - if any of the arguments are null
 193  0
         if (context == null || clientId == null || callback == null) {
 194  0
             throw new NullPointerException();
 195  
         }
 196  
 
 197  
         // searching for this component?
 198  0
         boolean found = clientId.equals(this.getClientId(context));
 199  0
         if (found) {
 200  
             try {
 201  0
                 callback.invokeContextCallback(context, this);
 202  0
             } catch (Exception e) {
 203  0
                 throw new FacesException(e);
 204  0
             }
 205  0
             return found;
 206  
         }
 207  
         // Searching for this component's children/facets
 208  0
         for (Iterator<UIComponent> it = this.getFacetsAndChildren(); !found && it.hasNext();) {
 209  0
             found = it.next().invokeOnComponent(context, clientId, callback);
 210  
         }
 211  
 
 212  0
         return found;
 213  
     }
 214  
 
 215  
     /**
 216  
      * 
 217  
      * @param component
 218  
      * @return true if the component is a composite component otherwise false is returned
 219  
      * 
 220  
      *
 221  
      * @throws NullPointerException if the component is null
 222  
      * @since 2.0
 223  
      */
 224  
     public static boolean isCompositeComponent(UIComponent component) {
 225  
 
 226  
         //since _isCompositeComponent does it the same way we do it here also although I
 227  
         //would prefer following method
 228  
 
 229  
         //return component.getRendererType().equals("javax.faces.Composite");
 230  
 
 231  0
         return component.getAttributes().containsKey(Resource.COMPONENT_RESOURCE_KEY);
 232  
     }
 233  
 
 234  
     /**
 235  
      * Indicate if this component is inside a view,
 236  
      * or in other words is contained by an UIViewRoot
 237  
      * instance (which represents the view). If this component
 238  
      * is a UIViewRoot instance, the components "always"
 239  
      * is on the view.
 240  
      * 
 241  
      * By default it is false but for UIViewRoot instances is
 242  
      * true. 
 243  
      * 
 244  
      * @return
 245  
      * 
 246  
      * @since 2.0
 247  
      */
 248  
     public boolean isInView() {
 249  0
         return _inView;
 250  
     }
 251  
 
 252  
     public abstract boolean isRendered();
 253  
 
 254  
     public void markInitialState()
 255  
     {
 256  0
         _initialStateMarked = true;
 257  0
     }
 258  
 
 259  
     /**
 260  
      *
 261  
      * This method indicates if a component is visitable
 262  
      * according to the hints passed by the VisitContext parameter!
 263  
      *
 264  
      * This method internally is used by visitTree and if it returns false
 265  
      * it short circuits the visitTree execution.
 266  
      *
 267  
      *
 268  
      *
 269  
      * @param context
 270  
      * @return
 271  
      * 
 272  
      * @since 2.0
 273  
      */
 274  
     protected boolean isVisitable(VisitContext context) {
 275  
 
 276  0
         Collection<VisitHint> hints = context.getHints();
 277  
 
 278  0
         if (hints.contains(VisitHint.SKIP_TRANSIENT) && this.isTransient())
 279  0
             return false;
 280  
 
 281  0
         if (hints.contains(VisitHint.SKIP_UNRENDERED) && !this.isRendered())
 282  0
             return false;
 283  
 
 284  
         //executable cannot be handled here because we do not have any method to determine
 285  
         //whether a component is executable or not, this seems to be a hole in the spec!
 286  
         //but we can resolve it on ppr context level, where it is needed!
 287  
         //maybe in the long run we can move it down here, if it makes sense
 288  
 
 289  0
         return true;
 290  
     }
 291  
 
 292  
     /**
 293  
      * @deprecated Replaced by setValueExpression
 294  
      */
 295  
     public abstract void setValueBinding(String name, ValueBinding binding);
 296  
 
 297  
     public void setValueExpression(String name, ValueExpression expression) {
 298  0
         if (name == null) {
 299  0
             throw new NullPointerException("name");
 300  
         }
 301  0
         if (name.equals("id")) {
 302  0
             throw new IllegalArgumentException("Can't set a ValueExpression for the 'id' property.");
 303  
         }
 304  0
         if (name.equals("parent")) {
 305  0
             throw new IllegalArgumentException("Can't set a ValueExpression for the 'parent' property.");
 306  
         }
 307  
 
 308  0
         if (expression == null) {
 309  
             //if (bindings != null) {
 310  
             //    bindings.remove(name);
 311  
             //    if (bindings.isEmpty()) {
 312  
             //        bindings = null;
 313  
             //    }
 314  
             //}
 315  0
             getStateHelper().remove(PropertyKeys.bindings, name);
 316  
         } else {
 317  0
             if (expression.isLiteralText()) {
 318  
                 try {
 319  0
                     Object value = expression.getValue(getFacesContext().getELContext());
 320  0
                     getAttributes().put(name, value);
 321  0
                     return;
 322  0
                 } catch (ELException e) {
 323  0
                     throw new FacesException(e);
 324  
                 }
 325  
             }
 326  
 
 327  
             //if (bindings == null) {
 328  
             //    bindings = new HashMap<String, ValueExpression>();
 329  
             //}
 330  
             //
 331  
             //bindings.put(name, expression);
 332  0
             getStateHelper().put(PropertyKeys.bindings, name, expression);
 333  
         }
 334  0
     }
 335  
 
 336  
     public String getClientId() {
 337  0
         return getClientId(getFacesContext());
 338  
     }
 339  
 
 340  
     public abstract String getClientId(FacesContext context);
 341  
 
 342  
     /**
 343  
      * search for the nearest parent composite component, if no parent is found
 344  
      * it has to return null!
 345  
      *
 346  
      * if the component itself is null we have to return null as well!
 347  
      *
 348  
      * @param component the component to start from
 349  
      * @return the parent composite component if found otherwise null
 350  
      * 
 351  
      * @since 2.0
 352  
      */
 353  
     public static UIComponent getCompositeComponentParent(UIComponent component) {
 354  
 
 355  0
         if(component == null) {
 356  0
             return null;
 357  
         }
 358  0
         UIComponent parent = component;
 359  
 
 360  
         do {
 361  0
             parent = parent.getParent();
 362  0
             if(parent != null && UIComponent.isCompositeComponent(parent)) {
 363  0
                 return parent;
 364  
             }
 365  0
         } while(parent != null);
 366  0
         return null;
 367  
     }
 368  
 
 369  
     /**
 370  
      * @since 1.2
 371  
      */
 372  
     public String getContainerClientId(FacesContext ctx) {
 373  0
         if (ctx == null) {
 374  0
             throw new NullPointerException("FacesContext ctx");
 375  
         }
 376  
 
 377  0
         return getClientId(ctx);
 378  
     }
 379  
 
 380  
     /**
 381  
      * 
 382  
      * @param context
 383  
      * @return
 384  
      * 
 385  
      * @since 2.0
 386  
      */
 387  
     public static UIComponent getCurrentComponent(FacesContext context) {
 388  0
         return (UIComponent) context.getAttributes().get(UIComponent.CURRENT_COMPONENT);
 389  
     }
 390  
 
 391  
     /**
 392  
      * 
 393  
      * @param context
 394  
      * @return
 395  
      * 
 396  
      * @since 2.0
 397  
      */
 398  
     public static UIComponent getCurrentCompositeComponent(FacesContext context) {
 399  0
         return (UIComponent) context.getAttributes().get(UIComponent.CURRENT_COMPOSITE_COMPONENT);
 400  
     }
 401  
 
 402  
     public abstract String getFamily();
 403  
 
 404  
     public abstract String getId();
 405  
 
 406  
     public List<SystemEventListener> getListenersForEventClass(Class<? extends SystemEvent> eventClass) {
 407  
         List<SystemEventListener> listeners;
 408  0
         if (_systemEventListenerClassMap == null) {
 409  0
             listeners = Collections.emptyList();
 410  
         } else {
 411  0
             listeners = _systemEventListenerClassMap.get(eventClass);
 412  0
             if (listeners == null) {
 413  0
                 listeners = Collections.emptyList();
 414  
             } else {
 415  0
                 listeners = Collections.unmodifiableList(listeners);
 416  
             }
 417  
         }
 418  
 
 419  0
         return listeners;
 420  
     }
 421  
 
 422  
     /**
 423  
      * 
 424  
      * @return
 425  
      * 
 426  
      * @since 2.0
 427  
      */
 428  
     public UIComponent getNamingContainer() {
 429  
         // Starting with "this", return the closest component in the ancestry that is a NamingContainer 
 430  
         // or null if none can be found.
 431  0
         UIComponent component = this;
 432  
         do {
 433  0
             if (component instanceof NamingContainer) {
 434  0
                 return component;
 435  
             }
 436  
 
 437  0
             component = component.getParent();
 438  0
         } while (component != null);
 439  
 
 440  0
         return null;
 441  
     }
 442  
 
 443  
     public abstract void setId(String id);
 444  
 
 445  
     /**
 446  
      * Define if the component is on the view or not.
 447  
      * <p>
 448  
      * This value is set in the following conditions:
 449  
      * </p>
 450  
      * <ul>
 451  
      * <li>Component / Facet added: if the parent isInView = true, 
 452  
      *     set it to true and all their children or facets,
 453  
      *     otherwise take no action</li>
 454  
      * <li>Component / Facet removed: if the parent isInView = false,
 455  
      *     set it to false and all their children or facets,
 456  
      *     otherwise take no action</li>
 457  
      * <ul>
 458  
      * @param isInView
 459  
      * 
 460  
      * @since 2.0
 461  
      */
 462  
     public void setInView(boolean isInView) {
 463  0
         _inView = isInView;
 464  0
     }
 465  
 
 466  
     /**
 467  
      * For JSF-framework internal use only. Don't call this method to add components to the component tree. Use
 468  
      * <code>parent.getChildren().add(child)</code> instead.
 469  
      */
 470  
     public abstract void setParent(UIComponent parent);
 471  
 
 472  
     /**
 473  
      * Returns the parent of the component. Children can be added to or removed from a component even if this method
 474  
      * returns null for the child.
 475  
      */
 476  
     public abstract UIComponent getParent();
 477  
 
 478  
     public abstract void setRendered(boolean rendered);
 479  
 
 480  
     public abstract String getRendererType();
 481  
 
 482  
     public abstract void setRendererType(String rendererType);
 483  
 
 484  
     public abstract boolean getRendersChildren();
 485  
 
 486  
     public Map<String, String> getResourceBundleMap() {
 487  0
         if (_resourceBundleMap == null) {
 488  0
             FacesContext context = getFacesContext();
 489  0
             Locale locale = context.getViewRoot().getLocale();
 490  0
             ClassLoader loader = _ClassUtils.getContextClassLoader();
 491  
 
 492  
             try {
 493  
                 // looks for a ResourceBundle with a base name equal to the fully qualified class
 494  
                 // name of the current UIComponent this and Locale equal to the Locale of the current UIViewRoot.
 495  0
                 _resourceBundleMap = new BundleMap(ResourceBundle.getBundle(getClass().getName(), locale, loader));
 496  0
             } catch (MissingResourceException e) {
 497  
                 // If no such bundle is found, and the component is a composite component
 498  0
                 if (this._isCompositeComponent()) {
 499  
                     // No need to check componentResource (the resource used to build the composite
 500  
                     // component instance) to null since it is already done on this._isCompositeComponent()
 501  0
                     Resource componentResource = (Resource) getAttributes().get(Resource.COMPONENT_RESOURCE_KEY);
 502  
                     // Let resourceName be the resourceName of the Resource for this composite component,
 503  
                     // replacing the file extension with ".properties"
 504  0
                     int extensionIndex = componentResource.getResourceName().lastIndexOf('.');
 505  0
                     String resourceName = (extensionIndex < 0 ? componentResource.getResourceName() : componentResource.getResourceName().substring(0, extensionIndex)) + ".properties";
 506  
 
 507  
                     // Let libraryName be the libraryName of the the Resource for this composite component.
 508  
                     // Call ResourceHandler.createResource(java.lang.String,java.lang.String), passing the derived
 509  
                     // resourceName and
 510  
                     // libraryName.
 511  0
                     Resource bundleResource = context.getApplication().getResourceHandler().createResource(resourceName, componentResource.getLibraryName());
 512  
 
 513  0
                     if (bundleResource != null) {
 514  
                         // If the resultant Resource exists and can be found, the InputStream for the resource
 515  
                         // is used to create a ResourceBundle. If either of the two previous steps for obtaining the
 516  
                         // ResourceBundle
 517  
                         // for this component is successful, the ResourceBundle is wrapped in a Map<String, String> and
 518  
                         // returned.
 519  
                         try {
 520  0
                             _resourceBundleMap = new BundleMap(new PropertyResourceBundle(bundleResource.getInputStream()));
 521  0
                         } catch (IOException e1) {
 522  
                             // Nothing happens, then resourceBundleMap is set as empty map
 523  0
                         }
 524  
                     }
 525  
                 }
 526  
                 // Otherwise Collections.EMPTY_MAP is returned.
 527  0
                 if (_resourceBundleMap == null) {
 528  0
                     _resourceBundleMap = Collections.emptyMap();
 529  
                 }
 530  0
             }
 531  
         }
 532  
 
 533  0
         return _resourceBundleMap;
 534  
     }
 535  
 
 536  
     /**
 537  
      * @deprecated Replaced by getValueExpression
 538  
      */
 539  
     public abstract ValueBinding getValueBinding(String name);
 540  
 
 541  
     public ValueExpression getValueExpression(String name) {
 542  0
         if (name == null) {
 543  0
             throw new NullPointerException("name can not be null");
 544  
         }
 545  
         
 546  0
         Map<String,Object> bindings = (Map<String,Object>) getStateHelper().
 547  
             get(PropertyKeys.bindings); 
 548  
 
 549  0
         if (bindings == null) {
 550  0
             if (!(this instanceof UIComponentBase)) {
 551  
                 // if the component does not inherit from UIComponentBase and don't implements JSF 1.2 or later
 552  0
                 ValueBinding vb = getValueBinding(name);
 553  0
                 if (vb != null) {
 554  
                     //bindings = new HashMap<String, ValueExpression>();
 555  0
                     ValueExpression ve = new _ValueBindingToValueExpression(vb);
 556  0
                     getStateHelper().put(PropertyKeys.bindings , name,  ve);
 557  0
                     return ve;
 558  
                 }
 559  0
             }
 560  
         } else {
 561  
             //return bindings.get(name);
 562  0
             return (ValueExpression) bindings.get(name);
 563  
         }
 564  0
         return null;
 565  
     }
 566  
 
 567  
     public abstract List<UIComponent> getChildren();
 568  
 
 569  
     public abstract int getChildCount();
 570  
 
 571  
     public abstract UIComponent findComponent(String expr);
 572  
 
 573  
     public abstract Map<String, UIComponent> getFacets();
 574  
 
 575  
     public abstract UIComponent getFacet(String name);
 576  
 
 577  
     public abstract Iterator<UIComponent> getFacetsAndChildren();
 578  
 
 579  
     public abstract void broadcast(FacesEvent event) throws AbortProcessingException;
 580  
 
 581  
     /**
 582  
      * {@inheritDoc}
 583  
      * 
 584  
      * @since 2.0
 585  
      */
 586  
     public void clearInitialState()
 587  
     {
 588  0
         _initialStateMarked = false;
 589  0
     }
 590  
 
 591  
     public abstract void decode(FacesContext context);
 592  
 
 593  
     public abstract void encodeBegin(FacesContext context) throws IOException;
 594  
 
 595  
     public abstract void encodeChildren(FacesContext context) throws IOException;
 596  
 
 597  
     public abstract void encodeEnd(FacesContext context) throws IOException;
 598  
 
 599  
     public void encodeAll(FacesContext context) throws IOException {
 600  0
         if (context == null) {
 601  0
             throw new NullPointerException();
 602  
         }
 603  
 
 604  0
         if (isRendered()) {
 605  0
             this.encodeBegin(context);
 606  
 
 607  
             // rendering children
 608  0
             if (this.getRendersChildren()) {
 609  0
                 this.encodeChildren(context);
 610  
             } // let children render itself
 611  
             else {
 612  0
                 if (this.getChildCount() > 0) {
 613  0
                     for (UIComponent comp : this.getChildren()) {
 614  0
                         comp.encodeAll(context);
 615  
                     }
 616  
                 }
 617  
             }
 618  0
             this.encodeEnd(context);
 619  
         }
 620  0
     }
 621  
 
 622  
     protected abstract void addFacesListener(FacesListener listener);
 623  
 
 624  
     protected abstract FacesListener[] getFacesListeners(Class clazz);
 625  
 
 626  
     protected abstract void removeFacesListener(FacesListener listener);
 627  
 
 628  
     public abstract void queueEvent(FacesEvent event);
 629  
 
 630  
     public abstract void processRestoreState(FacesContext context, Object state);
 631  
 
 632  
     public abstract void processDecodes(FacesContext context);
 633  
 
 634  
     public void processEvent(ComponentSystemEvent event) throws AbortProcessingException {
 635  
         // The default implementation performs the following action. If the argument event is an instance of
 636  
         // AfterRestoreStateEvent,
 637  0
         if (event instanceof PostRestoreStateEvent) {
 638  
 
 639  
             // call this.getValueExpression(java.lang.String) passing the literal string "binding"
 640  0
             ValueExpression expression = getValueExpression("binding");
 641  
 
 642  
             // If the result is non-null, set the value of the ValueExpression to be this.
 643  0
             if (expression != null) {
 644  0
                 expression.setValue(getFacesContext().getELContext(), this);
 645  
             }
 646  
 
 647  
             //we issue a PostRestoreStateEvent
 648  
             //we issue it here because the spec clearly states what UIComponent is allowed to do
 649  
             //the main issue is that the spec does not say anything about a global dispatch on this level
 650  
             //but a quick blackbox test against the ri revealed that the event clearly is dispatched
 651  
             //at restore level for every component so we either issue it here or in UIViewRoot and/or the facelet
 652  
             // and jsp restore state triggers, a central point is preferrble so we do it here
 653  
             //TODO ask the EG the spec clearly contradicts blackbox RI behavior here 
 654  
 
 655  
            //getFacesContext().getApplication().publishEvent(getFacesContext(), PostRestoreStateEvent.class, UIComponent.class, this);
 656  
         }
 657  
 
 658  0
     }
 659  
 
 660  
     public abstract void processValidators(FacesContext context);
 661  
 
 662  
     public abstract void processUpdates(FacesContext context);
 663  
 
 664  
     public abstract java.lang.Object processSaveState(FacesContext context);
 665  
 
 666  
     public void subscribeToEvent(Class<? extends SystemEvent> eventClass, ComponentSystemEventListener componentListener) {
 667  
         // The default implementation creates an inner SystemEventListener instance that wraps argument
 668  
         // componentListener as the listener argument.
 669  0
         if (eventClass == null)
 670  
         {
 671  0
             throw new NullPointerException("eventClass required");
 672  
         }
 673  0
         if (componentListener == null)
 674  
         {
 675  0
             throw new NullPointerException("componentListener required");
 676  
         }
 677  
         
 678  0
         SystemEventListener listener = new EventListenerWrapper(this, componentListener);
 679  
 
 680  
         // Make sure the map exists
 681  0
         if (_systemEventListenerClassMap == null) {
 682  0
             _systemEventListenerClassMap = new HashMap<Class<? extends SystemEvent>, List<SystemEventListener>>();
 683  
         }
 684  
 
 685  0
         List<SystemEventListener> listeners = _systemEventListenerClassMap.get(eventClass);
 686  
         // Make sure the list for class exists
 687  0
         if (listeners == null) {
 688  0
             listeners = new _DeltaList<SystemEventListener>(new ArrayList<SystemEventListener>(2));
 689  0
             _systemEventListenerClassMap.put(eventClass, listeners);
 690  
         }
 691  
 
 692  
         // Deal with contains? Spec is silent
 693  0
         listeners.add(listener);
 694  0
     }
 695  
 
 696  
     public void unsubscribeFromEvent(Class<? extends SystemEvent> eventClass,
 697  
             ComponentSystemEventListener componentListener) {
 698  
         /*
 699  
          * When doing the comparison to determine if an existing listener is equal to the argument componentListener
 700  
          * (and thus must be removed), the equals() method on the existing listener must be invoked, passing the
 701  
          * argument componentListener, rather than the other way around.
 702  
          * 
 703  
          * What is that supposed to mean? Are we supposed to keep an internal map of created listener wrappers? TODO:
 704  
          * Check with the EG what's the meaning of this, equals should be commutative -= Simon Lessard =-
 705  
          */
 706  0
         if (eventClass == null)
 707  
         {
 708  0
             throw new NullPointerException("eventClass required");
 709  
         }
 710  0
         if (componentListener == null)
 711  
         {
 712  0
             throw new NullPointerException("componentListener required");
 713  
         }
 714  
 
 715  0
         SystemEventListener listener = new EventListenerWrapper(this, componentListener);
 716  
 
 717  0
         getFacesContext().getApplication().unsubscribeFromEvent(eventClass, listener);
 718  0
     }
 719  
 
 720  
     /**
 721  
      * The visit tree method, visit tree walks over a subtree and processes
 722  
      * the callback object to perform some operation on the subtree
 723  
      * <p>
 724  
      * there are some details in the implementation which according to the spec have
 725  
      * to be in place:
 726  
      * a) before calling the callback and traversing into the subtree  pushComponentToEL
 727  
      * has to be called
 728  
      * b) after the processing popComponentFromEL has to be performed to remove the component
 729  
      * from the el
 730  
      * </p>
 731  
      * <p>
 732  
      * The tree traversal optimizations are located in the visit context and can be replaced
 733  
      * via the VisitContextFactory in the faces-config factory section
 734  
      * </p>
 735  
      *
 736  
      * @param context the visit context which handles the processing details
 737  
      * @param callback the callback to be performed
 738  
      * @return false if the processing is not done true if we can shortcut
 739  
      * the visiting because we are done with everything
 740  
      * 
 741  
      * @since 2.0
 742  
      */
 743  
     public boolean visitTree(VisitContext context, VisitCallback callback) {
 744  0
         if (!isVisitable(context)) {
 745  0
             return false;
 746  
         }
 747  
 
 748  0
         pushComponentToEL(context.getFacesContext(), this);
 749  
         try {
 750  0
             VisitResult res = context.invokeVisitCallback(this, callback);
 751  0
             switch (res) {
 752  
             //we are done nothing has to be processed anymore
 753  
             case COMPLETE:
 754  0
                 return true;
 755  
 
 756  
             case REJECT:
 757  0
                 return false;
 758  
 
 759  
             //accept
 760  
             default:
 761  0
                 if (getFacetCount() > 0) {
 762  0
                     for (UIComponent facet : getFacets().values()) {
 763  0
                         if (facet.visitTree(context, callback)) {
 764  0
                             return true;
 765  
                         }
 766  
                     }
 767  
                 }
 768  0
                 if (getChildCount() > 0) {
 769  0
                     for (UIComponent child : getChildren()) {
 770  0
                         if (child.visitTree(context, callback)) {
 771  0
                             return true;
 772  
                         }
 773  
                     }
 774  
                 }
 775  0
                 return false;
 776  
             }
 777  
         }
 778  
         finally {
 779  
             //all components must call popComponentFromEl after visiting is finished
 780  0
             popComponentFromEL(context.getFacesContext());
 781  
         }
 782  
     }
 783  
 
 784  
     protected abstract FacesContext getFacesContext();
 785  
 
 786  
     protected abstract Renderer getRenderer(FacesContext context);
 787  
 
 788  
     /**
 789  
      * Note that id, clientId properties
 790  
      * never change its value after the component is populated,
 791  
      * so we don't need to store it on StateHelper or restore it when
 792  
      * initialStateMarked == true
 793  
      * (Note that rendererType is suspicious, in theory this field is
 794  
      * initialized on constructor, but on 1.1 and 1.2 is saved and restored,
 795  
      * so to keep backward behavior we put it on StateHelper )
 796  
      *  
 797  
      * Also, facesListeners can't be wrapped on StateHelper because it
 798  
      * needs to handle PartialStateHolder instances when it is saved and
 799  
      * restored and this interface does not implement PartialStateHolder,
 800  
      * so we can't propagate calls to markInitialState and clearInitialState,
 801  
      * in other words, the List wrapped by StateHelper does not handle
 802  
      * PartialStateHolder items.
 803  
      * 
 804  
      * "bindings" map does not need to deal with PartialStateHolder instances,
 805  
      *  so we can use StateHelper feature (handle delta for this map or in
 806  
      *  other words track add/removal from bindings map as delta).
 807  
      */
 808  0
     enum PropertyKeys
 809  
     {
 810  0
         rendered,
 811  0
         rendererType,
 812  0
         attributesMap,
 813  0
         bindings,
 814  0
         facesListeners
 815  
     }
 816  
 
 817  
     protected StateHelper getStateHelper() {
 818  0
         return getStateHelper(true);
 819  
     }
 820  
 
 821  
     /**
 822  
      * returns a delta state saving enabled state helper
 823  
      * for the current component
 824  
      * @param create if true a state helper is created if not already existing
 825  
      * @return an implementation of the StateHelper interface or null if none exists and create is set to false
 826  
      */
 827  
     protected StateHelper getStateHelper(boolean create) {
 828  0
         if(_stateHelper != null) {
 829  0
             return _stateHelper;
 830  
         }
 831  0
         if(create) {
 832  0
             _stateHelper = new _DeltaStateHelper(this);
 833  
         }
 834  0
         return _stateHelper;
 835  
     }
 836  
 
 837  
     @SuppressWarnings("unchecked")
 838  
     public final void popComponentFromEL(FacesContext context) {
 839  0
         Map<Object, Object> contextAttributes = context.getAttributes();        
 840  
         
 841  
         // Pop the current UIComponent from the FacesContext attributes map so that the previous 
 842  
         // UIComponent, if any, becomes the current component.
 843  0
         LinkedList<UIComponent> componentStack = (LinkedList<UIComponent>) contextAttributes.get(UIComponent._COMPONENT_STACK);
 844  
         
 845  0
         UIComponent newCurrent = null;
 846  0
         if (componentStack != null && !componentStack.isEmpty())
 847  
         {
 848  0
             newCurrent = componentStack.removeFirst();
 849  
         }
 850  
         else
 851  
         {
 852  
             //Reset the current composite component
 853  0
             contextAttributes.put(UIComponent.CURRENT_COMPOSITE_COMPONENT, null);
 854  
         }
 855  0
         UIComponent oldCurrent = (UIComponent)contextAttributes.put(UIComponent.CURRENT_COMPONENT, newCurrent);
 856  
         
 857  0
         if (oldCurrent != null && oldCurrent._isCompositeComponent())
 858  
         {
 859  
             // Recalculate the current composite component
 860  0
             if (newCurrent != null)
 861  
             {
 862  0
                 if (newCurrent._isCompositeComponent())
 863  
                 {
 864  0
                     contextAttributes.put(UIComponent.CURRENT_COMPOSITE_COMPONENT, newCurrent);
 865  
                 }
 866  
                 else
 867  
                 {
 868  0
                     UIComponent previousCompositeComponent = null;
 869  0
                     for (Iterator<UIComponent> it = componentStack.iterator(); it.hasNext();)
 870  
                     {
 871  0
                         UIComponent component = it.next();
 872  0
                         if (component._isCompositeComponent())
 873  
                         {
 874  0
                             previousCompositeComponent = component;
 875  0
                             break;
 876  
                         }
 877  0
                     }
 878  0
                     contextAttributes.put(UIComponent.CURRENT_COMPOSITE_COMPONENT, previousCompositeComponent);
 879  
                 }
 880  
             }
 881  
         }
 882  0
     }
 883  
 
 884  
     @SuppressWarnings("unchecked")
 885  
     public final void pushComponentToEL(FacesContext context, UIComponent component) {
 886  0
         if (component == null)
 887  
         {
 888  0
             component = this;
 889  
         }
 890  0
         Map<Object, Object> contextAttributes = context.getAttributes();        
 891  0
         UIComponent currentComponent = (UIComponent) contextAttributes.get(UIComponent.CURRENT_COMPONENT);
 892  
         
 893  0
         if(currentComponent != null)
 894  
         {
 895  0
             LinkedList<UIComponent> componentStack = (LinkedList<UIComponent>) contextAttributes.get(UIComponent._COMPONENT_STACK);
 896  0
             if(componentStack == null)
 897  
             {
 898  0
                 componentStack = new LinkedList<UIComponent>();
 899  0
                 contextAttributes.put(UIComponent._COMPONENT_STACK, componentStack);
 900  
             }
 901  
             
 902  0
             componentStack.addFirst(currentComponent);
 903  
         }
 904  
         
 905  
         // Push the current UIComponent this to the FacesContext  attribute map using the key CURRENT_COMPONENT 
 906  
         // saving the previous UIComponent associated with CURRENT_COMPONENT for a subsequent call to 
 907  
         // popComponentFromEL(javax.faces.context.FacesContext).
 908  0
         contextAttributes.put(UIComponent.CURRENT_COMPONENT, component);
 909  
  
 910  0
         if (component._isCompositeComponent())
 911  
         {
 912  0
             contextAttributes.put(UIComponent.CURRENT_COMPOSITE_COMPONENT, component);
 913  
         }
 914  0
     }
 915  
 
 916  
     /**
 917  
      * @since 1.2
 918  
      */
 919  
     public int getFacetCount() {
 920  
         // not sure why the RI has this method in both
 921  
         // UIComponent and UIComponentBase
 922  0
         Map<String, UIComponent> facets = getFacets();
 923  0
         return facets == null ? 0 : facets.size();
 924  
     }
 925  
 
 926  
     private boolean _isCompositeComponent() {
 927  
         //moved to the static method
 928  0
         return UIComponent.isCompositeComponent(this);
 929  
     }
 930  
     
 931  0
     private static class BundleMap implements Map<String, String> {
 932  
 
 933  
         private ResourceBundle _bundle;
 934  
         private List<String> _values;
 935  
 
 936  0
         public BundleMap(ResourceBundle bundle) {
 937  0
             _bundle = bundle;
 938  0
         }
 939  
 
 940  
         // Optimized methods
 941  
         public String get(Object key) {
 942  
             try {
 943  0
                 return (String) _bundle.getObject(key.toString());
 944  0
             } catch (Exception e) {
 945  0
                 return "???" + key + "???";
 946  
             }
 947  
         }
 948  
 
 949  
         public boolean isEmpty() {
 950  0
             return !_bundle.getKeys().hasMoreElements();
 951  
         }
 952  
 
 953  
         public boolean containsKey(Object key) {
 954  
             try {
 955  0
                 return _bundle.getObject(key.toString()) != null;
 956  0
             } catch (MissingResourceException e) {
 957  0
                 return false;
 958  
             }
 959  
         }
 960  
 
 961  
         // Unoptimized methods
 962  
         public Collection<String> values() {
 963  0
             if (_values == null) {
 964  0
                 _values = new ArrayList<String>();
 965  0
                 for (Enumeration<String> enumer = _bundle.getKeys(); enumer.hasMoreElements();) {
 966  0
                     String v = _bundle.getString(enumer.nextElement());
 967  0
                     _values.add(v);
 968  0
                 }
 969  
             }
 970  0
             return _values;
 971  
         }
 972  
 
 973  
         public int size() {
 974  0
             return values().size();
 975  
         }
 976  
 
 977  
         public boolean containsValue(Object value) {
 978  0
             return values().contains(value);
 979  
         }
 980  
 
 981  
         public Set<Map.Entry<String, String>> entrySet() {
 982  0
             Set<Entry<String, String>> set = new HashSet<Entry<String, String>>();
 983  0
             for (Enumeration<String> enumer = _bundle.getKeys(); enumer.hasMoreElements();) {
 984  0
                 final String k = enumer.nextElement();
 985  0
                 set.add(new Map.Entry<String, String>() {
 986  
 
 987  
                     public String getKey() {
 988  0
                         return k;
 989  
                     }
 990  
 
 991  
                     public String getValue() {
 992  0
                         return (String) _bundle.getObject(k);
 993  
                     }
 994  
 
 995  
                     public String setValue(String value) {
 996  0
                         throw new UnsupportedOperationException();
 997  
                     }
 998  
                 });
 999  0
             }
 1000  
 
 1001  0
             return set;
 1002  
         }
 1003  
 
 1004  
         public Set<String> keySet() {
 1005  0
             Set<String> set = new HashSet<String>();
 1006  0
             for (Enumeration<String> enumer = _bundle.getKeys(); enumer.hasMoreElements();) {
 1007  0
                 set.add(enumer.nextElement());
 1008  
             }
 1009  0
             return set;
 1010  
         }
 1011  
 
 1012  
         // Unsupported methods
 1013  
         public String remove(Object key) {
 1014  0
             throw new UnsupportedOperationException();
 1015  
         }
 1016  
 
 1017  
         public void putAll(Map<? extends String, ? extends String> t) {
 1018  0
             throw new UnsupportedOperationException();
 1019  
         }
 1020  
 
 1021  
         public String put(String key, String value) {
 1022  0
             throw new UnsupportedOperationException();
 1023  
         }
 1024  
 
 1025  
         public void clear() {
 1026  0
             throw new UnsupportedOperationException();
 1027  
         }
 1028  
     }
 1029  
 
 1030  0
     static class EventListenerWrapper implements SystemEventListener, PartialStateHolder {
 1031  
 
 1032  
         private Class<?> componentClass;
 1033  
         private ComponentSystemEventListener listener;
 1034  
         
 1035  
         public EventListenerWrapper()
 1036  
         {
 1037  
             //need a no-arg constructor for state saving purposes
 1038  0
             super();
 1039  0
         }
 1040  
         
 1041  
         /**
 1042  
          * Note we have two cases:
 1043  
          * 
 1044  
          * 1. listener is an instance of UIComponent. In this case we cannot save and restore
 1045  
          *    it because we need to point to the real component, but we can assume the instance
 1046  
          *    is the same because UIComponent.subscribeToEvent says so. Also take into account
 1047  
          *    this case is the reason why we need a wrapper for UIComponent.subscribeToEvent
 1048  
          * 2. listener is an instance of ComponentSystemEventListener but not from UIComponent.
 1049  
          *    In this case, the instance could implement StateHolder, PartialStateHolder or do
 1050  
          *    implement anything, so we have to deal with that case as usual.
 1051  
          * 
 1052  
          * @param component
 1053  
          * @param listener
 1054  
          */
 1055  0
         public EventListenerWrapper(UIComponent component, ComponentSystemEventListener listener) {
 1056  0
             assert component != null;
 1057  0
             assert listener != null;
 1058  
 
 1059  0
             this.componentClass = component.getClass();
 1060  0
             this.listener = listener;
 1061  0
         }
 1062  
 
 1063  
         @Override
 1064  
         public boolean equals(Object o) {
 1065  0
             if (o == this)
 1066  
             {
 1067  0
                 return true;
 1068  
             }
 1069  0
             else if (o instanceof EventListenerWrapper)
 1070  
             {
 1071  0
                 EventListenerWrapper other = (EventListenerWrapper) o;
 1072  0
                 return componentClass.equals(other.componentClass) && listener.equals(other.listener);
 1073  
             } else {
 1074  0
                 return false;
 1075  
             }
 1076  
         }
 1077  
 
 1078  
         @Override
 1079  
         public int hashCode() {
 1080  0
             return componentClass.hashCode() + listener.hashCode();
 1081  
         }
 1082  
 
 1083  
         public boolean isListenerForSource(Object source)
 1084  
         {
 1085  
             // and its implementation of SystemEventListener.isListenerForSource(java.lang.Object) must return true
 1086  
             // if the instance class of this UIComponent is assignable from the argument to isListenerForSource.
 1087  
 
 1088  0
             return source.getClass().isAssignableFrom(componentClass);
 1089  
         }
 1090  
 
 1091  
         public void processEvent(SystemEvent event)
 1092  
         {
 1093  
             // This inner class must call through to the argument componentListener in its implementation of
 1094  
             // SystemEventListener.processEvent(javax.faces.event.SystemEvent)
 1095  
 
 1096  0
             assert event instanceof ComponentSystemEvent;
 1097  
 
 1098  0
             listener.processEvent((ComponentSystemEvent) event);
 1099  0
         }
 1100  
 
 1101  
         public void clearInitialState()
 1102  
         {
 1103  0
             if (!(listener instanceof UIComponent) && listener instanceof PartialStateHolder)
 1104  
             {
 1105  0
                 ((PartialStateHolder)listener).clearInitialState();
 1106  
             }
 1107  0
         }
 1108  
 
 1109  
         public boolean initialStateMarked()
 1110  
         {
 1111  0
             if (!(listener instanceof UIComponent) && listener instanceof PartialStateHolder)
 1112  
             {
 1113  0
                 return ((PartialStateHolder)listener).initialStateMarked();
 1114  
             }
 1115  0
             return false;
 1116  
         }
 1117  
 
 1118  
         public void markInitialState()
 1119  
         {
 1120  0
             if (!(listener instanceof UIComponent) && listener instanceof PartialStateHolder)
 1121  
             {
 1122  0
                 ((PartialStateHolder)listener).markInitialState();
 1123  
             }
 1124  0
         }
 1125  
 
 1126  
         public boolean isTransient()
 1127  
         {
 1128  0
             if (listener instanceof StateHolder)
 1129  
             {
 1130  0
                 return ((StateHolder)listener).isTransient();
 1131  
             }            
 1132  0
             return false;
 1133  
         }
 1134  
 
 1135  
         public void restoreState(FacesContext context, Object state)
 1136  
         {
 1137  0
             if (state == null)
 1138  
             {
 1139  0
                 return;
 1140  
             }
 1141  0
             Object[] values = (Object[]) state;
 1142  0
             componentClass = (Class) values[0];
 1143  0
             if (values[1] instanceof _AttachedDeltaWrapper)
 1144  
             {
 1145  0
                 ((StateHolder)listener).restoreState(context, ((_AttachedDeltaWrapper)values[1]).getWrappedStateObject());
 1146  
             }
 1147  
             else
 1148  
             {
 1149  0
                 listener = values[1] == null ? 
 1150  
                         UIComponent.getCurrentComponent(context) : 
 1151  
                             (ComponentSystemEventListener) UIComponentBase.restoreAttachedState(context, values[1]);
 1152  
             }
 1153  0
         }
 1154  
 
 1155  
         public Object saveState(FacesContext context)
 1156  
         {
 1157  0
             if (!initialStateMarked())
 1158  
             {
 1159  0
                 Object[] state = new Object[2];
 1160  0
                 state[0] = componentClass;
 1161  0
                 if (!(listener instanceof UIComponent))
 1162  
                 {
 1163  0
                     state[1] = UIComponentBase.saveAttachedState(context, listener);
 1164  
                 }
 1165  0
                 return state;
 1166  
             }
 1167  
             else
 1168  
             {
 1169  0
                 Object listenerSaved = ((StateHolder) listener).saveState(context);
 1170  0
                 if (listenerSaved == null)
 1171  
                 {
 1172  0
                     return null;
 1173  
                 }
 1174  0
                 return new Object[]{componentClass, new _AttachedDeltaWrapper(listener.getClass(), listenerSaved)};
 1175  
             }
 1176  
         }
 1177  
 
 1178  
         public void setTransient(boolean newTransientValue)
 1179  
         {
 1180  0
             if (listener instanceof StateHolder)
 1181  
             {
 1182  0
                 ((StateHolder)listener).setTransient(newTransientValue);
 1183  
             }            
 1184  0
         }
 1185  
     }
 1186  
 }