org.apache.myfaces.ov2021.application.ApplicationImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.myfaces.ov2021.application.ApplicationImpl.java

Source

/*
 * 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 org.apache.myfaces.ov2021.application;

import java.beans.BeanDescriptor;
import java.beans.BeanInfo;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.TimeZone;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.el.CompositeELResolver;
import javax.el.ELContext;
import javax.el.ELContextListener;
import javax.el.ELException;
import javax.el.ELResolver;
import javax.el.ExpressionFactory;
import javax.el.MethodExpression;
import javax.el.ValueExpression;
import javax.faces.FacesException;
import javax.faces.application.Application;
import javax.faces.application.NavigationHandler;
import javax.faces.application.ProjectStage;
import javax.faces.application.Resource;
import javax.faces.application.ResourceDependencies;
import javax.faces.application.ResourceDependency;
import javax.faces.application.ResourceHandler;
import javax.faces.application.StateManager;
import javax.faces.application.ViewHandler;
import javax.faces.component.UIComponent;
import javax.faces.component.UIComponentBase;
import javax.faces.component.UINamingContainer;
import javax.faces.component.UIOutput;
import javax.faces.component.UIViewRoot;
import javax.faces.component.behavior.Behavior;
import javax.faces.component.behavior.ClientBehaviorBase;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.DateTimeConverter;
import javax.faces.el.MethodBinding;
import javax.faces.el.PropertyResolver;
import javax.faces.el.ReferenceSyntaxException;
import javax.faces.el.ValueBinding;
import javax.faces.el.VariableResolver;
import javax.faces.event.AbortProcessingException;
import javax.faces.event.ActionListener;
import javax.faces.event.ComponentSystemEventListener;
import javax.faces.event.ListenerFor;
import javax.faces.event.ListenersFor;
import javax.faces.event.SystemEvent;
import javax.faces.event.SystemEventListener;
import javax.faces.event.SystemEventListenerHolder;
import javax.faces.render.ClientBehaviorRenderer;
import javax.faces.render.Renderer;
import javax.faces.validator.Validator;
import javax.faces.view.ViewDeclarationLanguage;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFWebConfigParam;
import org.apache.myfaces.ov2021.config.RuntimeConfig;
import org.apache.myfaces.ov2021.config.element.Property;
import org.apache.myfaces.ov2021.config.element.ResourceBundle;
import org.apache.myfaces.ov2021.context.RequestViewContext;
import org.apache.myfaces.ov2021.el.PropertyResolverImpl;
import org.apache.myfaces.ov2021.el.VariableResolverToApplicationELResolverAdapter;
import org.apache.myfaces.ov2021.el.convert.MethodExpressionToMethodBinding;
import org.apache.myfaces.ov2021.el.convert.ValueBindingToValueExpression;
import org.apache.myfaces.ov2021.el.convert.ValueExpressionToValueBinding;
import org.apache.myfaces.ov2021.el.unified.ELResolverBuilder;
import org.apache.myfaces.ov2021.el.unified.ResolverBuilderForFaces;
import org.apache.myfaces.ov2021.el.unified.resolver.FacesCompositeELResolver;
import org.apache.myfaces.ov2021.el.unified.resolver.FacesCompositeELResolver.Scope;
import org.apache.myfaces.ov2021.lifecycle.LifecycleImpl;
import org.apache.myfaces.shared_ext202patch.config.MyfacesConfig;
import org.apache.myfaces.shared_ext202patch.util.ClassUtils;
import org.apache.myfaces.ov2021.view.facelets.FaceletCompositionContext;
import org.apache.myfaces.ov2021.view.facelets.el.ELText;

/**
 * DOCUMENT ME!
 * 
 * @author Manfred Geiler (latest modification by $Author: lu4242 $)
 * @author Anton Koinov
 * @author Thomas Spiegl
 * @author Stan Silvert
 * @version $Revision: 1505865 $ $Date: 2013-07-23 02:19:31 +0200 (Di, 23 Jul 2013) $
 */
@SuppressWarnings("deprecation")
public class ApplicationImpl extends Application {
    //private static final Log log = LogFactory.getLog(ApplicationImpl.class);
    private static final Logger log = Logger.getLogger(ApplicationImpl.class.getName());

    private final static VariableResolver VARIABLERESOLVER = new VariableResolverToApplicationELResolverAdapter();

    private final static PropertyResolver PROPERTYRESOLVER = new PropertyResolverImpl();

    // the name for the system property which specifies the current ProjectStage (see MYFACES-2545 for details)
    public final static String PROJECT_STAGE_SYSTEM_PROPERTY_NAME = "faces.PROJECT_STAGE";

    // MyFaces specific System Property to set the ProjectStage, if not present via the standard way
    @Deprecated
    public final static String MYFACES_PROJECT_STAGE_SYSTEM_PROPERTY_NAME = "org.apache.myfaces.PROJECT_STAGE";

    /**
     * Set the default timezone as system timezone when a converter extending from DateTimeConverter is created.
     */
    @JSFWebConfigParam(defaultValue = "false", expectedValues = "true, false", since = "2.0", group = "validation")
    public final static String DATETIMECONVERTER_DEFAULT_TIMEZONE_IS_SYSTEM_TIMEZONE_PARAM_NAME = "javax.faces.DATETIMECONVERTER_DEFAULT_TIMEZONE_IS_SYSTEM_TIMEZONE";

    /**
     * Indicate the stage of the initialized application.
     */
    @JSFWebConfigParam(defaultValue = "Production", expectedValues = "Development, Production, SystemTest, UnitTest", since = "2.0")
    private static final String PROJECT_STAGE_PARAM_NAME = "javax.faces.PROJECT_STAGE";

    /**
     * Indicate if the classes associated to components, converters, validators or behaviors
     * should be loaded as soon as they are added to the current application instance or instead
     * loaded in a lazy way.
     */
    @JSFWebConfigParam(defaultValue = "true", since = "2.0", tags = "performance")
    private static final String LAZY_LOAD_CONFIG_OBJECTS_PARAM_NAME = "org.apache.myfaces.LAZY_LOAD_CONFIG_OBJECTS";
    private static final boolean LAZY_LOAD_CONFIG_OBJECTS_DEFAULT_VALUE = true;
    private Boolean _lazyLoadConfigObjects = null;

    /**
     * Key under UIViewRoot to generated unique ids for components added 
     * by @ResourceDependency effect.
     */
    private static final String RESOURCE_DEPENDENCY_UNIQUE_ID_KEY = "oam.view.resourceDependencyUniqueId";

    // ~ Instance fields
    // --------------------------------------------------------------------------
    // --

    private Collection<Locale> _supportedLocales = Collections.emptySet();
    private Locale _defaultLocale;
    private String _messageBundle;

    private ViewHandler _viewHandler;
    private NavigationHandler _navigationHandler;
    private ActionListener _actionListener;
    private String _defaultRenderKitId;
    private ResourceHandler _resourceHandler;
    private StateManager _stateManager;

    private ArrayList<ELContextListener> _elContextListeners;

    // components, converters, and validators can be added at runtime--must
    // synchronize, uses ConcurrentHashMap to allow concurrent read of map
    private final Map<String, Object> _converterIdToClassMap = new ConcurrentHashMap<String, Object>();

    private final Map<Class<?>, Object> _converterTargetClassToConverterClassMap = new ConcurrentHashMap<Class<?>, Object>();

    private final Map<String, Object> _componentClassMap = new ConcurrentHashMap<String, Object>();

    private final Map<String, Object> _validatorClassMap = new ConcurrentHashMap<String, Object>();

    private final Map<Class<? extends SystemEvent>, SystemListenerEntry> _systemEventListenerClassMap = new ConcurrentHashMap<Class<? extends SystemEvent>, SystemListenerEntry>();

    private final Map<String, String> _defaultValidatorsIds = new HashMap<String, String>();

    private volatile Map<String, String> _cachedDefaultValidatorsIds = null;

    private final Map<String, Object> _behaviorClassMap = new ConcurrentHashMap<String, Object>();

    private final RuntimeConfig _runtimeConfig;

    private ELResolver elResolver;

    private ELResolverBuilder resolverBuilderForFaces;

    private ProjectStage _projectStage;

    private volatile boolean _firstRequestProcessed = false;

    // MYFACES-3442 If HashMap or other non thread-safe structure is used, it is
    // possible to fall in a infinite loop under heavy load unless a synchronized block
    // is used to modify it or a ConcurrentHashMap.
    private final Map<Class<?>, List<ListenerFor>> _classToListenerForMap = new ConcurrentHashMap<Class<?>, List<ListenerFor>>();

    private final Map<Class<?>, List<ResourceDependency>> _classToResourceDependencyMap = new ConcurrentHashMap<Class<?>, List<ResourceDependency>>();

    private List<Class<? extends Converter>> _noArgConstructorConverterClasses = new CopyOnWriteArrayList<Class<? extends Converter>>();

    /** Value of javax.faces.DATETIMECONVERTER_DEFAULT_TIMEZONE_IS_SYSTEM_TIMEZONE parameter */
    private boolean _dateTimeConverterDefaultTimeZoneIsSystemTimeZone = false;

    /**
     * Represents semantic null in _componentClassMap. 
     */
    private static final UIComponent NOTHING = new UIComponentBase() {
        @Override
        public String getFamily() {
            return null;
        }
    };

    // ~ Constructors
    // --------------------------------------------------------------------------
    // -----

    public ApplicationImpl() {
        this(getRuntimeConfig());
    }

    private static RuntimeConfig getRuntimeConfig() {
        return RuntimeConfig.getCurrentInstance(FacesContext.getCurrentInstance().getExternalContext());
    }

    ApplicationImpl(final RuntimeConfig runtimeConfig) {
        if (runtimeConfig == null) {
            throw new IllegalArgumentException("runtimeConfig must mot be null");
        }
        // set default implementation in constructor
        // pragmatic approach, no syncronizing will be needed in get methods
        _viewHandler = new ViewHandlerImpl();
        _navigationHandler = new NavigationHandlerImpl();
        _actionListener = new ActionListenerImpl();
        _defaultRenderKitId = "HTML_BASIC";
        _stateManager = new StateManagerImpl();
        _elContextListeners = new ArrayList<ELContextListener>();
        _resourceHandler = new ResourceHandlerImpl();
        _runtimeConfig = runtimeConfig;

        if (log.isLoggable(Level.FINEST)) {
            log.finest("New Application instance created");
        }

        String configParam = getFaceContext().getExternalContext()
                .getInitParameter(DATETIMECONVERTER_DEFAULT_TIMEZONE_IS_SYSTEM_TIMEZONE_PARAM_NAME);
        if (configParam != null && configParam.toLowerCase().equals("true")) {
            _dateTimeConverterDefaultTimeZoneIsSystemTimeZone = true;
        }
    }

