Package javax.faces.component

Source Code of javax.faces.component.UIComponent$EventListenerWrapper

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package javax.faces.component;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.PropertyResourceBundle;
import java.util.ResourceBundle;
import java.util.Set;

import javax.el.ELException;
import javax.el.ValueExpression;
import javax.faces.FacesException;
import javax.faces.application.Resource;
import javax.faces.component.visit.VisitCallback;
import javax.faces.component.visit.VisitContext;
import javax.faces.component.visit.VisitHint;
import javax.faces.component.visit.VisitResult;
import javax.faces.context.FacesContext;
import javax.faces.el.ValueBinding;
import javax.faces.event.AbortProcessingException;
import javax.faces.event.ComponentSystemEvent;
import javax.faces.event.ComponentSystemEventListener;
import javax.faces.event.FacesEvent;
import javax.faces.event.FacesListener;
import javax.faces.event.PostRestoreStateEvent;
import javax.faces.event.SystemEvent;
import javax.faces.event.SystemEventListener;
import javax.faces.event.SystemEventListenerHolder;
import javax.faces.render.Renderer;
import javax.faces.render.RendererWrapper;

import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFComponent;
import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFWebConfigParam;

/**
*
* see Javadoc of <a href="http://java.sun.com/javaee/javaserverfaces/1.2/docs/api/index.html">J
* SF Specification</a>
*/
@JSFComponent(type = "javax.faces.Component", family = "javax.faces.Component",
              desc = "abstract base component", configExcluded = true)