    // ~ Methods
    // --------------------------------------------------------------------------
    // ----------

    @Override
    public final void addELResolver(final ELResolver resolver) {
        if (isFirstRequestProcessed()) {
            throw new IllegalStateException("It is illegal to add a resolver after the first request is processed");
        }
        if (resolver != null) {
            _runtimeConfig.addApplicationElResolver(resolver);
        }
    }

    @Override
    public void addDefaultValidatorId(String validatorId) {
        if (_validatorClassMap.containsKey(validatorId)) {
            Object validatorClass = getObjectFromClassMap(validatorId, _validatorClassMap);
            String className;

            if (validatorClass instanceof Class) {
                className = ((Class<?>) validatorClass).getName();
            } else {
                className = validatorClass.toString();
            }
            // Ensure atomicity between _defaultValidatorsIds and _cachedDefaultValidatorsIds
            synchronized (_defaultValidatorsIds) {
                _defaultValidatorsIds.put(validatorId, className);
                _cachedDefaultValidatorsIds = null;
            }
        }
    }

    @Override
    public Map<String, String> getDefaultValidatorInfo() {
        // cachedMap ensures we will not return null if after the check for null
        // _cachedDefaultValidatorsIds is set to null. In theory the unmodifiable map
        // always has a reference to _defaultValidatorsIds, so any instance set
        // in _cachedDefaultValidatorsIds is always the same.
        Map<String, String> cachedMap = _cachedDefaultValidatorsIds;
        if (cachedMap == null) {
            synchronized (_defaultValidatorsIds) {
                if (_cachedDefaultValidatorsIds == null) {
                    _cachedDefaultValidatorsIds = Collections.unmodifiableMap(_defaultValidatorsIds);
                }
                cachedMap = _cachedDefaultValidatorsIds;
            }
        }
        return cachedMap;
    }

    @Override
    public final ELResolver getELResolver() {
        // we don't need synchronization here since it is ok to have multiple
        // instances of the elresolver
        if (elResolver == null) {
            elResolver = createFacesResolver();
        }
        return elResolver;
    }

    private ELResolver createFacesResolver() {
        boolean supportJSPAndFacesEL = MyfacesConfig.getCurrentInstance(getFaceContext().getExternalContext())
                .isSupportJSPAndFacesEL();
        CompositeELResolver resolver;
        if (supportJSPAndFacesEL) {
            resolver = new FacesCompositeELResolver(Scope.Faces);
        } else {
            resolver = new CompositeELResolver();
        }
        getResolverBuilderForFaces().build(resolver);
        return resolver;
    }

    protected final ELResolverBuilder getResolverBuilderForFaces() {
        if (resolverBuilderForFaces == null) {
            resolverBuilderForFaces = new ResolverBuilderForFaces(_runtimeConfig);
        }
        return resolverBuilderForFaces;
    }

    public final void setResolverBuilderForFaces(final ELResolverBuilder factory) {
        resolverBuilderForFaces = factory;
    }

    @Override
    public final java.util.ResourceBundle getResourceBundle(final FacesContext facesContext, final String name)
            throws FacesException, NullPointerException {

        checkNull(facesContext, "facesContext");
        checkNull(name, "name");

        final String bundleName = getBundleName(facesContext, name);

        if (bundleName == null) {
            return null;
        }

        Locale locale = Locale.getDefault();

        final UIViewRoot viewRoot = facesContext.getViewRoot();
        if (viewRoot != null && viewRoot.getLocale() != null) {
            locale = viewRoot.getLocale();
        }

        try {
            return getResourceBundle(bundleName, locale, getClassLoader());
        } catch (MissingResourceException e) {
            try {
                return getResourceBundle(bundleName, locale, this.getClass().getClassLoader());
            } catch (MissingResourceException e1) {
                throw new FacesException(
                        "Could not load resource bundle for name '" + name + "': " + e.getMessage(), e1);
            }
        }
    }

    private ClassLoader getClassLoader() {
        return ClassUtils.getContextClassLoader();
    }

    String getBundleName(final FacesContext facesContext, final String name) {
        ResourceBundle bundle = getRuntimeConfig(facesContext).getResourceBundle(name);
        return bundle != null ? bundle.getBaseName() : null;
    }

    java.util.ResourceBundle getResourceBundle(final String name, final Locale locale, final ClassLoader loader)
            throws MissingResourceException {
        return java.util.ResourceBundle.getBundle(name, locale, loader);
    }

    final RuntimeConfig getRuntimeConfig(final FacesContext facesContext) {
        return RuntimeConfig.getCurrentInstance(facesContext.getExternalContext());
    }

    final FacesContext getFaceContext() {
        return FacesContext.getCurrentInstance();
    }

    @Override
    public final UIComponent createComponent(final ValueExpression componentExpression,
            final FacesContext facesContext, final String componentType)
            throws FacesException, NullPointerException {

        /*
         * Before the component instance is returned, it must be inspected for the presence of a ListenerFor (or
         * ListenersFor) or ResourceDependency (or ResourceDependencies) annotation. If any of these annotations are
         * present, the action listed in ListenerFor or ResourceDependency must be taken on the component, 
         * before it is
         * returned from this method. This variant of createComponent must not inspect the Renderer for the 
         * component to
         * be returned for any of the afore mentioned annotations. Such inspection is the province of
         */

        checkNull(componentExpression, "componentExpression");
        checkNull(facesContext, "facesContext");
        checkNull(componentType, "componentType");

        ELContext elContext = facesContext.getELContext();

        try {
            Object retVal = componentExpression.getValue(elContext);

            UIComponent createdComponent;

            if (retVal instanceof UIComponent) {
                createdComponent = (UIComponent) retVal;
                _handleAnnotations(facesContext, createdComponent, createdComponent);
            } else {
                createdComponent = createComponent(facesContext, componentType);
                componentExpression.setValue(elContext, createdComponent);
            }

            return createdComponent;
        } catch (FacesException e) {
            throw e;
        } catch (Exception e) {
            throw new FacesException(e);
        }
    }

    @Override
    public UIComponent createComponent(ValueExpression componentExpression, FacesContext context,
            String componentType, String rendererType) {
        // Like createComponent(ValueExpression, FacesContext, String)
        UIComponent component = createComponent(componentExpression, context, componentType);

        if (rendererType != null) {
            _inspectRenderer(context, component, componentType, rendererType);
        }

        return component;
    }

    @Override
    public final ExpressionFactory getExpressionFactory() {
        return _runtimeConfig.getExpressionFactory();
    }

    @SuppressWarnings("unchecked")
    @Override
    public final <T> T evaluateExpressionGet(final FacesContext context, final String expression,
            final Class<? extends T> expectedType) throws ELException {
        ELContext elContext = context.getELContext();

        ExpressionFactory factory = getExpressionFactory();

        return (T) factory.createValueExpression(elContext, expression, expectedType).getValue(elContext);
    }

    @Override
    public final void addELContextListener(final ELContextListener listener) {
        synchronized (_elContextListeners) {
            _elContextListeners.add(listener);
        }
    }

    @Override
    public void publishEvent(FacesContext facesContext, Class<? extends SystemEvent> systemEventClass,
            Class<?> sourceBaseType, Object source) {
        checkNull(systemEventClass, "systemEventClass");
        checkNull(source, "source");

        //Call events only if event processing is enabled.
        if (!facesContext.isProcessingEvents()) {
            return;
        }

        // spec: If this argument is null the return from source.getClass() must be used as the sourceBaseType. 
        if (sourceBaseType == null) {
            sourceBaseType = source.getClass();
        }

        try {
            SystemEvent event = null;
            if (source instanceof SystemEventListenerHolder) {
                SystemEventListenerHolder holder = (SystemEventListenerHolder) source;

                // If the source argument implements SystemEventListenerHolder, call
                // SystemEventListenerHolder.getListenersForEventClass(java.lang.Class) on it, passing the
                // systemEventClass
                // argument. If the list is not empty, perform algorithm traverseListenerList on the list.
                event = _traverseListenerList(holder.getListenersForEventClass(systemEventClass), systemEventClass,
                        source, event);
            }

            UIViewRoot uiViewRoot = facesContext.getViewRoot();
            if (uiViewRoot != null) {
                //Call listeners on view level
                event = _traverseListenerListWithCopy(uiViewRoot.getViewListenersForEventClass(systemEventClass),
                        systemEventClass, source, event);
            }

            SystemListenerEntry systemListenerEntry = _systemEventListenerClassMap.get(systemEventClass);
            if (systemListenerEntry != null) {
                systemListenerEntry.publish(systemEventClass, sourceBaseType, source, event);
            }
        } catch (AbortProcessingException e) {
            // If the act of invoking the processListener method causes an AbortProcessingException to be thrown,
            // processing of the listeners must be aborted, no further processing of the listeners for this event must
            // take place, and the exception must be logged with Level.SEVERE.
            log.log(Level.SEVERE, "Event processing was aborted", e);
        }
    }

    @Override
    public void publishEvent(FacesContext facesContext, Class<? extends SystemEvent> systemEventClass,
            Object source) {
        publishEvent(facesContext, systemEventClass, source.getClass(), source);
    }

    @Override
    public final void removeELContextListener(final ELContextListener listener) {
        synchronized (_elContextListeners) {
            _elContextListeners.remove(listener);
        }
    }

    @Override
    public final ELContextListener[] getELContextListeners() {
        // this gets called on every request, so I can't afford to synchronize
        // I just have to trust that toArray() with do the right thing if the
        // list is changing (not likely)
        return _elContextListeners.toArray(new ELContextListener[_elContextListeners.size()]);
    }

    @Override
    public final void setActionListener(final ActionListener actionListener) {
        checkNull(actionListener, "actionListener");

        _actionListener = actionListener;
        if (log.isLoggable(Level.FINEST)) {
            log.finest("set actionListener = " + actionListener.getClass().getName());
        }
    }

    @Override
    public final ActionListener getActionListener() {
        return _actionListener;
    }

    @Override
    public Iterator<String> getBehaviorIds() {
        return _behaviorClassMap.keySet().iterator();
    }

    @Override
    public final Iterator<String> getComponentTypes() {
        return _componentClassMap.keySet().iterator();
    }

    @Override
    public final Iterator<String> getConverterIds() {
        return _converterIdToClassMap.keySet().iterator();
    }

    @Override
    public final Iterator<Class<?>> getConverterTypes() {
        return _converterTargetClassToConverterClassMap.keySet().iterator();
    }

    @Override
    public final void setDefaultLocale(final Locale locale) {
        checkNull(locale, "locale");

        _defaultLocale = locale;
        if (log.isLoggable(Level.FINEST)) {
            log.finest("set defaultLocale = " + locale.getCountry() + " " + locale.getLanguage());
        }
    }

    @Override
    public final Locale getDefaultLocale() {
        return _defaultLocale;
    }

    @Override
    public final void setMessageBundle(final String messageBundle) {
        checkNull(messageBundle, "messageBundle");

        _messageBundle = messageBundle;
        if (log.isLoggable(Level.FINEST)) {
            log.finest("set MessageBundle = " + messageBundle);
        }
    }

    @Override
    public final String getMessageBundle() {
        return _messageBundle;
    }

    @Override
    public final void setNavigationHandler(final NavigationHandler navigationHandler) {
        checkNull(navigationHandler, "navigationHandler");

        _navigationHandler = navigationHandler;
        if (log.isLoggable(Level.FINEST)) {
            log.finest("set NavigationHandler = " + navigationHandler.getClass().getName());
        }
    }

    @Override
    public final NavigationHandler getNavigationHandler() {
        return _navigationHandler;
    }

    /**
     * @deprecated
     */
    @Deprecated
    @Override
    public final void setPropertyResolver(final PropertyResolver propertyResolver) {
        checkNull(propertyResolver, "propertyResolver");

        if (getFaceContext() != null) {
            throw new IllegalStateException("propertyResolver must be defined before request processing");
        }

        _runtimeConfig.setPropertyResolver(propertyResolver);

        if (log.isLoggable(Level.FINEST)) {
            log.finest("set PropertyResolver = " + propertyResolver.getClass().getName());
        }
    }

    @Override
    public ProjectStage getProjectStage() {
        // If the value has already been determined by a previous call to this
        // method, simply return that value.
        if (_projectStage == null) {
            String stageName = null;

            // try to obtain the ProjectStage from the system property
            // faces.PROJECT_STAGE as proposed by Ed Burns
            stageName = System.getProperty(PROJECT_STAGE_SYSTEM_PROPERTY_NAME);

            if (stageName == null) {
                // if not found check for the "old" System Property
                // and print a warning message to the log (just to be 
                // sure that everyone recognizes the change in the name).
                stageName = System.getProperty(MYFACES_PROJECT_STAGE_SYSTEM_PROPERTY_NAME);
                if (stageName != null) {
                    log.log(Level.WARNING,
                            "The system property " + MYFACES_PROJECT_STAGE_SYSTEM_PROPERTY_NAME
                                    + " has been replaced by " + PROJECT_STAGE_SYSTEM_PROPERTY_NAME + "!"
                                    + " Please change your settings.");
                }
            }

            if (stageName == null) {
                // Look for a JNDI environment entry under the key given by the
                // value of ProjectStage.PROJECT_STAGE_JNDI_NAME (return type of
                // java.lang.String).
                try {
                    Context ctx = new InitialContext();
                    Object temp = ctx.lookup(ProjectStage.PROJECT_STAGE_JNDI_NAME);
                    if (temp != null) {
                        if (temp instanceof String) {
                            stageName = (String) temp;
                        } else {
                            log.severe("JNDI lookup for key " + ProjectStage.PROJECT_STAGE_JNDI_NAME
                                    + " should return a java.lang.String value");
                        }
                    }
                } catch (NamingException e) {
                    // no-op
                } catch (NoClassDefFoundError er) {
                    //On Google App Engine, javax.naming.Context is a restricted class.
                    //In that case, NoClassDefFoundError is thrown. stageName needs to be configured
                    //below by context parameter.
                    //It can be done with changing the order to look first at
                    // context param, but it is defined in the spec.
                    //http://java.sun.com/javaee/6/docs/api/javax/faces/application/Application.html#getProjectStage()
                    //no-op
                }
            }

            /*
             * If found, continue with the algorithm below, otherwise, look for an entry in the initParamMap of the
             * ExternalContext from the current FacesContext with the key ProjectStage.PROJECT_STAGE_PARAM_NAME
             */
            if (stageName == null) {
                FacesContext context = FacesContext.getCurrentInstance();
                stageName = context.getExternalContext().getInitParameter(ProjectStage.PROJECT_STAGE_PARAM_NAME);
            }

            // If a value is found
            if (stageName != null) {
                /*
                 * see if an enum constant can be obtained by calling ProjectStage.valueOf(), passing 
                 * the value from the initParamMap. If this succeeds without exception, save the value 
                 * and return it.
                 */
                try {
                    _projectStage = ProjectStage.valueOf(stageName);
                    return _projectStage;
                } catch (IllegalArgumentException e) {
                    log.log(Level.SEVERE, "Couldn't discover the current project stage", e);
                }
            } else {
                if (log.isLoggable(Level.INFO)) {
                    log.info("Couldn't discover the current project stage, using " + ProjectStage.Production);
                }
            }

            /*
             * If not found, or any of the previous attempts to discover the enum constant value have failed, log a
             * descriptive error message, assign the value as ProjectStage.Production and return it.
             */

            _projectStage = ProjectStage.Production;
        }

        return _projectStage;
    }

    /**
     * @deprecated
     */
    @Deprecated
    @Override
    public final PropertyResolver getPropertyResolver() {
        return PROPERTYRESOLVER;
    }

    @Override
    public final void setResourceHandler(ResourceHandler resourceHandler) {
        checkNull(resourceHandler, "resourceHandler");

        if (isFirstRequestProcessed()) {
            throw new IllegalStateException(
                    "setResourceHandler may not be executed after a lifecycle request has been completed");
        }
        _resourceHandler = resourceHandler;
    }

    @Override
    public final ResourceHandler getResourceHandler() {
        return _resourceHandler;
    }

    @Override
    public final void setSupportedLocales(final Collection<Locale> locales) {
        checkNull(locales, "locales");

        _supportedLocales = locales;
        if (log.isLoggable(Level.FINEST)) {
            log.finest("set SupportedLocales");
        }
    }

    @Override
    public final Iterator<Locale> getSupportedLocales() {
        return _supportedLocales.iterator();
    }

    @Override
    public final Iterator<String> getValidatorIds() {
        return _validatorClassMap.keySet().iterator();
    }

    /**
     * @deprecated
     */
    @Deprecated
    @Override
    public final void setVariableResolver(final VariableResolver variableResolver) {
        checkNull(variableResolver, "variableResolver");

        if (isFirstRequestProcessed()) {
            throw new IllegalStateException("variableResolver must be defined before request processing");
        }

        _runtimeConfig.setVariableResolver(variableResolver);

        if (log.isLoggable(Level.FINEST)) {
            log.finest("set VariableResolver = " + variableResolver.getClass().getName());
        }
    }

    /**
     * @deprecated
     */
    @Deprecated
    @Override
    public final VariableResolver getVariableResolver() {
        return VARIABLERESOLVER;
    }

    @Override
    public final void setViewHandler(final ViewHandler viewHandler) {
        checkNull(viewHandler, "viewHandler");

        if (isFirstRequestProcessed()) {
            throw new IllegalStateException(
                    "setViewHandler may not be executed after a lifecycle request has been completed");
        }
        _viewHandler = viewHandler;
        if (log.isLoggable(Level.FINEST)) {
            log.finest("set ViewHandler = " + viewHandler.getClass().getName());
        }
    }

    @Override
    public void subscribeToEvent(Class<? extends SystemEvent> systemEventClass, SystemEventListener listener) {
        subscribeToEvent(systemEventClass, null, listener);
    }

    @Override
    public void subscribeToEvent(Class<? extends SystemEvent> systemEventClass, Class<?> sourceClass,
            SystemEventListener listener) {
        checkNull(systemEventClass, "systemEventClass");
        checkNull(listener, "listener");

        SystemListenerEntry systemListenerEntry;
        synchronized (_systemEventListenerClassMap) {
            systemListenerEntry = _systemEventListenerClassMap.get(systemEventClass);
            if (systemListenerEntry == null) {
                systemListenerEntry = new SystemListenerEntry();
                _systemEventListenerClassMap.put(systemEventClass, systemListenerEntry);
            }
        }

        systemListenerEntry.addListener(listener, sourceClass);
    }

    @Override
    public void unsubscribeFromEvent(Class<? extends SystemEvent> systemEventClass, SystemEventListener listener) {
        unsubscribeFromEvent(systemEventClass, null, listener);
    }

    @Override
    public void unsubscribeFromEvent(Class<? extends SystemEvent> systemEventClass, Class<?> sourceClass,
            SystemEventListener listener) {
        checkNull(systemEventClass, "systemEventClass");
        checkNull(listener, "listener");

        SystemListenerEntry systemListenerEntry = _systemEventListenerClassMap.get(systemEventClass);
        if (systemListenerEntry != null) {
            systemListenerEntry.removeListener(listener, sourceClass);
        }
    }

    @Override
    public final ViewHandler getViewHandler() {
        return _viewHandler;
    }

    @Override
    public void addBehavior(String behaviorId, String behaviorClass) {
        checkNull(behaviorId, "behaviorId");
        checkEmpty(behaviorId, "behaviorId");
        checkNull(behaviorClass, "behaviorClass");
        checkEmpty(behaviorClass, "behaviorClass");

        try {
            if (isLazyLoadConfigObjects()) {
                _behaviorClassMap.put(behaviorId, behaviorClass);
            } else {
                _behaviorClassMap.put(behaviorId, ClassUtils.simpleClassForName(behaviorClass));
            }

            if (log.isLoggable(Level.FINEST)) {
                log.finest("add Behavior class = " + behaviorClass + " for id = " + behaviorId);
            }
        } catch (Exception e) {
            log.log(Level.SEVERE, "Behavior class " + behaviorClass + " not found", e);
        }

    }

    @Override
    public final void addComponent(final String componentType, final String componentClassName) {
        checkNull(componentType, "componentType");
        checkEmpty(componentType, "componentType");
        checkNull(componentClassName, "componentClassName");
        checkEmpty(componentClassName, "componentClassName");

        try {
            if (isLazyLoadConfigObjects()) {
                _componentClassMap.put(componentType, componentClassName);
            } else {
                _componentClassMap.put(componentType, ClassUtils.simpleClassForName(componentClassName));
            }

            if (log.isLoggable(Level.FINEST)) {
                log.finest("add Component class = " + componentClassName + " for type = " + componentType);
            }
        } catch (Exception e) {
            log.log(Level.SEVERE, "Component class " + componentClassName + " not found", e);
        }
    }