public abstract class UIComponent
        implements PartialStateHolder, TransientStateHolder, SystemEventListenerHolder, ComponentSystemEventListener
{
    // TODO: Reorder methods, this class is a mess
    /**
     * Constant used in component attribute map to retrieve the BeanInfo of a composite
     * component.
     *
     * @see javax.faces.view.ViewDeclarationLanguage#getComponentMetadata(FacesContext, Resource)
     * @see javax.faces.view.ViewDeclarationLanguage#retargetAttachedObjects(FacesContext, UIComponent, List)
     * @see javax.faces.view.ViewDeclarationLanguage#retargetMethodExpressions(FacesContext, UIComponent)
     * @see javax.faces.application.Application#createComponent(FacesContext, Resource)
     */
    public static final String BEANINFO_KEY = "javax.faces.component.BEANINFO_KEY";

    /**
     * Constant used in BeanInfo descriptor as a key for retrieve an alternate component type
     * for create the composite base component.
     *
     * @see javax.faces.application.Application#createComponent(FacesContext, Resource)
     */
    public static final String COMPOSITE_COMPONENT_TYPE_KEY = "javax.faces.component.COMPOSITE_COMPONENT_TYPE";

    /**
     * Constant used to define the facet inside this component that store the component hierarchy
     * generated by a composite component implementation, and then rendered. In other words,
     * note that direct children of a component are not rendered, instead components inside
     * this face are rendered.
     */
    public static final String COMPOSITE_FACET_NAME = "javax.faces.component.COMPOSITE_FACET_NAME";

    /**
     * Constant used to store the current component that is being processed.
     *
     * @see #pushComponentToEL(FacesContext, UIComponent)
     * @see #popComponentFromEL(FacesContext)
     */
    public static final String CURRENT_COMPONENT = "javax.faces.component.CURRENT_COMPONENT";

    /**
     * Constant used to store the current composite component that is being processed.
     *
     * @see #pushComponentToEL(FacesContext, UIComponent)
     * @see #popComponentFromEL(FacesContext)
     */
    public static final String CURRENT_COMPOSITE_COMPONENT = "javax.faces.component.CURRENT_COMPOSITE_COMPONENT";

    /**
     * This constant has two usages. The first one is in component attribute map to identify the
     * facet name under this component is child of its parent. The second one is on BeanInfo descriptor
     * as a key for a Map&lt;String, PropertyDescriptor&gt; that contains metadata information defined
     * by composite:facet tag and composite:implementation(because this one fills the facet referenced
     * by COMPOSITE_FACET_NAME constant).
     */
    public static final String FACETS_KEY = "javax.faces.component.FACETS_KEY";

    /**
     * Constant used in component attribute map to store the {@link javax.faces.view.Location} object
     * where the definition of this component is.
     */
    public static final String VIEW_LOCATION_KEY = "javax.faces.component.VIEW_LOCATION_KEY";

    public static final String ATTRS_WITH_DECLARED_DEFAULT_VALUES
            = "javax.faces.component.ATTR_NAMES_WITH_DEFAULT_VALUES";

    /**
     * Indicate if the facesContext attribute values under the keys javax.faces.component.CURRENT_COMPONENT and
     * javax.faces.component.CURRENT_COMPOSITE_COMPONENT should be valid or not. By default, those keys are
     * deprecated since 2.1
     */
    @JSFWebConfigParam(since = "2.1.0", expectedValues = "true, false", defaultValue = "false")
    public static final String HONOR_CURRENT_COMPONENT_ATTRIBUTES_PARAM_NAME
            = "javax.faces.HONOR_CURRENT_COMPONENT_ATTRIBUTES";

    /**
     * The key under which the component stack is stored in the FacesContext.
     * ATTENTION: this constant is duplicate in CompositeComponentExpressionUtils.
     */
    private static final String _COMPONENT_STACK = "componentStack:" + UIComponent.class.getName();

    private static final String _CURRENT_COMPOSITE_COMPONENT_KEY = "compositeComponent:" + UIComponent.class.getName();

    Map<Class<? extends SystemEvent>, List<SystemEventListener>> _systemEventListenerClassMap;

    /**
     * @deprecated
     */
    @Deprecated
    protected Map<String, ValueExpression> bindings;
    /**
     * Used to cache the map created using getResourceBundleMap() method, since this method could be called several
     * times when rendering the composite component. This attribute may not be serialized, so transient is used (There
     * are some very few special cases when UIComponent instances are serializable like t:schedule, so it is better if
     * transient is used).
     */
    private transient Map<String, String> _resourceBundleMap = null;
    private boolean _inView = false;
    private _DeltaStateHelper _stateHelper = null;

    /**
     * In JSF 2.0 bindings map was deprecated, and replaced with a map
     * inside stateHelper. We need this one here because stateHelper needs
     * to be implemented from here and internally it depends from this property.
     */
    private boolean _initialStateMarked = false;

    /** Value of the {@link UIComponent#HONOR_CURRENT_COMPONENT_ATTRIBUTES_PARAM_NAME} parameter */
    private Boolean _honorCurrentComponentAttributes;

    public UIComponent()
    {
    }

    public abstract Map<String, Object> getAttributes();
   
    /**
     * @since 2.2
     * @return
     */
    public final Map<String,Object> getPassThroughAttributes()
    {
        return getPassThroughAttributes(true);
    }
   
    /**
     * @since 2.2
     * @param create
     * @return
     */
    public abstract Map<String,Object> getPassThroughAttributes(boolean create);

    /**
     *
     * {@inheritDoc}
     *
     * @since 2.0
     */
    public boolean initialStateMarked()
    {
        return _initialStateMarked;
    }

    /**
     * Invokes the <code>invokeContextCallback</code> method with the component, specified by <code>clientId</code>.
     *
     * @param context
     *            <code>FacesContext</code> for the current request
     * @param clientId
     *            the id of the desired <code>UIComponent</code> clazz
     * @param callback
     *            Implementation of the <code>ContextCallback</code> to be called
     * @return has component been found ?
     * @throws javax.faces.FacesException
     */
    public boolean invokeOnComponent(FacesContext context, String clientId, ContextCallback callback)
            throws FacesException
    {
        // java.lang.NullPointerException - if any of the arguments are null
        if (context == null || clientId == null || callback == null)
        {
            throw new NullPointerException();
        }

        pushComponentToEL(context, this);
        try
        {
            // searching for this component?
            boolean found = clientId.equals(this.getClientId(context));
            if (found)
            {
                try
                {
                    callback.invokeContextCallback(context, this);
                }
                catch (Exception e)
                {
                    throw new FacesException(e);
                }
                return found;
            }
            // Searching for this component's children/facets
            // [perf] Use getFacetsAndChildren() is nicer but this one prevents
            // create 1 iterator per component class that does not have
            // facets attached, which is a common case.
            if (this.getFacetCount() > 0)
            {
                for (Iterator<UIComponent> it = this.getFacets().values().iterator(); !found && it.hasNext(); )
                {
                    found = it.next().invokeOnComponent(context, clientId, callback);
                }               
            }
            if (this.getChildCount() > 0)
            {
                for (int i = 0, childCount = getChildCount(); !found && (i < childCount); i++)
                {
                    UIComponent child = getChildren().get(i);
                    found = child.invokeOnComponent(context, clientId, callback);
                }
            }
            return found;
        }
        finally
        {
            //all components must call popComponentFromEl after visiting is finished
            popComponentFromEL(context);
        }
    }

    /**
     *
     * @param component
     * @return true if the component is a composite component otherwise false is returned
     *
     *
     * @throws NullPointerException if the component is null
     * @since 2.0
     */
    public static boolean isCompositeComponent(UIComponent component)
    {

        //since _isCompositeComponent does it the same way we do it here also although I
        //would prefer following method

        //return component.getRendererType().equals("javax.faces.Composite");

        return component.getAttributes().containsKey(Resource.COMPONENT_RESOURCE_KEY);
    }

    /**
     * Indicate if this component is inside a view,
     * or in other words is contained by an UIViewRoot
     * instance (which represents the view). If this component
     * is a UIViewRoot instance, the components "always"
     * is on the view.
     *
     * By default it is false but for UIViewRoot instances is
     * true.
     *
     * @return
     *
     * @since 2.0
     */
    public boolean isInView()
    {
        return _inView;
    }

    public abstract boolean isRendered();

    public void markInitialState()
    {
        _initialStateMarked = true;
    }

    /**
     *
     * This method indicates if a component is visitable
     * according to the hints passed by the VisitContext parameter!
     *
     * This method internally is used by visitTree and if it returns false
     * it short circuits the visitTree execution.
     *
     *
     *
     * @param context
     * @return
     *
     * @since 2.0
     */
    protected boolean isVisitable(VisitContext context)
    {

        Collection<VisitHint> hints = context.getHints();

        if (hints.contains(VisitHint.SKIP_TRANSIENT) && this.isTransient())
        {
            return false;
        }

        if (hints.contains(VisitHint.SKIP_UNRENDERED) && !this.isRendered())
        {
            return false;
        }

        //executable cannot be handled here because we do not have any method to determine
        //whether a component is executable or not, this seems to be a hole in the spec!
        //but we can resolve it on ppr context level, where it is needed!
        //maybe in the long run we can move it down here, if it makes sense

        return true;
    }

    /**
     * @deprecated Replaced by setValueExpression
     */
    public abstract void setValueBinding(String name, ValueBinding binding);

    public void setValueExpression(String name, ValueExpression expression)
    {
        if (name == null)
        {
            throw new NullPointerException("name");
        }
        if (name.equals("id"))
        {
            throw new IllegalArgumentException("Can't set a ValueExpression for the 'id' property.");
        }
        if (name.equals("parent"))
        {
            throw new IllegalArgumentException("Can't set a ValueExpression for the 'parent' property.");
        }

        if (expression == null)
        {
            //if (bindings != null) {
            //    bindings.remove(name);
            //    if (bindings.isEmpty()) {
            //        bindings = null;
            //    }
            //}
            getStateHelper().remove(PropertyKeys.bindings, name);
        }
        else
        {
            if (expression.isLiteralText())
            {
                try
                {
                    Object value = expression.getValue(getFacesContext().getELContext());
                    getAttributes().put(name, value);
                    return;
                }
                catch (ELException e)
                {
                    throw new FacesException(e);
                }
            }

            //if (bindings == null) {
            //    bindings = new HashMap<String, ValueExpression>();
            //}
            //
            //bindings.put(name, expression);
            getStateHelper().put(PropertyKeys.bindings, name, expression);
        }
    }

    public String getClientId()
    {
        return getClientId(getFacesContext());
    }

    public abstract String getClientId(FacesContext context);

    /**
     * search for the nearest parent composite component, if no parent is found
     * it has to return null!
     *
     * if the component itself is null we have to return null as well!
     *
     * @param component the component to start from
     * @return the parent composite component if found otherwise null
     *
     * @since 2.0
     */
    public static UIComponent getCompositeComponentParent(UIComponent component)
    {

        if (component == null)
        {
            return null;
        }
        UIComponent parent = component;

        do
        {
            parent = parent.getParent();
            if (parent != null && UIComponent.isCompositeComponent(parent))
            {
                return parent;
            }
        } while (parent != null);
        return null;
    }

    /**
     * @since 1.2
     */
    public String getContainerClientId(FacesContext ctx)
    {
        if (ctx == null)
        {
            throw new NullPointerException("FacesContext ctx");
        }

        return getClientId(ctx);
    }

    /**
     *
     * @param context
     * @return
     *
     * @since 2.0
     */
    public static UIComponent getCurrentComponent(FacesContext context)
    {
        Boolean honorCurrentComponentAttributes = null;

        if (context.getViewRoot() != null)
        {
            honorCurrentComponentAttributes = ((UIComponent)context.getViewRoot())._honorCurrentComponentAttributes;
            if (honorCurrentComponentAttributes == null)
            {
                honorCurrentComponentAttributes = _getHonorCurrentComponentAttributes(context);
            }
        }
        else
        {
            honorCurrentComponentAttributes = _getHonorCurrentComponentAttributes(context);
        }

        if (Boolean.TRUE.equals(honorCurrentComponentAttributes))
        {
            return (UIComponent) context.getAttributes().get(UIComponent.CURRENT_COMPONENT);
        }
        else
        {
            List<UIComponent> componentStack
                    = (List<UIComponent>) context.getAttributes().get(UIComponent._COMPONENT_STACK);
            if (componentStack == null)
            {
                return null;
            }
            else
            {
                if (componentStack.size() > 0)
                {
                    return componentStack.get(componentStack.size()-1);
                }
                else
                {
                    return null;
                }
            }
        }
    }

    /**
     *
     * @param context
     * @return
     *
     * @since 2.0
     */
    public static UIComponent getCurrentCompositeComponent(FacesContext context)
    {
        Boolean honorCurrentComponentAttributes = null;

        if (context.getViewRoot() != null)
        {
            honorCurrentComponentAttributes = ((UIComponent)context.getViewRoot())._honorCurrentComponentAttributes;
            if (honorCurrentComponentAttributes == null)
            {
                honorCurrentComponentAttributes = _getHonorCurrentComponentAttributes(context);
            }
        }
        else
        {
            honorCurrentComponentAttributes = _getHonorCurrentComponentAttributes(context);
        }

        if (Boolean.TRUE.equals(honorCurrentComponentAttributes))
        {
            return (UIComponent) context.getAttributes().get(UIComponent.CURRENT_COMPOSITE_COMPONENT);
        }
        else
        {
            return (UIComponent) context.getAttributes().get(UIComponent._CURRENT_COMPOSITE_COMPONENT_KEY);
        }
    }

    public abstract String getFamily();

    public abstract String getId();

    public List<SystemEventListener> getListenersForEventClass(Class<? extends SystemEvent> eventClass)
    {
        List<SystemEventListener> listeners;
        if (_systemEventListenerClassMap == null)
        {
            listeners = Collections.emptyList();
        }
        else
        {
            listeners = _systemEventListenerClassMap.get(eventClass);
            if (listeners == null)
            {
                listeners = Collections.emptyList();
            }
            else
            {
                listeners = Collections.unmodifiableList(listeners);
            }
        }

        return listeners;
    }

    /**
     *
     * @return
     *
     * @since 2.0
     */
    public UIComponent getNamingContainer()
    {
        // Starting with "this", return the closest component in the ancestry that is a NamingContainer
        // or null if none can be found.
        UIComponent component = this;
        do
        {
            if (component instanceof NamingContainer)
            {
                return component;
            }

            component = component.getParent();
        } while (component != null);

        return null;
    }

    public abstract void setId(String id);

    /**
     * Define if the component is on the view or not.
     * <p>
     * This value is set in the following conditions:
     * </p>
     * <ul>
     * <li>Component / Facet added: if the parent isInView = true,
     *     set it to true and all their children or facets,
     *     otherwise take no action</li>
     * <li>Component / Facet removed: if the parent isInView = false,
     *     set it to false and all their children or facets,
     *     otherwise take no action</li>
     * <ul>
     * @param isInView
     *
     * @since 2.0
     */
    public void setInView(boolean isInView)
    {
        _inView = isInView;
    }

    /**
     * For JSF-framework internal use only. Don't call this method to add components to the component tree. Use
     * <code>parent.getChildren().add(child)</code> instead.
     */
    public abstract void setParent(UIComponent parent);

    /**
     * Returns the parent of the component. Children can be added to or removed from a component even if this method
     * returns null for the child.
     */
    public abstract UIComponent getParent();

    public abstract void setRendered(boolean rendered);

    public abstract String getRendererType();

    public abstract void setRendererType(String rendererType);

    public abstract boolean getRendersChildren();

    public Map<String, String> getResourceBundleMap()
    {
        if (_resourceBundleMap == null)
        {
            FacesContext context = getFacesContext();
            Locale locale = context.getViewRoot().getLocale();
            ClassLoader loader = _ClassUtils.getContextClassLoader();

            try
            {
                // looks for a ResourceBundle with a base name equal to the fully qualified class
                // name of the current UIComponent this and Locale equal to the Locale of the current UIViewRoot.
                _resourceBundleMap = new BundleMap(ResourceBundle.getBundle(getClass().getName(), locale, loader));
            }
            catch (MissingResourceException e)
            {
                // If no such bundle is found, and the component is a composite component
                if (this._isCompositeComponent())
                {
                    // No need to check componentResource (the resource used to build the composite
                    // component instance) to null since it is already done on this._isCompositeComponent()
                    Resource componentResource = (Resource) getAttributes().get(Resource.COMPONENT_RESOURCE_KEY);
                    // Let resourceName be the resourceName of the Resource for this composite component,
                    // replacing the file extension with ".properties"
                    int extensionIndex = componentResource.getResourceName().lastIndexOf('.');
                    String resourceName = (extensionIndex < 0
                            ? componentResource.getResourceName()
                            : componentResource.getResourceName().substring(0, extensionIndex)) + ".properties";

                    // Let libraryName be the libraryName of the the Resource for this composite component.
                    // Call ResourceHandler.createResource(java.lang.String,java.lang.String), passing the derived
                    // resourceName and
                    // libraryName.
                    Resource bundleResource = context.getApplication().getResourceHandler()
                            .createResource(resourceName, componentResource.getLibraryName());

                    if (bundleResource != null)
                    {
                        // If the resultant Resource exists and can be found, the InputStream for the resource
                        // is used to create a ResourceBundle. If either of the two previous steps for obtaining the
                        // ResourceBundle
                        // for this component is successful, the ResourceBundle is wrapped in a Map<String, String> and
                        // returned.
                        try
                        {
                            _resourceBundleMap
                                    = new BundleMap(new PropertyResourceBundle(bundleResource.getInputStream()));
                        }
                        catch (IOException e1)
                        {
                            // Nothing happens, then resourceBundleMap is set as empty map
                        }
                    }
                }
                // Otherwise Collections.EMPTY_MAP is returned.
                if (_resourceBundleMap == null)
                {
                    _resourceBundleMap = Collections.emptyMap();
                }
            }
        }

        return _resourceBundleMap;
    }

    /**
     * @deprecated Replaced by getValueExpression
     */
    public abstract ValueBinding getValueBinding(String name);

    public ValueExpression getValueExpression(String name)
    {
        if (name == null)
        {
            throw new NullPointerException("name can not be null");
        }

        Map<String, Object> bindings = (Map<String, Object>) getStateHelper().
                get(PropertyKeys.bindings);

        if (bindings == null)
        {
            if (!(this instanceof UIComponentBase))
            {
                // if the component does not inherit from UIComponentBase and don't implements JSF 1.2 or later
                ValueBinding vb = getValueBinding(name);
                if (vb != null)
                {
                    //bindings = new HashMap<String, ValueExpression>();
                    ValueExpression ve = new _ValueBindingToValueExpression(vb);
                    getStateHelper().put(PropertyKeys.bindings, name, ve);
                    return ve;
                }
            }
        }
        else
        {
            //return bindings.get(name);
            return (ValueExpression) bindings.get(name);
        }
        return null;
    }

    public abstract List<UIComponent> getChildren();

    public abstract int getChildCount();

    public abstract UIComponent findComponent(String expr);

    public abstract Map<String, UIComponent> getFacets();

    public abstract UIComponent getFacet(String name);

    public abstract Iterator<UIComponent> getFacetsAndChildren();

    public abstract void broadcast(FacesEvent event) throws AbortProcessingException;

    /**
     * {@inheritDoc}
     *
     * @since 2.0
     */
    public void clearInitialState()
    {
        _initialStateMarked = false;
    }

    public abstract void decode(FacesContext context);

    public abstract void encodeBegin(FacesContext context) throws IOException;

    public abstract void encodeChildren(FacesContext context) throws IOException;

    public abstract void encodeEnd(FacesContext context) throws IOException;

    public void encodeAll(FacesContext context) throws IOException
    {
        if (context == null)
        {
            throw new NullPointerException();
        }

        pushComponentToEL(context, this);
        try
        {
            if (!isRendered())
            {
                return;
            }
        }
        finally
        {
            popComponentFromEL(context);
        }

        //if (isRendered()) {
        this.encodeBegin(context);

        // rendering children
        if (this.getRendersChildren())
        {
            this.encodeChildren(context);
        } // let children render itself
        else
        {
            if (this.getChildCount() > 0)
            {
                for (int i = 0; i < this.getChildCount(); i++)
                {
                    UIComponent comp = this.getChildren().get(i);
                    comp.encodeAll(context);
                }
            }
        }
        this.encodeEnd(context);
        //}
    }

    protected abstract void addFacesListener(FacesListener listener);

    protected abstract FacesListener[] getFacesListeners(Class clazz);

    protected abstract void removeFacesListener(FacesListener listener);

    public abstract void queueEvent(FacesEvent event);

    public abstract void processRestoreState(FacesContext context, Object state);

    public abstract void processDecodes(FacesContext context);

    public void processEvent(ComponentSystemEvent event) throws AbortProcessingException
    {
        // The default implementation performs the following action. If the argument event is an instance of
        // AfterRestoreStateEvent,
        if (event instanceof PostRestoreStateEvent)
        {

            // call this.getValueExpression(java.lang.String) passing the literal string "binding"
            ValueExpression expression = getValueExpression("binding");

            // If the result is non-null, set the value of the ValueExpression to be this.
            if (expression != null)
            {
                expression.setValue(getFacesContext().getELContext(), this);
            }

            //we issue a PostRestoreStateEvent
            //we issue it here because the spec clearly states what UIComponent is allowed to do
            //the main issue is that the spec does not say anything about a global dispatch on this level
            //but a quick blackbox test against the ri revealed that the event clearly is dispatched
            //at restore level for every component so we either issue it here or in UIViewRoot and/or the facelet
            // and jsp restore state triggers, a central point is preferrble so we do it here
            //TODO ask the EG the spec clearly contradicts blackbox RI behavior here

            //getFacesContext().getApplication().publishEvent(getFacesContext(),
            // PostRestoreStateEvent.class, UIComponent.class, this);
           
            // JSF 2.2 vdl.createComponent() requires special handling to refresh
            // dynamic parts when refreshing is done. The only way to do it is
            // attaching a listener to PostRestoreStateEvent, so we need to do this
            // invocation here.
            // Do it inside UIComponent.processEvent() is better because in facelets
            // UILeaf we can skip this part just overriding the method.
           
            List<SystemEventListener> listeners = this.getListenersForEventClass(
                PostRestoreStateEvent.class);
            if (!listeners.isEmpty())
            {
                for (int i  = 0, size = listeners.size(); i < size; i++)
                {
                    SystemEventListener listener = listeners.get(i);
                    if (listener.isListenerForSource(this))
                    {
                        // Check if the listener points again to the component, to
                        // avoid StackoverflowException
                        boolean shouldProcessEvent = true;
                        if (listener instanceof EventListenerWrapper &&
                            ((EventListenerWrapper)listener).listenerCapability ==
                                EventListenerWrapper.LISTENER_TYPE_COMPONENT)
                        {
                            shouldProcessEvent = false;
                        }
                        if (shouldProcessEvent)
                        {
                            listener.processEvent(event);
                        }
                    }
                }
            }
        }
    }

    public abstract void processValidators(FacesContext context);

    public abstract void processUpdates(FacesContext context);

    public abstract java.lang.Object processSaveState(FacesContext context);

    public void subscribeToEvent(Class<? extends SystemEvent> eventClass,
                                 ComponentSystemEventListener componentListener)
    {
        // The default implementation creates an inner SystemEventListener instance that wraps argument
        // componentListener as the listener argument.
        if (eventClass == null)
        {
            throw new NullPointerException("eventClass required");
        }
        if (componentListener == null)
        {
            throw new NullPointerException("componentListener required");
        }

        SystemEventListener listener = new EventListenerWrapper(this, componentListener);

        // Make sure the map exists
        if (_systemEventListenerClassMap == null)
        {
            _systemEventListenerClassMap = new HashMap<Class<? extends SystemEvent>, List<SystemEventListener>>();
        }

        List<SystemEventListener> listeners = _systemEventListenerClassMap.get(eventClass);
        // Make sure the list for class exists
        if (listeners == null)
        {
            // how many listeners per event type can single component have?
            // We use 3 here as expected number, but it is a question
            listeners = new _DeltaList<SystemEventListener>(new ArrayList<SystemEventListener>(3));
            _systemEventListenerClassMap.put(eventClass, listeners);
        }

        // Deal with contains? Spec is silent
        listeners.add(listener);
    }

    public void unsubscribeFromEvent(Class<? extends SystemEvent> eventClass,
                                     ComponentSystemEventListener componentListener)
    {
        /*
         * When doing the comparison to determine if an existing listener is equal to the argument componentListener
         * (and thus must be removed), the equals() method on the existing listener must be invoked, passing the
         * argument componentListener, rather than the other way around.
         *
         * -=Simon Lessard=- What is that supposed to mean? Are we supposed to keep
         * an internal map of created listener wrappers?
         * -= Leonardo Uribe=- Yes, it is supposed a wrapper should be used to hold listener references, to prevent
         * serialize component instances on the state.
         */
        if (eventClass == null)
        {
            throw new NullPointerException("eventClass required");
        }
        if (componentListener == null)
        {
            throw new NullPointerException("componentListener required");
        }

        if (_systemEventListenerClassMap != null)
        {
            List<SystemEventListener> listeners = _systemEventListenerClassMap.get(eventClass);

            if (listeners != null && !listeners.isEmpty())
            {
                for (Iterator<SystemEventListener> it = listeners.iterator(); it.hasNext(); )
                {
                    ComponentSystemEventListener listener
                            = ((EventListenerWrapper) it.next()).getComponentSystemEventListener();
                    if (listener != null && listener.equals(componentListener))
                    {
                        it.remove();
                        break;
                    }
                }
            }
        }
    }

    /**
     * The visit tree method, visit tree walks over a subtree and processes
     * the callback object to perform some operation on the subtree
     * <p>
     * there are some details in the implementation which according to the spec have
     * to be in place:
     * a) before calling the callback and traversing into the subtree  pushComponentToEL
     * has to be called
     * b) after the processing popComponentFromEL has to be performed to remove the component
     * from the el
     * </p>
     * <p>
     * The tree traversal optimizations are located in the visit context and can be replaced
     * via the VisitContextFactory in the faces-config factory section
     * </p>
     *
     * @param context the visit context which handles the processing details
     * @param callback the callback to be performed
     * @return false if the processing is not done true if we can shortcut
     * the visiting because we are done with everything
     *
     * @since 2.0
     */
    public boolean visitTree(VisitContext context, VisitCallback callback)
    {
        try
        {
            pushComponentToEL(context.getFacesContext(), this);

            if (!isVisitable(context))
            {
                return false;
            }

            VisitResult res = context.invokeVisitCallback(this, callback);
            switch (res)
            {
                //we are done nothing has to be processed anymore
                case COMPLETE:
                    return true;

                case REJECT:
                    return false;

                //accept
                default:
                    if (getFacetCount() > 0)
                    {
                        for (UIComponent facet : getFacets().values())
                        {
                            if (facet.visitTree(context, callback))
                            {
                                return true;
                            }
                        }
                    }
                    int childCount = getChildCount();
                    if (childCount > 0)
                    {
                        for (int i = 0; i < childCount; i++)
                        {
                            UIComponent child = getChildren().get(i);
                            if (child.visitTree(context, callback))
                            {
                                return true;
                            }
                        }
                    }
                    return false;
            }
        }
        finally
        {
            //all components must call popComponentFromEl after visiting is finished
            popComponentFromEL(context.getFacesContext());
        }
    }

    protected abstract FacesContext getFacesContext();

    protected abstract Renderer getRenderer(FacesContext context);

    /**
     * Note that id, clientId properties
     * never change its value after the component is populated,
     * so we don't need to store it on StateHelper or restore it when
     * initialStateMarked == true
     * (Note that rendererType is suspicious, in theory this field is
     * initialized on constructor, but on 1.1 and 1.2 is saved and restored,
     * so to keep backward behavior we put it on StateHelper )
     *
     * Also, facesListeners can't be wrapped on StateHelper because it
     * needs to handle PartialStateHolder instances when it is saved and
     * restored and this interface does not implement PartialStateHolder,
     * so we can't propagate calls to markInitialState and clearInitialState,
     * in other words, the List wrapped by StateHelper does not handle
     * PartialStateHolder items.
     *
     * "bindings" map does not need to deal with PartialStateHolder instances,
     *  so we can use StateHelper feature (handle delta for this map or in
     *  other words track add/removal from bindings map as delta).
     */
    enum PropertyKeys
    {
        rendered,
        rendererType,
        attributesMap,
        bindings,
        facesListeners,
        passThroughAttributesMap
    }

    protected StateHelper getStateHelper()
    {
        return getStateHelper(true);
    }

    /**
     * returns a delta state saving enabled state helper
     * for the current component
     * @param create if true a state helper is created if not already existing
     * @return an implementation of the StateHelper interface or null if none exists and create is set to false
     */
    protected StateHelper getStateHelper(boolean create)
    {
        if (_stateHelper != null)
        {
            return _stateHelper;
        }
        if (create)
        {
            _stateHelper = new _DeltaStateHelper(this);
        }
        return _stateHelper;
    }

    public final TransientStateHelper getTransientStateHelper()
    {
        return getTransientStateHelper(true);
    }

    public TransientStateHelper getTransientStateHelper(boolean create)
    {
        if (_stateHelper != null)
        {
            return _stateHelper;
        }
        if (create)
        {
            _stateHelper = new _DeltaStateHelper(this);
        }
        return _stateHelper;
    }

    public void restoreTransientState(FacesContext context, Object state)
    {
        getTransientStateHelper().restoreTransientState(context, state);
    }

    public Object saveTransientState(FacesContext context)
    {
        return getTransientStateHelper().saveTransientState(context);
    }

    @SuppressWarnings("unchecked")
    public final void popComponentFromEL(FacesContext context)
    {
        Map<Object, Object> contextAttributes = context.getAttributes();

        if (_honorCurrentComponentAttributes == null)
        {
            _honorCurrentComponentAttributes = _getHonorCurrentComponentAttributes(context);
        }

        if (Boolean.TRUE.equals(_honorCurrentComponentAttributes))
        {
            // Pop the current UIComponent from the FacesContext attributes map so that the previous
            // UIComponent, if any, becomes the current component.
            List<UIComponent> componentStack
                    = (List<UIComponent>) contextAttributes.get(UIComponent._COMPONENT_STACK);

            UIComponent oldCurrent = (UIComponent) contextAttributes.get(UIComponent.CURRENT_COMPONENT);

            UIComponent newCurrent = null;
            if (componentStack != null && !componentStack.isEmpty())
            {
                if (!this.equals(oldCurrent))
                {
                    //Check on the componentStack if it can be found
                    int componentIndex = componentStack.lastIndexOf(this);
                    if (componentIndex >= 0)
                    {
                        //for (int i = 0; i < (componentIndex + 1); i++)
                        for (int i = componentStack.size()-1; i >= componentIndex ; i--)
                        {
                            newCurrent = componentStack.remove(componentStack.size()-1);
                        }
                    }
                    else
                    {
                        //Component not found on the stack. Do not pop.
                        return;
                    }
                }
                else
                {
                    newCurrent = componentStack.remove(componentStack.size()-1);
                }
            }
            else
            {
                //Reset the current composite component
                contextAttributes.put(UIComponent.CURRENT_COMPOSITE_COMPONENT, null);
            }
            oldCurrent = (UIComponent) contextAttributes.put(UIComponent.CURRENT_COMPONENT, newCurrent);

            if (oldCurrent != null && oldCurrent._isCompositeComponent() && newCurrent != null)
            {
                // Recalculate the current composite component
                if (newCurrent._isCompositeComponent())
                {
                    contextAttributes.put(UIComponent.CURRENT_COMPOSITE_COMPONENT, newCurrent);
                }
                else
                {
                    UIComponent previousCompositeComponent = null;
                    for (int i = componentStack.size()-1; i >= 0; i--)
                    {
                        UIComponent component = componentStack.get(i);
                        if (component._isCompositeComponent())
                        {
                            previousCompositeComponent = component;
                            break;
                        }
                    }
                    contextAttributes.put(UIComponent.CURRENT_COMPOSITE_COMPONENT, previousCompositeComponent);
                }
            }
        }
        else
        {
            // Pop the current UIComponent from the FacesContext attributes map so that the previous
            // UIComponent, if any, becomes the current component.
            List<UIComponent> componentStack
                    = (List<UIComponent>) contextAttributes.get(UIComponent._COMPONENT_STACK);

            UIComponent oldCurrent = null;
            if (componentStack != null && !componentStack.isEmpty())
            {
                int componentIndex = componentStack.lastIndexOf(this);
                if (componentIndex >= 0)
                {
                    for (int i = componentStack.size()-1; i >= componentIndex ; i--)
                    {
                        oldCurrent = componentStack.remove(componentStack.size()-1);
                    }
                }
                else
                {
                    return;
                }
            }

            if (oldCurrent != null && oldCurrent._isCompositeComponent())
            {
                // Recalculate the current composite component
                UIComponent previousCompositeComponent = null;
                for (int i = componentStack.size()-1; i >= 0; i--)
                {
                    UIComponent component = componentStack.get(i);
                    if (component._isCompositeComponent())
                    {
                        previousCompositeComponent = component;
                        break;
                    }
                }
                contextAttributes.put(UIComponent._CURRENT_COMPOSITE_COMPONENT_KEY, previousCompositeComponent);
            }
        }
    }

    @SuppressWarnings("unchecked")
    public final void pushComponentToEL(FacesContext context, UIComponent component)
    {
        if (component == null)
        {
            component = this;
        }

        Map<Object, Object> contextAttributes = context.getAttributes();

        if (_honorCurrentComponentAttributes == null)
        {
            _honorCurrentComponentAttributes = _getHonorCurrentComponentAttributes(context);
        }

        if (Boolean.TRUE.equals(_honorCurrentComponentAttributes))
        {
            UIComponent currentComponent = (UIComponent) contextAttributes.get(UIComponent.CURRENT_COMPONENT);

            if (currentComponent != null)
            {
                List<UIComponent> componentStack
                        = (List<UIComponent>) contextAttributes.get(UIComponent._COMPONENT_STACK);
                if (componentStack == null)
                {
                    componentStack = new ArrayList<UIComponent>();
                    contextAttributes.put(UIComponent._COMPONENT_STACK, componentStack);
                }

                componentStack.add(currentComponent);
            }

            // Push the current UIComponent this to the FacesContext  attribute map using the key CURRENT_COMPONENT
            // saving the previous UIComponent associated with CURRENT_COMPONENT for a subsequent call to
            // popComponentFromEL(javax.faces.context.FacesContext).
            contextAttributes.put(UIComponent.CURRENT_COMPONENT, component);

            if (component._isCompositeComponent())
            {
                contextAttributes.put(UIComponent.CURRENT_COMPOSITE_COMPONENT, component);
            }
        }
        else
        {
            List<UIComponent> componentStack
                    = (List<UIComponent>) contextAttributes.get(UIComponent._COMPONENT_STACK);
            if (componentStack == null)
            {
                componentStack = new ArrayList<UIComponent>();
                contextAttributes.put(UIComponent._COMPONENT_STACK, componentStack);
            }
            componentStack.add(component);
            if (component._isCompositeComponent())
            {
                contextAttributes.put(UIComponent._CURRENT_COMPOSITE_COMPONENT_KEY, component);
            }
        }
    }

    /**
     * @since 1.2
     */
    public int getFacetCount()
    {
        // not sure why the RI has this method in both
        // UIComponent and UIComponentBase
        Map<String, UIComponent> facets = getFacets();
        return facets == null ? 0 : facets.size();
    }

    private boolean _isCompositeComponent()
    {
        //moved to the static method
        return UIComponent.isCompositeComponent(this);
    }
   
    boolean isCachedFacesContext()
    {
        return false;
    }

    // Dummy method to prevent cast for UIComponentBase when caching
    void setCachedFacesContext(FacesContext facesContext)
    {
    }

    /**
     * Gets value of "javax.faces.HONOR_CURRENT_COMPONENT_ATTRIBUTES" parameter cached in facesContext.attributes
     * or resolves that param and caches its value in facesContext.attributes.   
     *
     * @return canonical Boolean value for parameter "javax.faces.HONOR_CURRENT_COMPONENT_ATTRIBUTES"
     */
    private static Boolean _getHonorCurrentComponentAttributes(FacesContext facesContext)
    {
        // performance note: we cache value in facesContext.attributes because
        // 1) methods pushComponentToEL, popComponentFromEl, getCurrentComponent a getCurrentCompositeComponent
        // can use that value
        // 2) getExternalContext().getInitParameter has undetermined performance. In typical JSF app, there
        // are one or two wrappers around external context; servletContext.getInitParameter has also unknown
        // implementation and performance
        Map<Object, Object> attributes = facesContext.getAttributes();
        Boolean paramValue = (Boolean) attributes.get(HONOR_CURRENT_COMPONENT_ATTRIBUTES_PARAM_NAME);
        if (paramValue == null)
        {
            String param
                    = facesContext.getExternalContext().getInitParameter(HONOR_CURRENT_COMPONENT_ATTRIBUTES_PARAM_NAME);
            paramValue = Boolean.valueOf((param != null && Boolean.valueOf(param).booleanValue()));
            attributes.put(HONOR_CURRENT_COMPONENT_ATTRIBUTES_PARAM_NAME, paramValue);
        }
        return paramValue;
    }

    private static class BundleMap implements Map<String, String>
    {

        private ResourceBundle _bundle;
        private List<String> _values;

        public BundleMap(ResourceBundle bundle)
        {
            _bundle = bundle;
        }

        // Optimized methods
        public String get(Object key)
        {
            try
            {
                return (String) _bundle.getObject(key.toString());
            }
            catch (Exception e)
            {
                return "???" + key + "???";
            }
        }

        public boolean isEmpty()
        {
            return !_bundle.getKeys().hasMoreElements();
        }

        public boolean containsKey(Object key)
        {
            try
            {
                return _bundle.getObject(key.toString()) != null;
            }
            catch (MissingResourceException e)
            {
                return false;
            }
        }

        // Unoptimized methods
        public Collection<String> values()
        {
            if (_values == null)
            {
                _values = new ArrayList<String>();
                for (Enumeration<String> enumer = _bundle.getKeys(); enumer.hasMoreElements(); )
                {
                    String v = _bundle.getString(enumer.nextElement());
                    _values.add(v);
                }
            }
            return _values;
        }

        public int size()
        {
            return values().size();
        }

        public boolean containsValue(Object value)
        {
            return values().contains(value);
        }

        public Set<Map.Entry<String, String>> entrySet()
        {
            Set<Entry<String, String>> set = new HashSet<Entry<String, String>>();
            for (Enumeration<String> enumer = _bundle.getKeys(); enumer.hasMoreElements(); )
            {
                final String k = enumer.nextElement();
                set.add(new Map.Entry<String, String>()
                {

                    public String getKey()
                    {
                        return k;
                    }

                    public String getValue()
                    {
                        return (String) _bundle.getObject(k);
                    }

                    public String setValue(String value)
                    {
                        throw new UnsupportedOperationException();
                    }
                });
            }

            return set;
        }

        public Set<String> keySet()
        {
            Set<String> set = new HashSet<String>();
            for (Enumeration<String> enumer = _bundle.getKeys(); enumer.hasMoreElements(); )
            {
                set.add(enumer.nextElement());
            }
            return set;
        }

        // Unsupported methods
        public String remove(Object key)
        {
            throw new UnsupportedOperationException();
        }

        public void putAll(Map<? extends String, ? extends String> t)
        {
            throw new UnsupportedOperationException();
        }

        public String put(String key, String value)
        {
            throw new UnsupportedOperationException();
        }

        public void clear()
        {
            throw new UnsupportedOperationException();
        }
    }

    static class EventListenerWrapper implements SystemEventListener, PartialStateHolder
    {

        private Class<?> componentClass;
        private ComponentSystemEventListener listener;

        private boolean _initialStateMarked;

        private int listenerCapability;
        private transient UIComponent _component;

        private static final int LISTENER_SAVE_STATE_HOLDER = 1;
        private static final int LISTENER_SAVE_PARTIAL_STATE_HOLDER = 2;
        private static final int LISTENER_TYPE_COMPONENT = 4;
        private static final int LISTENER_TYPE_RENDERER = 8;
        private static final int LISTENER_TYPE_OTHER = 16;

        public EventListenerWrapper()
        {
            //need a no-arg constructor for state saving purposes
            super();
        }

        /**
         * Note we have two cases:
         *
         * 1. listener is an instance of UIComponent. In this case we cannot save and restore
         *    it because we need to point to the real component, but we can assume the instance
         *    is the same because UIComponent.subscribeToEvent says so. Also take into account
         *    this case is the reason why we need a wrapper for UIComponent.subscribeToEvent
         * 2. listener is an instance of Renderer. In this case we can assume the same renderer
         *    used by the source component is the one used by the listener (ListenerFor).
         * 3. listener is an instance of ComponentSystemEventListener but not from UIComponent.
         *    In this case, the instance could implement StateHolder, PartialStateHolder or do
         *    implement anything, so we have to deal with that case as usual.
         *
         * @param component
         * @param listener
         */
        public EventListenerWrapper(UIComponent component, ComponentSystemEventListener listener)
        {
            assert component != null;
            assert listener != null;

            this.componentClass = component.getClass();
            this.listener = listener;
            this._component = component;
            initListenerCapability();
        }

        private void initListenerCapability()
        {
            this.listenerCapability = 0;
            if (this.listener instanceof UIComponent)
            {
                this.listenerCapability = LISTENER_TYPE_COMPONENT;
            }
            else if (this.listener instanceof Renderer)
            {
                this.listenerCapability = LISTENER_TYPE_RENDERER;
            }
            else
            {
                if (this.listener instanceof PartialStateHolder)
                {
                    this.listenerCapability = LISTENER_TYPE_OTHER | LISTENER_SAVE_PARTIAL_STATE_HOLDER;
                }
                else if (this.listener instanceof StateHolder)
                {
                    this.listenerCapability = LISTENER_TYPE_OTHER | LISTENER_SAVE_STATE_HOLDER;
                }
                else
                {
                    this.listenerCapability = LISTENER_TYPE_OTHER;
                }
            }
        }

        @Override
        public boolean equals(Object o)
        {
            if (o == this)
            {
                return true;
            }
            else if (o instanceof EventListenerWrapper)
            {
                EventListenerWrapper other = (EventListenerWrapper) o;
                return componentClass.equals(other.componentClass) && listener.equals(other.listener);
            }
            else
            {
                return false;
            }
        }

        @Override
        public int hashCode()
        {
            return componentClass.hashCode() + listener.hashCode();
        }

        public boolean isListenerForSource(Object source)
        {
            // and its implementation of SystemEventListener.isListenerForSource(java.lang.Object) must return true
            // if the instance class of this UIComponent is assignable from the argument to isListenerForSource.

            return source.getClass().isAssignableFrom(componentClass);
        }

        public ComponentSystemEventListener getComponentSystemEventListener()
        {
            return listener;
        }

        public void processEvent(SystemEvent event)
        {
            // This inner class must call through to the argument componentListener in its implementation of
            // SystemEventListener.processEvent(javax.faces.event.SystemEvent)

            assert event instanceof ComponentSystemEvent;

            listener.processEvent((ComponentSystemEvent) event);
        }

        public void clearInitialState()
        {
            //if (!(listener instanceof UIComponent) && listener instanceof PartialStateHolder)
            if ((listenerCapability & LISTENER_SAVE_PARTIAL_STATE_HOLDER) != 0)
            {
                ((PartialStateHolder) listener).clearInitialState();
            }
            _initialStateMarked = false;
        }

        public boolean initialStateMarked()
        {
            //if (!(listener instanceof UIComponent) && listener instanceof PartialStateHolder)
            if ((listenerCapability & LISTENER_SAVE_PARTIAL_STATE_HOLDER) != 0)
            {
                return ((PartialStateHolder) listener).initialStateMarked();
            }
            //return false;
            return _initialStateMarked;
        }

        public void markInitialState()
        {
            //if (!(listener instanceof UIComponent) && listener instanceof PartialStateHolder)
            if ((listenerCapability & LISTENER_SAVE_PARTIAL_STATE_HOLDER) != 0)
            {
                ((PartialStateHolder) listener).markInitialState();
            }
            _initialStateMarked = true;
        }

        public boolean isTransient()
        {
            //if ( listener instanceof StateHolder)
            if ((listenerCapability & LISTENER_SAVE_PARTIAL_STATE_HOLDER) != 0 ||
                    (listenerCapability & LISTENER_SAVE_STATE_HOLDER) != 0)
            {
                return ((StateHolder) listener).isTransient();
            }
            return false;
        }

        public void restoreState(FacesContext context, Object state)
        {
            if (state == null)
            {
                return;
            }
            Object[] values = (Object[]) state;
            componentClass = (Class) values[0];
            if (values[1] instanceof _AttachedDeltaWrapper)
            {
                ((StateHolder) listener).restoreState(context,
                        ((_AttachedDeltaWrapper) values[1]).getWrappedStateObject());
            }
            else
            {
                //Full restore
                listenerCapability = (Integer) values[2];

                _component = UIComponent.getCurrentComponent(context);
                if ((listenerCapability & LISTENER_TYPE_COMPONENT) != 0)
                {
                    listener = _component;
                }
                else if ((listenerCapability & LISTENER_TYPE_RENDERER) != 0)
                {
                    //listener = (ComponentSystemEventListener)
                    //        UIComponent.getCurrentComponent(context).getRenderer(context);
                    Renderer renderer = _component.getRenderer(context);
                    Integer i = (Integer) values[1];
                    if (i != null && i >= 0)
                    {
                        while (i > 0)
                        {
                            renderer = ((RendererWrapper) renderer).getWrapped();
                            i--;
                        }
                    }
                    listener = (ComponentSystemEventListener) renderer;
                }
                else
                {
                    listener = (ComponentSystemEventListener)
                            UIComponentBase.restoreAttachedState(context, values[1]);
                }
                /*
                listener = values[1] == null ?
                        UIComponent.getCurrentComponent(context) :
                            (ComponentSystemEventListener) UIComponentBase.restoreAttachedState(context, values[1]);
                            */
            }
        }

        public Object saveState(FacesContext context)
        {
            if (!initialStateMarked())
            {
                /*
                Object[] state = new Object[2];
                state[0] = componentClass;
                if (!(listener instanceof UIComponent))
                {
                    state[1] = UIComponentBase.saveAttachedState(context, listener);
                }
                return state;
                */
                Object[] state = new Object[3];
                state[0] = componentClass;
                //If this is not a component or a renderer, save it calling UIComponent.saveAttachedState
                if (!((listenerCapability & LISTENER_TYPE_COMPONENT) != 0 ||
                        (listenerCapability & LISTENER_TYPE_RENDERER) != 0))
                {
                    state[1] = UIComponentBase.saveAttachedState(context, listener);
                }
                else
                {
                    if ( (listenerCapability & LISTENER_TYPE_RENDERER) != 0)
                    {
                        UIComponent componentRef = _component != null ? _component : getCurrentComponent(context);
                        Renderer renderer = componentRef.getRenderer(context);
                        int i = 0;
                        while (renderer != null && !renderer.getClass().equals(listener.getClass()))
                        {
                            if (renderer instanceof RendererWrapper)
                            {
                                renderer = ((RendererWrapper) renderer).getWrapped();
                                i++;
                            }
                            else
                            {
                                renderer = null;
                                i = -1;
                            }
                        }
                        if (i != -1)
                        {
                            // Store the number so we can get the right wrapper to invoke the method.
                            state[1] = i;
                        }
                        else
                        {
                            state[1] = null;
                        }
                    }
                    else
                    {
                        state[1] = null;
                    }
                }
                state[2] = (Integer) listenerCapability;
                return state;
            }
            else
            {
                // If initialStateMarked() == true means two things:
                // 1. PSS is being used
                if ((listenerCapability & LISTENER_TYPE_COMPONENT) != 0)
                {
                    return null;
                }
                else if ((listenerCapability & LISTENER_TYPE_RENDERER) != 0)
                {
                    return null;
                }
                else
                {
                    if ((listenerCapability & LISTENER_SAVE_STATE_HOLDER) != 0 ||
                            (listenerCapability & LISTENER_SAVE_PARTIAL_STATE_HOLDER) != 0)
                    {
                        Object listenerSaved = ((StateHolder) listener).saveState(context);
                        if (listenerSaved == null)
                        {
                            return null;
                        }
                        return new Object[]{componentClass,
                                            new _AttachedDeltaWrapper(listener.getClass(), listenerSaved)};
                    }
                    else
                    {
                        //This is not necessary, because the instance is considered serializable!
                        return null;
                    }
                }
                /*
                Object listenerSaved = ((StateHolder) listener).saveState(context);
                if (listenerSaved == null)
                {
                    return null;
                }
                return new Object[]{componentClass, new _AttachedDeltaWrapper(listener.getClass(), listenerSaved)};
                */
            }
        }

        public void setTransient(boolean newTransientValue)
        {
            if ((listenerCapability & LISTENER_SAVE_PARTIAL_STATE_HOLDER) != 0 ||
                    (listenerCapability & LISTENER_SAVE_STATE_HOLDER) != 0)
            {
                ((StateHolder) listener).setTransient(newTransientValue);
            }
        }
    }
}
TOP

Related Classes of javax.faces.component.UIComponent$EventListenerWrapper

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.