    @Override
    public final void addConverter(final String converterId, final String converterClass) {
        checkNull(converterId, "converterId");
        checkEmpty(converterId, "converterId");
        checkNull(converterClass, "converterClass");
        checkEmpty(converterClass, "converterClass");

        try {
            if (isLazyLoadConfigObjects()) {
                _converterIdToClassMap.put(converterId, converterClass);
            } else {
                _converterIdToClassMap.put(converterId, ClassUtils.simpleClassForName(converterClass));
            }
            if (log.isLoggable(Level.FINEST)) {
                log.finest("add Converter id = " + converterId + " converterClass = " + converterClass);
            }
        } catch (Exception e) {
            log.log(Level.SEVERE, "Converter class " + converterClass + " not found", e);
        }
    }

    @Override
    public final void addConverter(final Class<?> targetClass, final String converterClass) {
        checkNull(targetClass, "targetClass");
        checkNull(converterClass, "converterClass");
        checkEmpty(converterClass, "converterClass");

        try {
            if (isLazyLoadConfigObjects()) {
                _converterTargetClassToConverterClassMap.put(targetClass, converterClass);
            } else {
                _converterTargetClassToConverterClassMap.put(targetClass,
                        ClassUtils.simpleClassForName(converterClass));
            }

            if (log.isLoggable(Level.FINEST)) {
                log.finest("add Converter for class = " + targetClass + " converterClass = " + converterClass);
            }
        } catch (Exception e) {
            log.log(Level.SEVERE, "Converter class " + converterClass + " not found", e);
        }
    }

    @Override
    public final void addValidator(final String validatorId, final String validatorClass) {
        checkNull(validatorId, "validatorId");
        checkEmpty(validatorId, "validatorId");
        checkNull(validatorClass, "validatorClass");
        checkEmpty(validatorClass, "validatorClass");

        try {
            if (isLazyLoadConfigObjects()) {
                _validatorClassMap.put(validatorId, validatorClass);
            } else {
                _validatorClassMap.put(validatorId, ClassUtils.simpleClassForName(validatorClass));
            }

            if (log.isLoggable(Level.FINEST)) {
                log.finest("add Validator id = " + validatorId + " class = " + validatorClass);
            }
        } catch (Exception e) {
            log.log(Level.SEVERE, "Validator class " + validatorClass + " not found", e);
        }
    }

    @Override
    public Behavior createBehavior(String behaviorId) throws FacesException {
        checkNull(behaviorId, "behaviorId");
        checkEmpty(behaviorId, "behaviorId");

        final Class<?> behaviorClass = getObjectFromClassMap(behaviorId, _behaviorClassMap);

        if (behaviorClass == null) {
            throw new FacesException("Could not find any registered behavior-class for behaviorId : " + behaviorId);
        }

        try {
            Behavior behavior = (Behavior) behaviorClass.newInstance();
            FacesContext facesContext = FacesContext.getCurrentInstance();
            _handleAttachedResourceDependencyAnnotations(facesContext, behavior);

            if (behavior instanceof ClientBehaviorBase) {
                ClientBehaviorBase clientBehavior = (ClientBehaviorBase) behavior;
                String renderType = clientBehavior.getRendererType();
                if (renderType != null) {
                    ClientBehaviorRenderer cbr = facesContext.getRenderKit().getClientBehaviorRenderer(renderType);
                    _handleAttachedResourceDependencyAnnotations(facesContext, cbr);
                }
            }

            return behavior;
        } catch (Exception e) {
            log.log(Level.SEVERE, "Could not instantiate behavior " + behaviorClass, e);
            throw new FacesException("Could not instantiate behavior: " + behaviorClass, e);
        }
    }

    @Override
    public UIComponent createComponent(FacesContext context, Resource componentResource) {
        checkNull(context, "context");
        checkNull(componentResource, "componentResource");

        UIComponent component = null;
        Resource resource;
        String fqcn;
        Class<? extends UIComponent> componentClass = null;

        /*
         * Obtain a reference to the ViewDeclarationLanguage for this Application instance by calling
         * ViewHandler.getViewDeclarationLanguage(javax.faces.context.FacesContext, java.lang.String), passing the
         * viewId found by calling UIViewRoot.getViewId() on the UIViewRoot in the argument FacesContext.
         */
        UIViewRoot view = context.getViewRoot();
        Application application = context.getApplication();
        ViewDeclarationLanguage vdl = application.getViewHandler().getViewDeclarationLanguage(context,
                view.getViewId());

        /*
         * Obtain a reference to the composite component metadata for this composite component by calling
         * ViewDeclarationLanguage.getComponentMetadata(javax.faces.context.FacesContext,
         * javax.faces.application.Resource), passing the facesContext and componentResource arguments to this method.
         * This version of JSF specification uses JavaBeans as the API to the component metadata.
         */
        BeanInfo metadata = vdl.getComponentMetadata(context, componentResource);
        if (metadata == null) {
            throw new FacesException("Could not get component metadata for " + componentResource.getResourceName()
                    + ". Did you forget to specify <composite:interface>?");
        }

        /*
         * Determine if the component author declared a component-type for this component instance by obtaining the
         * BeanDescriptor from the component metadata and calling its getValue() method, passing
         * UIComponent.COMPOSITE_COMPONENT_TYPE_KEY as the argument. If non-null, the result must be a ValueExpression
         * whose value is the component-type of the UIComponent to be created for this Resource component. Call through
         * to createComponent(java.lang.String) to create the component.
         */
        BeanDescriptor descriptor = metadata.getBeanDescriptor();
        ValueExpression componentType = (ValueExpression) descriptor
                .getValue(UIComponent.COMPOSITE_COMPONENT_TYPE_KEY);
        boolean annotationsApplied = false;
        if (componentType != null) {
            component = application.createComponent((String) componentType.getValue(context.getELContext()));
            annotationsApplied = true;
        } else {
            /*
             * Otherwise, determine if a script based component for this Resource can be found by calling
             * ViewDeclarationLanguage.getScriptComponentResource(javax.faces.context.FacesContext,
             * javax.faces.application.Resource). If the result is non-null, and is a script written in one of the
             * languages listed in JSF 4.3 of the specification prose document, create a UIComponent instance from the
             * script resource.
             */
            resource = vdl.getScriptComponentResource(context, componentResource);
            if (resource != null) {
                String name = resource.getResourceName();
                String className = name.substring(0, name.lastIndexOf('.'));

                component = (UIComponent) ClassUtils.newInstance(className);
            } else {
                /*
                 * Otherwise, let library-name be the return from calling Resource.getLibraryName() on the argument
                 * componentResource and resource-name be the return from calling Resource.getResourceName() on the
                 * argument componentResource. Create a fully qualified Java class name by removing any file extension
                 * from resource-name and let fqcn be library-name + "." + resource-name. If a class with the name of
                 * fqcn cannot be found, take no action and continue to the next step. If any of 
                 * InstantiationException,
                 * IllegalAccessException, or ClassCastException are thrown, wrap the exception in a FacesException and
                 * re-throw it. If any other exception is thrown, log the exception and continue to the next step.
                 */

                boolean isProduction = FacesContext.getCurrentInstance().isProjectStage(ProjectStage.Production);
                String name = componentResource.getResourceName();
                String className = name.substring(0, name.lastIndexOf('.'));
                fqcn = componentResource.getLibraryName() + "." + className;

                if (isProduction) {
                    componentClass = (Class<? extends UIComponent>) _componentClassMap.get(fqcn);
                }
                if (componentClass == null) {
                    try {
                        componentClass = ClassUtils.classForName(fqcn);
                        if (isProduction) {
                            _componentClassMap.put(fqcn, componentClass);
                        }
                    } catch (ClassNotFoundException e) {
                        // Remember here that classForName did not find Class
                        if (isProduction) {
                            _componentClassMap.put(fqcn, NOTHING.getClass());
                        }
                    }
                }

                if (componentClass != null && NOTHING.getClass() != componentClass) {
                    try {
                        component = componentClass.newInstance();
                    } catch (InstantiationException e) {
                        log.log(Level.SEVERE, "Could not instantiate component class name = " + fqcn, e);
                        throw new FacesException("Could not instantiate component class name = " + fqcn, e);
                    } catch (IllegalAccessException e) {
                        log.log(Level.SEVERE, "Could not instantiate component class name = " + fqcn, e);
                        throw new FacesException("Could not instantiate component class name = " + fqcn, e);
                    } catch (Exception e) {
                        log.log(Level.SEVERE, "Could not instantiate component class name = " + fqcn, e);
                    }
                }

                /*
                 * If none of the previous steps have yielded a UIComponent instance, call
                 * createComponent(java.lang.String) passing "javax.faces.NamingContainer" as the argument.
                 */
                if (component == null) {
                    component = application.createComponent(context, UINamingContainer.COMPONENT_TYPE, null);
                    annotationsApplied = true;
                }
            }
        }

        /*
         * Call UIComponent.setRendererType(java.lang.String) on the UIComponent instance, passing
         * "javax.faces.Composite" as the argument.
         */
        component.setRendererType("javax.faces.Composite");

        /*
         * Store the argument Resource in the attributes Map of the UIComponent under the key,
         * Resource.COMPONENT_RESOURCE_KEY.
         */
        component.getAttributes().put(Resource.COMPONENT_RESOURCE_KEY, componentResource);

        /*
         * Store composite component metadata in the attributes Map of the UIComponent under the key,
         * UIComponent.BEANINFO_KEY.
         */
        component.getAttributes().put(UIComponent.BEANINFO_KEY, metadata);

        /*
         * Before the component instance is returned, it must be inspected for the presence of a 
         * ListenerFor annotation.
         * If this annotation is present, the action listed in ListenerFor must be taken on the component, 
         * before it is
         * returned from this method.
         */
        if (!annotationsApplied) {
            _handleAnnotations(context, component, component);
        }

        return component;
    }

    @Override
    public UIComponent createComponent(FacesContext context, String componentType, String rendererType) {
        checkNull(context, "context");
        checkNull(componentType, "componentType");

        // Like createComponent(String)
        UIComponent component = createComponent(context, componentType);

        // A null value on this field is valid! If that so, no need to do any log
        // or look on RenderKit map for a inexistent renderer!
        if (rendererType != null) {
            _inspectRenderer(context, component, componentType, rendererType);
        }

        return component;
    }

    /**
     * This works just like createComponent(String componentType), but without call
     * FacesContext.getCurrentInstance()
     * 
     * @param facesContext
     * @param componentType
     * @return
     * @throws FacesException 
     */
    private final UIComponent createComponent(FacesContext facesContext, final String componentType)
            throws FacesException {
        checkNull(componentType, "componentType");
        checkEmpty(componentType, "componentType");

        final Class<?> componentClass = getObjectFromClassMap(componentType, _componentClassMap);
        if (componentClass == null) {
            log.log(Level.SEVERE, "Undefined component type " + componentType);
            throw new FacesException("Undefined component type " + componentType);
        }

        try {
            UIComponent component = (UIComponent) componentClass.newInstance();
            _handleAnnotations(facesContext, component, component);
            return component;
        } catch (Exception e) {
            log.log(Level.SEVERE, "Could not instantiate component componentType = " + componentType, e);
            throw new FacesException("Could not instantiate component componentType = " + componentType, e);
        }
    }

    @Override
    public final UIComponent createComponent(final String componentType) throws FacesException {
        checkNull(componentType, "componentType");
        checkEmpty(componentType, "componentType");

        final Class<?> componentClass = getObjectFromClassMap(componentType, _componentClassMap);
        if (componentClass == null) {
            log.log(Level.SEVERE, "Undefined component type " + componentType);
            throw new FacesException("Undefined component type " + componentType);
        }

        try {
            UIComponent component = (UIComponent) componentClass.newInstance();
            _handleAnnotations(FacesContext.getCurrentInstance(), component, component);
            return component;
        } catch (Exception e) {
            log.log(Level.SEVERE, "Could not instantiate component componentType = " + componentType, e);
            throw new FacesException("Could not instantiate component componentType = " + componentType, e);
        }
    }

    /**
     * @deprecated Use createComponent(ValueExpression, FacesContext, String) instead.
     */
    @Deprecated
    @Override
    public final UIComponent createComponent(final ValueBinding valueBinding, final FacesContext facesContext,
            final String componentType) throws FacesException {

        checkNull(valueBinding, "valueBinding");
        checkNull(facesContext, "facesContext");
        checkNull(componentType, "componentType");
        checkEmpty(componentType, "componentType");

        final ValueExpression valExpression = new ValueBindingToValueExpression(valueBinding);

        return createComponent(valExpression, facesContext, componentType);
    }

    /**
     * Return an instance of the converter class that has been registered under the specified id.
     * <p>
     * Converters are registered via faces-config.xml files, and can also be registered via the addConverter(String id,
     * Class converterClass) method on this class. Here the the appropriate Class definition is found, then an instance
     * is created and returned.
     * <p>
     * A converter registered via a config file can have any number of nested attribute or property tags. The JSF
     * specification is very vague about what effect these nested tags have. This method ignores nested attribute
     * definitions, but for each nested property tag the corresponding setter is invoked on the new Converter instance
     * passing the property's defaultValuer. Basic typeconversion is done so the target properties on the Converter
     * instance can be String, int, boolean, etc. Note that:
     * <ol>
     * <li>the Sun Mojarra JSF implemenation ignores nested property tags completely, so this behaviour cannot be 
     * relied on across implementations.
     * <li>there is no equivalent functionality for converter classes registered via the Application.addConverter api
     * method.
     * </ol>
     * <p>
     * Note that this method is most commonly called from the standard f:attribute tag. As an alternative, most
     * components provide a "converter" attribute which uses an EL expression to create a Converter instance, in which
     * case this method is not invoked at all. The converter attribute allows the returned Converter instance to be
     * configured via normal dependency-injection, and is generally a better choice than using this method.
     */
    @Override
    public final Converter createConverter(final String converterId) {
        checkNull(converterId, "converterId");
        checkEmpty(converterId, "converterId");

        final Class<?> converterClass = getObjectFromClassMap(converterId, _converterIdToClassMap);
        if (converterClass == null) {
            throw new FacesException(
                    "Could not find any registered converter-class by converterId : " + converterId);
        }

        try {
            final Converter converter = (Converter) converterClass.newInstance();

            setConverterProperties(converterClass, converter);

            _handleAttachedResourceDependencyAnnotations(FacesContext.getCurrentInstance(), converter);

            return converter;
        } catch (Exception e) {
            log.log(Level.SEVERE, "Could not instantiate converter " + converterClass, e);
            throw new FacesException("Could not instantiate converter: " + converterClass, e);
        }
    }

    @Override
    public final Converter createConverter(final Class<?> targetClass) {
        checkNull(targetClass, "targetClass");

        return internalCreateConverter(targetClass);
    }

    @SuppressWarnings("unchecked")
    private Converter internalCreateConverter(final Class<?> targetClass) {
        // Locate a Converter registered for the target class itself.
        Object converterClassOrClassName = _converterTargetClassToConverterClassMap.get(targetClass);

        // Locate a Converter registered for interfaces that are
        // implemented by the target class (directly or indirectly).
        // Skip if class is String, for performance reasons 
        // (save 3 additional lookups over a concurrent map per request). 
        if (converterClassOrClassName == null && !String.class.equals(targetClass)) {
            final Class<?> interfaces[] = targetClass.getInterfaces();
            if (interfaces != null) {
                for (int i = 0, len = interfaces.length; i < len; i++) {
                    // search all superinterfaces for a matching converter,
                    // create it
                    final Converter converter = internalCreateConverter(interfaces[i]);
                    if (converter != null) {
                        return converter;
                    }
                }
            }
        }

        // Get EnumConverter for enum classes with no special converter, check
        // here as recursive call with java.lang.Enum will not work
        if (converterClassOrClassName == null && targetClass.isEnum()) {
            converterClassOrClassName = _converterTargetClassToConverterClassMap.get(Enum.class);
        }

        if (converterClassOrClassName != null) {
            try {
                Class<? extends Converter> converterClass = null;
                if (converterClassOrClassName instanceof Class<?>) {
                    converterClass = (Class<? extends Converter>) converterClassOrClassName;
                } else if (converterClassOrClassName instanceof String) {
                    converterClass = ClassUtils.simpleClassForName((String) converterClassOrClassName);
                    _converterTargetClassToConverterClassMap.put(targetClass, converterClass);
                } else {
                    //object stored in the map for this id is an invalid type.  remove it and return null
                    _converterTargetClassToConverterClassMap.remove(targetClass);
                }

                Converter converter = null;

                // check cached constructor information
                if (!_noArgConstructorConverterClasses.contains(converterClass)) {
                    // the converter class either supports the one-arg constructor
                    // or has never been processed before
                    try {
                        // look for a constructor that takes a single Class object
                        // See JSF 1.2 javadoc for Converter
                        Constructor<? extends Converter> constructor = converterClass
                                .getConstructor(new Class[] { Class.class });

                        converter = constructor.newInstance(new Object[] { targetClass });
                    } catch (Exception e) {
                        // the constructor does not exist
                        // add the class to the no-arg constructor classes cache
                        _noArgConstructorConverterClasses.add(converterClass);

                        // use no-arg constructor
                        converter = converterClass.newInstance();
                    }
                } else {
                    // use no-arg constructor
                    converter = converterClass.newInstance();
                }

                setConverterProperties(converterClass, converter);

                return converter;
            } catch (Exception e) {
                log.log(Level.SEVERE, "Could not instantiate converter " + converterClassOrClassName.toString(), e);
                throw new FacesException("Could not instantiate converter: " + converterClassOrClassName.toString(),
                        e);
            }
        }

        // locate converter for primitive types
        if (targetClass == Long.TYPE) {
            return internalCreateConverter(Long.class);
        } else if (targetClass == Boolean.TYPE) {
            return internalCreateConverter(Boolean.class);
        } else if (targetClass == Double.TYPE) {
            return internalCreateConverter(Double.class);
        } else if (targetClass == Byte.TYPE) {
            return internalCreateConverter(Byte.class);
        } else if (targetClass == Short.TYPE) {
            return internalCreateConverter(Short.class);
        } else if (targetClass == Integer.TYPE) {
            return internalCreateConverter(Integer.class);
        } else if (targetClass == Float.TYPE) {
            return internalCreateConverter(Float.class);
        } else if (targetClass == Character.TYPE) {
            return internalCreateConverter(Character.class);
        }

        // Locate a Converter registered for the superclass (if any) of the
        // target class,
        // recursively working up the inheritance hierarchy.
        Class<?> superClazz = targetClass.getSuperclass();

        return superClazz != null ? internalCreateConverter(superClazz) : null;

    }

    private void setConverterProperties(final Class<?> converterClass, final Converter converter) {
        final org.apache.myfaces.ov2021.config.element.Converter converterConfig = _runtimeConfig
                .getConverterConfiguration(converterClass.getName());

        // if the converter is a DataTimeConverter, check the init param for the default timezone (since 2.0)
        if (converter instanceof DateTimeConverter && _dateTimeConverterDefaultTimeZoneIsSystemTimeZone) {
            ((DateTimeConverter) converter).setTimeZone(TimeZone.getDefault());
        }

        if (converterConfig != null && converterConfig.getProperties().size() > 0) {
            for (Property property : converterConfig.getProperties()) {
                try {
                    BeanUtils.setProperty(converter, property.getPropertyName(), property.getDefaultValue());
                } catch (Throwable th) {
                    log.log(Level.SEVERE,
                            "Initializing converter : " + converterClass.getName() + " with property : "
                                    + property.getPropertyName() + " and value : " + property.getDefaultValue()
                                    + " failed.");
                }
            }
        }
    }

    private void _handleAttachedResourceDependencyAnnotations(FacesContext context, Object inspected) {
        if (inspected == null) {
            return;
        }

        // This and only this method handles @ResourceDependency and @ResourceDependencies annotations
        // The source of these annotations is Class<?> inspectedClass.
        // Because Class<?> and its annotations cannot change
        // during request/response, it is sufficient to process Class<?> only once per view.
        RequestViewContext rvc = RequestViewContext.getCurrentInstance(context);
        Class<?> inspectedClass = inspected.getClass();
        if (rvc.isClassAlreadyProcessed(inspectedClass)) {
            return;
        }
        boolean classAlreadyProcessed = false;

        List<ResourceDependency> dependencyList = null;
        boolean isCachedList = false;

        if (context.isProjectStage(ProjectStage.Production)
                && _classToResourceDependencyMap.containsKey(inspectedClass)) {
            dependencyList = _classToResourceDependencyMap.get(inspectedClass);
            if (dependencyList == null) {
                return; //class has been inspected and did not contain any resource dependency annotations
            } else if (dependencyList.isEmpty()) {
                return;
            }

            isCachedList = true; // else annotations were found in the cache
        }

        if (dependencyList == null) //not in production or the class hasn't been inspected yet
        {
            ResourceDependency dependency = inspectedClass.getAnnotation(ResourceDependency.class);
            ResourceDependencies dependencies = inspectedClass.getAnnotation(ResourceDependencies.class);
            if (dependency != null || dependencies != null) {
                //resource dependencies were found using one or both annotations, create and build a new list
                dependencyList = new ArrayList<ResourceDependency>();

                if (dependency != null) {
                    dependencyList.add(dependency);
                }

                if (dependencies != null) {
                    dependencyList.addAll(Arrays.asList(dependencies.value()));
                }
            } else {
                dependencyList = Collections.emptyList();
            }
        }

        //resource dependencies were found through inspection or from cache, handle them
        if (dependencyList != null && !dependencyList.isEmpty()) {
            for (int i = 0, size = dependencyList.size(); i < size; i++) {
                ResourceDependency dependency = dependencyList.get(i);
                if (!rvc.isResourceDependencyAlreadyProcessed(dependency)) {
                    _handleAttachedResourceDependency(context, dependency, inspectedClass);
                    rvc.setResourceDependencyAsProcessed(dependency);
                }
            }
        }

        //if we're in production and the list is not yet cached, store it
        if (context.isProjectStage(ProjectStage.Production) && !isCachedList) {
            // Note at this point listenerForList cannot be null, but just let this
            // as a sanity check.
            if (dependencyList != null) {
                _classToResourceDependencyMap.put(inspectedClass, dependencyList);
            }
        }

        if (!classAlreadyProcessed) {
            rvc.setClassProcessed(inspectedClass);
        }
    }

    /**
     * If the ResourceDependency component is created under facelets processing, it should receive
     * an special unique component id. This method check if there is a FaceletCompositionContext
     * and if that so, set the id. Components added by the effect of ResourceDependency are special,
     * because they do not have state, but they depends on the view structure, so with PSS, 
     * each time the view is built they are "recalculated", so they work as if they were transient
     * components that needs to be created at each request, but there are some cases were the 
     * components needs to be saved and restored fully. If a component is created outside facelets 
     * control (render response phase) it is expected to use the default implementation of 
     * createUniqueId(), but in that case, note that this happens after markInitialState() is 
     * called, and the component in this case is saved and restored fully, as expected.
     * 
     * This code cannot be called from facelets component tag handler, because in cases where a
     * component subtree is created using binding property, facelets lost control over component
     * creation and delegates it to the user, but since the binding code is executed each time the
     * view is created, the effect over ResourceDependency persists and the binding code takes into
     * account in the recalculation step, even if later the node related to the binding property
     * is dropped and recreated from the state fully. 
     * 
     * @param facesContext
     * @param component 
     */
    private void setResourceIdOnFaceletsMode(FacesContext facesContext, UIComponent component,
            Class<?> inspectedClass) {
        if (component.getId() == null) {
            FaceletCompositionContext mctx = FaceletCompositionContext.getCurrentInstance(facesContext);
            if (mctx != null) {
                UIViewRoot root = facesContext.getViewRoot();
                root.getAttributes().put(RESOURCE_DEPENDENCY_UNIQUE_ID_KEY, Boolean.TRUE);
                try {
                    String uid = root.createUniqueId(facesContext, null);
                    component.setId(uid);
                } finally {
                    root.getAttributes().put(RESOURCE_DEPENDENCY_UNIQUE_ID_KEY, Boolean.FALSE);
                }
                if (!mctx.isUsingPSSOnThisView()) {
                    // Now set the identifier that will help to know which classes has been already inspected.
                    component.getAttributes().put(RequestViewContext.RESOURCE_DEPENDENCY_INSPECTED_CLASS,
                            inspectedClass);
                } else if (mctx.isRefreshTransientBuildOnPSSPreserveState()) {
                    component.getAttributes().put(RequestViewContext.RESOURCE_DEPENDENCY_INSPECTED_CLASS,
                            inspectedClass);
                }
            } else {
                // This happens when there is a programmatic addition, which means the user has added the
                // components to the tree on render response phase or earlier but outside facelets control.
                // In that case we need to save the dependency.
                component.getAttributes().put(RequestViewContext.RESOURCE_DEPENDENCY_INSPECTED_CLASS,
                        inspectedClass);
            }
        }
    }

    private void _handleAttachedResourceDependency(FacesContext context, ResourceDependency annotation,
            Class<?> inspectedClass) {
        // If this annotation is not present on the class in question, no action must be taken. 
        if (annotation != null) {
            Application application = context.getApplication();

            // Create a UIOutput instance by passing javax.faces.Output. to 
            // Application.createComponent(java.lang.String).
            UIOutput output = (UIOutput) application.createComponent(context, UIOutput.COMPONENT_TYPE, null);

            // Get the annotation instance from the class and obtain the values of the name, library, and 
            // target attributes.
            String name = annotation.name();
            if (name != null && name.length() > 0) {
                name = ELText.parse(getExpressionFactory(), context.getELContext(), name)
                        .toString(context.getELContext());
            }

            // Obtain the renderer-type for the resource name by passing name to 
            // ResourceHandler.getRendererTypeForResourceName(java.lang.String).
            String rendererType = application.getResourceHandler().getRendererTypeForResourceName(name);

            // Call setRendererType on the UIOutput instance, passing the renderer-type.
            output.setRendererType(rendererType);

            // If the @ResourceDependency was done inside facelets processing,
            // call setId() and set a proper id from facelets
            setResourceIdOnFaceletsMode(context, output, inspectedClass);

            // Obtain the Map of attributes from the UIOutput component by calling UIComponent.getAttributes().
            Map<String, Object> attributes = output.getAttributes();

            // Store the name into the attributes Map under the key "name".
            attributes.put("name", name);

            // If library is the empty string, let library be null.
            String library = annotation.library();
            if (library != null && library.length() > 0) {
                library = ELText.parse(getExpressionFactory(), context.getELContext(), library)
                        .toString(context.getELContext());
                // If library is non-null, store it under the key "library".
                attributes.put("library", library);
            }

            // If target is the empty string, let target be null.
            String target = annotation.target();
            if (target != null && target.length() > 0) {
                target = ELText.parse(getExpressionFactory(), context.getELContext(), target)
                        .toString(context.getELContext());
                // If target is non-null, store it under the key "target".
                attributes.put("target", target);
                context.getViewRoot().addComponentResource(context, output, target);
            } else {
                // Otherwise, if target is null, call 
                // UIViewRoot.addComponentResource(javax.faces.context.FacesContext, 
                // javax.faces.component.UIComponent), passing the UIOutput instance as the second argument.
                context.getViewRoot().addComponentResource(context, output);
            }
        }
    }

    // Note: this method used to be synchronized in the JSF 1.1 version. Why?
    /**
     * @deprecated
     */
    @Deprecated
    @Override
    public final MethodBinding createMethodBinding(final String reference, Class<?>[] params)
            throws ReferenceSyntaxException {
        checkNull(reference, "reference");
        checkEmpty(reference, "reference");

        // TODO: this check should be performed by the expression factory. It is
        // a requirement of the TCK
        if (!(reference.startsWith("#{") && reference.endsWith("}"))) {
            throw new ReferenceSyntaxException("Invalid method reference: '" + reference + "'");
        }

        if (params == null) {
            params = new Class[0];
        }

        MethodExpression methodExpression;

        try {
            methodExpression = getExpressionFactory().createMethodExpression(threadELContext(), reference,
                    Object.class, params);
        } catch (ELException e) {
            throw new ReferenceSyntaxException(e);
        }

        return new MethodExpressionToMethodBinding(methodExpression);
    }

    @Override
    public final Validator createValidator(final String validatorId) throws FacesException {
        checkNull(validatorId, "validatorId");
        checkEmpty(validatorId, "validatorId");

        Class<?> validatorClass = getObjectFromClassMap(validatorId, _validatorClassMap);
        if (validatorClass == null) {
            String message = "Unknown validator id '" + validatorId + "'.";
            log.severe(message);
            throw new FacesException(message);
        }

        try {
            Validator validator = (Validator) validatorClass.newInstance();

            _handleAttachedResourceDependencyAnnotations(FacesContext.getCurrentInstance(), validator);

            return validator;
        } catch (Exception e) {
            log.log(Level.SEVERE, "Could not instantiate validator " + validatorClass, e);
            throw new FacesException("Could not instantiate validator: " + validatorClass, e);
        }
    }

    /**
     * @deprecated
     */
    @Override
    public final ValueBinding createValueBinding(final String reference) throws ReferenceSyntaxException {
        checkNull(reference, "reference");
        checkEmpty(reference, "reference");

        ValueExpression valueExpression;

        try {
            valueExpression = getExpressionFactory().createValueExpression(threadELContext(), reference,
                    Object.class);
        } catch (ELException e) {
            throw new ReferenceSyntaxException(e);
        }

        return new ValueExpressionToValueBinding(valueExpression);
    }

    // gets the elContext from the current FacesContext()
    private final ELContext threadELContext() {
        return getFaceContext().getELContext();
    }

    @Override
    public final String getDefaultRenderKitId() {
        return _defaultRenderKitId;
    }

    @Override
    public final void setDefaultRenderKitId(final String defaultRenderKitId) {
        _defaultRenderKitId = defaultRenderKitId;
    }

    @Override
    public final StateManager getStateManager() {
        return _stateManager;
    }

    @Override
    public final void setStateManager(final StateManager stateManager) {
        checkNull(stateManager, "stateManager");

        if (isFirstRequestProcessed()) {
            throw new IllegalStateException(
                    "setStateManager may not be executed after a lifecycle request has been completed");
        }

        _stateManager = stateManager;
    }

    private void checkNull(final Object param, final String paramName) {
        if (param == null) {
            throw new NullPointerException(paramName + " cannot be null.");
        }
    }

    private void checkEmpty(final String param, final String paramName) {
        if (param.length() == 0) {
            throw new NullPointerException("String " + paramName + " cannot be empty.");
        }
    }

    private static SystemEvent _createEvent(Class<? extends SystemEvent> systemEventClass, Object source,
            SystemEvent event) {
        if (event == null) {
            try {
                Constructor<?>[] constructors = systemEventClass.getConstructors();
                Constructor<? extends SystemEvent> constructor = null;
                for (Constructor<?> c : constructors) {
                    if (c.getParameterTypes().length == 1) {
                        // Safe cast, since the constructor belongs
                        // to a class of type SystemEvent
                        constructor = (Constructor<? extends SystemEvent>) c;
                        break;
                    }
                }
                if (constructor != null) {
                    event = constructor.newInstance(source);
                }

            } catch (Exception e) {
                throw new FacesException("Couldn't instanciate system event of type " + systemEventClass.getName(),
                        e);
            }
        }

        return event;
    }

    private void _handleAnnotations(FacesContext context, Object inspected, UIComponent component) {
        // determine the ProjectStage setting via the given FacesContext
        // note that a local getProjectStage() could cause problems in wrapped environments
        boolean isProduction = context.isProjectStage(ProjectStage.Production);

        Class<?> inspectedClass = inspected.getClass();
        _handleListenerForAnnotations(context, inspected, inspectedClass, component, isProduction);

        _handleResourceDependencyAnnotations(context, inspectedClass, component, isProduction);
    }

    private void _handleListenerForAnnotations(FacesContext context, Object inspected, Class<?> inspectedClass,
            UIComponent component, boolean isProduction) {
        List<ListenerFor> listenerForList = null;
        boolean isCachedList = false;

        if (isProduction && _classToListenerForMap.containsKey(inspectedClass)) {
            listenerForList = _classToListenerForMap.get(inspectedClass);
            if (listenerForList == null) {
                return; //class has been inspected and did not contain any listener annotations
            } else if (listenerForList.isEmpty()) {
                return;
            }

            isCachedList = true; // else annotations were found in the cache
        }

        if (listenerForList == null) //not in production or the class hasn't been inspected yet
        {
            ListenerFor listener = inspectedClass.getAnnotation(ListenerFor.class);
            ListenersFor listeners = inspectedClass.getAnnotation(ListenersFor.class);
            if (listener != null || listeners != null) {
                //listeners were found using one or both annotations, create and build a new list
                listenerForList = new ArrayList<ListenerFor>();

                if (listener != null) {
                    listenerForList.add(listener);
                }

                if (listeners != null) {
                    listenerForList.addAll(Arrays.asList(listeners.value()));
                }
            } else {
                listenerForList = Collections.emptyList();
            }
        }

        // listeners were found through inspection or from cache, handle them
        if (listenerForList != null && !listenerForList.isEmpty()) {
            for (int i = 0, size = listenerForList.size(); i < size; i++) {
                ListenerFor listenerFor = listenerForList.get(i);
                _handleListenerFor(context, inspected, component, listenerFor);
            }
        }

        if (isProduction && !isCachedList) //if we're in production and the list is not yet cached, store it
        {
            // Note at this point listenerForList cannot be null, but just let this
            // as a sanity check.
            if (listenerForList != null) {
                _classToListenerForMap.put(inspectedClass, listenerForList);
            }
        }
    }

    private void _handleListenerFor(FacesContext context, Object inspected, UIComponent component,
            ListenerFor annotation) {
        // If this annotation is not present on the class in question, no action must be taken.
        if (annotation != null) {
            // Determine the "target" on which to call subscribeToEvent.
            // If the class to which this annotation is attached implements ComponentSystemEventListener
            if (inspected instanceof ComponentSystemEventListener) {
                // If the class to which this annotation is attached is a UIComponent instance, "target" is the
                // UIComponent instance.

                // If the class to which this annotation is attached is a Renderer instance, "target" is the
                // UIComponent instance.

                /*
                 * If "target" is a UIComponent call UIComponent.subscribeToEvent(Class, ComponentSystemEventListener)
                 * passing the systemEventClass() of the annotation as the first argument and the instance of the class
                 * to which this annotation is attached (which must implement ComponentSystemEventListener) as the
                 * second argument.
                 */
                component.subscribeToEvent(annotation.systemEventClass(), (ComponentSystemEventListener) inspected);
            }
            // If the class to which this annotation is attached implements SystemEventListener and does not implement
            // ComponentSystemEventListener, "target" is the Application instance.
            else if (component instanceof SystemEventListener) {
                // use the Application object from the FacesContext (note that a
                // direct use of subscribeToEvent() could cause problems if the
                // Application is wrapped)
                Application application = context.getApplication();

                // If "target" is the Application instance, inspect the value of the sourceClass() annotation attribute
                // value.
                if (Void.class.equals(annotation.sourceClass())) {
                    /*
                     * If the value is Void.class, call Application.subscribeToEvent(Class, SystemEventListener),
                     * passing the value of systemEventClass() as the first argument and the instance of the class to
                     * which this annotation is attached (which must implement SystemEventListener) as the second
                     * argument.
                     */
                    application.subscribeToEvent(annotation.systemEventClass(), (SystemEventListener) inspected);
                } else {
                    /*
                     * Otherwise, call Application.subscribeToEvent(Class, Class, SystemEventListener), passing the
                     * value of systemEventClass() as the first argument, the value of sourceClass() as the second
                     * argument, and the instance of the class to which this annotation is attached (which must
                     * implement SystemEventListener) as the third argument.
                     */
                    application.subscribeToEvent(annotation.systemEventClass(), annotation.sourceClass(),
                            (SystemEventListener) inspected);
                }
            }

            /*
             * If the class to which this annotation is attached implements ComponentSystemEventListener and is neither
             * an instance of Renderer nor UIComponent, the action taken is unspecified. This case must not trigger any
             * kind of error.
             */
        }
    }

    private void _handleResourceDependencyAnnotations(FacesContext context, Class<?> inspectedClass,
            UIComponent component, boolean isProduction) {
        // This and only this method handles @ResourceDependency and @ResourceDependencies annotations
        // The source of these annotations is Class<?> inspectedClass.
        // Because Class<?> and its annotations cannot change
        // during request/response, it is sufficient to process Class<?> only once per view.
        RequestViewContext rvc = RequestViewContext.getCurrentInstance(context);
        if (rvc.isClassAlreadyProcessed(inspectedClass)) {
            return;
        }
        boolean classAlreadyProcessed = false;

        List<ResourceDependency> dependencyList = null;
        boolean isCachedList = false;

        if (isProduction && _classToResourceDependencyMap.containsKey(inspectedClass)) {
            dependencyList = _classToResourceDependencyMap.get(inspectedClass);
            if (dependencyList == null) {
                return; //class has been inspected and did not contain any resource dependency annotations
            } else if (dependencyList.isEmpty()) {
                return;
            }

            isCachedList = true; // else annotations were found in the cache
        }

        if (dependencyList == null) //not in production or the class hasn't been inspected yet
        {
            ResourceDependency dependency = inspectedClass.getAnnotation(ResourceDependency.class);
            ResourceDependencies dependencies = inspectedClass.getAnnotation(ResourceDependencies.class);
            if (dependency != null || dependencies != null) {
                //resource dependencies were found using one or both annotations, create and build a new list
                dependencyList = new ArrayList<ResourceDependency>();

                if (dependency != null) {
                    dependencyList.add(dependency);
                }

                if (dependencies != null) {
                    dependencyList.addAll(Arrays.asList(dependencies.value()));
                }
            } else {
                dependencyList = Collections.emptyList();
            }
        }

        // resource dependencies were found through inspection or from cache, handle them
        if (dependencyList != null && !dependencyList.isEmpty()) {
            for (int i = 0, size = dependencyList.size(); i < size; i++) {
                ResourceDependency dependency = dependencyList.get(i);
                if (!rvc.isResourceDependencyAlreadyProcessed(dependency)) {
                    _handleResourceDependency(context, component, dependency, inspectedClass);
                    rvc.setResourceDependencyAsProcessed(dependency);
                }
            }
        }

        if (isProduction && !isCachedList) //if we're in production and the list is not yet cached, store it
        {
            // Note at this point listenerForList cannot be null, but just let this
            // as a sanity check.
            if (dependencyList != null) {
                _classToResourceDependencyMap.put(inspectedClass, dependencyList);
            }
        }

        if (!classAlreadyProcessed) {
            rvc.setClassProcessed(inspectedClass);
        }
    }

    private void _handleResourceDependency(FacesContext context, UIComponent component,
            ResourceDependency annotation, Class<?> inspectedClass) {
        // If this annotation is not present on the class in question, no action must be taken.
        if (annotation != null) {
            // Create a UIOutput instance by passing javax.faces.Output. to
            // Application.createComponent(java.lang.String).
            UIOutput output = (UIOutput) createComponent(context, UIOutput.COMPONENT_TYPE, null);

            // Get the annotation instance from the class and obtain the values of the name, library, and
            // target attributes.
            String name = annotation.name();
            if (name != null && name.length() > 0) {
                name = ELText.parse(getExpressionFactory(), context.getELContext(), name)
                        .toString(context.getELContext());
            }

            // Obtain the renderer-type for the resource name by passing name to
            // ResourceHandler.getRendererTypeForResourceName(java.lang.String).
            // (note that we can not use this.getResourceHandler(), because the Application might be wrapped)
            String rendererType = context.getApplication().getResourceHandler()
                    .getRendererTypeForResourceName(name);

            // Call setRendererType on the UIOutput instance, passing the renderer-type.
            output.setRendererType(rendererType);

            // If the @ResourceDependency was done inside facelets processing,
            // call setId() and set a proper id from facelets
            setResourceIdOnFaceletsMode(context, output, inspectedClass);

            // Obtain the Map of attributes from the UIOutput component by calling UIComponent.getAttributes().
            Map<String, Object> attributes = output.getAttributes();

            // Store the name into the attributes Map under the key "name".
            attributes.put("name", name);

            // If library is the empty string, let library be null.
            String library = annotation.library();
            if (library != null && library.length() > 0) {
                library = ELText.parse(getExpressionFactory(), context.getELContext(), library)
                        .toString(context.getELContext());
                // If library is non-null, store it under the key "library".
                if ("this".equals(library)) {
                    // Special "this" behavior
                    Resource resource = (Resource) component.getAttributes().get(Resource.COMPONENT_RESOURCE_KEY);
                    if (resource != null) {
                        attributes.put("library", resource.getLibraryName());
                    }
                } else {
                    attributes.put("library", library);
                }
            }

            // If target is the empty string, let target be null.
            String target = annotation.target();
            if (target != null && target.length() > 0) {
                target = ELText.parse(getExpressionFactory(), context.getELContext(), target)
                        .toString(context.getELContext());
                // If target is non-null, store it under the key "target".
                attributes.put("target", target);
                context.getViewRoot().addComponentResource(context, output, target);
            } else {
                // Otherwise, if target is null, call UIViewRoot.addComponentResource(javax.faces.context.FacesContext,
                // javax.faces.component.UIComponent), passing the UIOutput instance as the second argument.
                context.getViewRoot().addComponentResource(context, output);
            }
        }
    }

    private void _inspectRenderer(FacesContext context, UIComponent component, String componentType,
            String rendererType) {
        /*
         * The Renderer instance to inspect must be obtained by calling FacesContext.getRenderKit() and calling
         * RenderKit.getRenderer(java.lang.String, java.lang.String) on the result, passing the argument componentFamily
         * of the newly created component as the first argument and the argument rendererType as the second argument.
         */
        Renderer renderer = context.getRenderKit().getRenderer(component.getFamily(), rendererType);
        if (renderer == null) {
            // If no such Renderer can be found, a message must be logged with a helpful error message.
            log.severe("renderer cannot be found for component type " + componentType + " and renderer type "
                    + rendererType);
        } else {
            // Otherwise, UIComponent.setRendererType(java.lang.String) must be called on the newly created
            // UIComponent instance, passing the argument rendererType as the argument.
            component.setRendererType(rendererType);

            /*
             * except the Renderer for the component to be returned must be inspected for the annotations mentioned in
             * createComponent(ValueExpression, FacesContext, String) as specified in the documentation for that method.
             */
            _handleAnnotations(context, renderer, component);
        }
    }

    private static SystemEvent _traverseListenerList(List<? extends SystemEventListener> listeners,
            Class<? extends SystemEvent> systemEventClass, Object source, SystemEvent event) {
        if (listeners != null && !listeners.isEmpty()) {
            // perf: org.apache.myfaces.ov2021.application.ApplicationImpl.
            //    SystemListenerEntry.getSpecificSourceListenersNotNull(Class<?>)
            // or javax.faces.component.UIComponent.subscribeToEvent(
            //      Class<? extends SystemEvent>, ComponentSystemEventListener)
            // creates a ArrayList:
            for (int i = 0, size = listeners.size(); i < size; i++) {
                SystemEventListener listener = listeners.get(i);
                // Call SystemEventListener.isListenerForSource(java.lang.Object), passing the source argument.
                // If this returns false, take no action on the listener.
                if (listener.isListenerForSource(source)) {
                    // Otherwise, if the event to be passed to the listener instances has not yet been constructed,
                    // construct the event, passing source as the argument to the one-argument constructor that takes
                    // an Object. This same event instance must be passed to all listener instances.
                    event = _createEvent(systemEventClass, source, event);

                    // Call SystemEvent.isAppropriateListener(javax.faces.event.FacesListener), passing the listener
                    // instance as the argument. If this returns false, take no action on the listener.
                    if (event.isAppropriateListener(listener)) {
                        // Call SystemEvent.processListener(javax.faces.event.FacesListener), passing the listener
                        // instance.
                        event.processListener(listener);
                    }
                }
            }
        }

        return event;
    }

    private static SystemEvent _traverseListenerListWithCopy(List<? extends SystemEventListener> listeners,
            Class<? extends SystemEvent> systemEventClass, Object source, SystemEvent event) {
        if (listeners != null && !listeners.isEmpty()) {
            List<SystemEventListener> listenersCopy = new ArrayList<SystemEventListener>();
            int processedListenerIndex = 0;

            for (int i = 0; i < listeners.size(); i++) {
                listenersCopy.add(listeners.get(i));
            }

            // If the inner for is succesful, processedListenerIndex == listenersCopy.size()
            // and the loop will be complete.
            while (processedListenerIndex < listenersCopy.size()) {
                for (; processedListenerIndex < listenersCopy.size(); processedListenerIndex++) {
                    SystemEventListener listener = listenersCopy.get(processedListenerIndex);
                    // Call SystemEventListener.isListenerForSource(java.lang.Object), passing the source argument.
                    // If this returns false, take no action on the listener.
                    if (listener.isListenerForSource(source)) {
                        // Otherwise, if the event to be passed to the listener instances has not yet been constructed,
                        // construct the event, passing source as the argument
                        // to the one-argument constructor that takes
                        // an Object. This same event instance must be passed to all listener instances.
                        event = _createEvent(systemEventClass, source, event);

                        // Call SystemEvent.isAppropriateListener(javax.faces.event.FacesListener), passing the listener
                        // instance as the argument. If this returns false, take no action on the listener.
                        if (event.isAppropriateListener(listener)) {
                            // Call SystemEvent.processListener(javax.faces.event.FacesListener), passing the listener
                            // instance.
                            event.processListener(listener);
                        }
                    }
                }

                boolean listChanged = false;
                if (listeners.size() == listenersCopy.size()) {
                    for (int i = 0; i < listenersCopy.size(); i++) {
                        if (listenersCopy.get(i) != listeners.get(i)) {
                            listChanged = true;
                            break;
                        }
                    }
                } else {
                    listChanged = true;
                }

                if (listChanged) {
                    for (int i = 0; i < listeners.size(); i++) {
                        SystemEventListener listener = listeners.get(i);

                        // check if listenersCopy.get(i) is valid
                        if (i < listenersCopy.size()) {
                            // The normal case is a listener was added, 
                            // so as heuristic, check first
                            // if we can find it at the same location
                            if (!listener.equals(listenersCopy.get(i))) {
                                if (!listenersCopy.contains(listener)) {
                                    listenersCopy.add(listener);
                                }
                            }
                        } else {
                            if (!listenersCopy.contains(listener)) {
                                listenersCopy.add(listener);
                            }
                        }
                    }
                }
            }
        }

        return event;
    }

    /**
     * Method to handle determining if the first request has 
     * been handled by the associated LifecycleImpl.
     * @return true if the first request has already been processed, false otherwise
     */
    private boolean isFirstRequestProcessed() {
        FacesContext context = FacesContext.getCurrentInstance();

        //if firstRequestProcessed is not set, check the application map
        if (!_firstRequestProcessed && context != null && Boolean.TRUE.equals(context.getExternalContext()
                .getApplicationMap().containsKey(LifecycleImpl.FIRST_REQUEST_PROCESSED_PARAM))) {
            _firstRequestProcessed = true;
        }
        return _firstRequestProcessed;
    }

    private static class SystemListenerEntry {
        private List<SystemEventListener> _lstSystemEventListener;
        private Map<Class<?>, List<SystemEventListener>> _sourceClassMap;

        public SystemListenerEntry() {
        }

        public void addListener(SystemEventListener listener) {
            assert listener != null;

            addListenerNoDuplicate(getAnySourceListenersNotNull(), listener);
        }

        public void addListener(SystemEventListener listener, Class<?> source) {
            assert listener != null;

            if (source == null) {
                addListener(listener);
            } else {
                addListenerNoDuplicate(getSpecificSourceListenersNotNull(source), listener);
            }
        }

        public void removeListener(SystemEventListener listener) {
            assert listener != null;

            if (_lstSystemEventListener != null) {
                _lstSystemEventListener.remove(listener);
            }
        }

        public void removeListener(SystemEventListener listener, Class<?> sourceClass) {
            assert listener != null;

            if (sourceClass == null) {
                removeListener(listener);
            } else {
                if (_sourceClassMap != null) {
                    List<SystemEventListener> listeners = _sourceClassMap.get(sourceClass);
                    if (listeners != null) {
                        listeners.remove(listener);
                    }
                }
            }
        }

        public void publish(Class<? extends SystemEvent> systemEventClass, Class<?> classSource, Object source,
                SystemEvent event) {
            if (source != null && _sourceClassMap != null) {
                event = _traverseListenerList(_sourceClassMap.get(classSource), systemEventClass, source, event);
            }

            _traverseListenerList(_lstSystemEventListener, systemEventClass, source, event);
        }

        private void addListenerNoDuplicate(List<SystemEventListener> listeners, SystemEventListener listener) {
            if (!listeners.contains(listener)) {
                listeners.add(listener);
            }
        }

        private synchronized List<SystemEventListener> getAnySourceListenersNotNull() {
            if (_lstSystemEventListener == null) {
                /*
                 * TODO: Check if modification occurs often or not, might have to use a synchronized list instead.
                 * 
                 * Registrations found:
                 */
                _lstSystemEventListener = new CopyOnWriteArrayList<SystemEventListener>();
            }

            return _lstSystemEventListener;
        }

        private synchronized List<SystemEventListener> getSpecificSourceListenersNotNull(Class<?> sourceClass) {
            if (_sourceClassMap == null) {
                _sourceClassMap = new ConcurrentHashMap<Class<?>, List<SystemEventListener>>();
            }

            List<SystemEventListener> list = _sourceClassMap.get(sourceClass);
            if (list == null) {
                /*
                 * TODO: Check if modification occurs often or not, might have to use a synchronized list instead.
                 * 
                 * Registrations found:
                 */
                list = new CopyOnWriteArrayList<SystemEventListener>();
                _sourceClassMap.put(sourceClass, list);
            }

            return list;
        }
    }

    /*
     * private method to look for config objects on a classmap.  The objects can be either a type string
     * or a Class<?> object.  This is done to facilitate lazy loading of config objects.   
     * @param id 
     * @param classMap 
     * @return
     */
    private Class<?> getObjectFromClassMap(String id, Map<String, Object> classMap) {
        Object obj = classMap.get(id);

        if (obj == null) {
            return null; //object for this id wasn't found on the map
        }

        if (obj instanceof Class<?>) {
            return (Class<?>) obj;
        } else if (obj instanceof String) {
            Class<?> clazz = ClassUtils.simpleClassForName((String) obj);
            classMap.put(id, clazz);
            return clazz;
        }

        //object stored in the map for this id is an invalid type.  remove it and return null
        classMap.remove(id);
        return null;
    }

    private boolean isLazyLoadConfigObjects() {
        if (_lazyLoadConfigObjects == null) {
            String configParam = getFaceContext().getExternalContext()
                    .getInitParameter(LAZY_LOAD_CONFIG_OBJECTS_PARAM_NAME);
            _lazyLoadConfigObjects = configParam == null ? LAZY_LOAD_CONFIG_OBJECTS_DEFAULT_VALUE
                    : Boolean.parseBoolean(configParam);
        }
        return _lazyLoadConfigObjects;
    }
}