All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sun.faces.application.applicationimpl.InstanceFactory Maven / Gradle / Ivy

There is a newer version: 4.1.1
Show newest version
/*
 * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v. 2.0, which is available at
 * http://www.eclipse.org/legal/epl-2.0.
 *
 * This Source Code may also be made available under the following Secondary
 * Licenses when the conditions for such availability set forth in the
 * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
 * version 2 with the GNU Classpath Exception, which is available at
 * https://www.gnu.org/software/classpath/license.html.
 *
 * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
 */

package com.sun.faces.application.applicationimpl;

import static com.sun.faces.application.ApplicationImpl.THIS_LIBRARY;
import static com.sun.faces.config.WebConfiguration.BooleanWebContextInitParameter.DateTimeConverterUsesSystemTimezone;
import static com.sun.faces.config.WebConfiguration.BooleanWebContextInitParameter.RegisterConverterPropertyEditors;
import static com.sun.faces.util.Util.isEmpty;
import static com.sun.faces.util.Util.loadClass;
import static com.sun.faces.util.Util.notNull;
import static com.sun.faces.util.Util.notNullNamedObject;
import static jakarta.faces.application.Resource.COMPONENT_RESOURCE_KEY;
import static jakarta.faces.component.UIComponent.ATTRS_WITH_DECLARED_DEFAULT_VALUES;
import static jakarta.faces.component.UIComponent.BEANINFO_KEY;
import static jakarta.faces.component.UIComponent.COMPOSITE_COMPONENT_TYPE_KEY;
import static java.beans.Introspector.getBeanInfo;
import static java.beans.PropertyEditorManager.findEditor;
import static java.text.MessageFormat.format;
import static java.util.Collections.unmodifiableMap;
import static java.util.logging.Level.FINE;
import static java.util.logging.Level.SEVERE;
import static java.util.logging.Level.WARNING;

import java.beans.BeanDescriptor;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.beans.PropertyEditor;
import java.beans.PropertyEditorManager;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.text.MessageFormat;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.TimeZone;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.sun.faces.application.ApplicationAssociate;
import com.sun.faces.application.ConverterPropertyEditorFactory;
import com.sun.faces.application.ViewMemberInstanceFactoryMetadataMap;
import com.sun.faces.cdi.CdiUtils;
import com.sun.faces.config.WebConfiguration;
import com.sun.faces.util.FacesLogger;
import com.sun.faces.util.MessageUtils;
import com.sun.faces.util.ReflectionUtils;
import com.sun.faces.util.Util;

import jakarta.el.ExpressionFactory;
import jakarta.el.ValueExpression;
import jakarta.enterprise.inject.spi.BeanManager;
import jakarta.faces.FacesException;
import jakarta.faces.application.Application;
import jakarta.faces.application.Resource;
import jakarta.faces.component.UIComponent;
import jakarta.faces.component.behavior.Behavior;
import jakarta.faces.context.FacesContext;
import jakarta.faces.convert.Converter;
import jakarta.faces.convert.DateTimeConverter;
import jakarta.faces.render.RenderKit;
import jakarta.faces.render.Renderer;
import jakarta.faces.validator.Validator;
import jakarta.faces.view.ViewDeclarationLanguage;

public class InstanceFactory {

    // Log instance for this class
    private static final Logger LOGGER = FacesLogger.APPLICATION.getLogger();

    private static final String CONTEXT = "context";
    private static final String COMPONENT_EXPRESSION = "componentExpression";
    private static final String COMPONENT_TYPE = "componentType";
    private static final String COMPONENT_CLASS = "componentClass";

    private static final Map[]> STANDARD_CONV_ID_TO_TYPE_MAP = new HashMap<>(8, 1.0f);
    private static final Map, String> STANDARD_TYPE_TO_CONV_ID_MAP = new HashMap<>(16, 1.0f);

    static {
        STANDARD_CONV_ID_TO_TYPE_MAP.put("jakarta.faces.Byte", new Class[] { Byte.TYPE, Byte.class });
        STANDARD_CONV_ID_TO_TYPE_MAP.put("jakarta.faces.Boolean", new Class[] { Boolean.TYPE, Boolean.class });
        STANDARD_CONV_ID_TO_TYPE_MAP.put("jakarta.faces.Character", new Class[] { Character.TYPE, Character.class });
        STANDARD_CONV_ID_TO_TYPE_MAP.put("jakarta.faces.Short", new Class[] { Short.TYPE, Short.class });
        STANDARD_CONV_ID_TO_TYPE_MAP.put("jakarta.faces.Integer", new Class[] { Integer.TYPE, Integer.class });
        STANDARD_CONV_ID_TO_TYPE_MAP.put("jakarta.faces.Long", new Class[] { Long.TYPE, Long.class });
        STANDARD_CONV_ID_TO_TYPE_MAP.put("jakarta.faces.Float", new Class[] { Float.TYPE, Float.class });
        STANDARD_CONV_ID_TO_TYPE_MAP.put("jakarta.faces.Double", new Class[] { Double.TYPE, Double.class });
        for (Map.Entry[]> entry : STANDARD_CONV_ID_TO_TYPE_MAP.entrySet()) {
            Class[] types = entry.getValue();
            String key = entry.getKey();
            for (Class clazz : types) {
                STANDARD_TYPE_TO_CONV_ID_MAP.put(clazz, key);
            }
        }
    }

    private final String[] STANDARD_BY_TYPE_CONVERTER_CLASSES = { "java.math.BigDecimal", "java.lang.Boolean", "java.lang.Byte", "java.lang.Character",
            "java.lang.Double", "java.lang.Float", "java.lang.Integer", "java.lang.Long", "java.lang.Short", "java.lang.Enum" };

    private Map, Object> converterTypeMap;
    private boolean registerPropertyEditors;
    private boolean passDefaultTimeZone;

    private TimeZone systemTimeZone;

    private static final class ComponentResourceClassNotFound {
    }

    //
    // These four maps store store "identifier" | "class name"
    // mappings.
    //
    private ViewMemberInstanceFactoryMetadataMap componentMap;
    private ViewMemberInstanceFactoryMetadataMap behaviorMap;
    private ViewMemberInstanceFactoryMetadataMap converterIdMap;
    private ViewMemberInstanceFactoryMetadataMap validatorMap;

    private Set defaultValidatorIds;
    private volatile Map defaultValidatorInfo;

    private final ApplicationAssociate associate;

    /**
     * Stores the bean manager.
     */
    private BeanManager beanManager;

    public InstanceFactory(ApplicationAssociate applicationAssociate) {
        associate = applicationAssociate;

        componentMap = new ViewMemberInstanceFactoryMetadataMap<>(new ConcurrentHashMap<>());
        converterIdMap = new ViewMemberInstanceFactoryMetadataMap<>(new ConcurrentHashMap<>());
        converterTypeMap = new ConcurrentHashMap<>();
        validatorMap = new ViewMemberInstanceFactoryMetadataMap<>(new ConcurrentHashMap<>());
        defaultValidatorIds = new LinkedHashSet<>();
        behaviorMap = new ViewMemberInstanceFactoryMetadataMap<>(new ConcurrentHashMap<>());

        WebConfiguration webConfig = WebConfiguration.getInstance(FacesContext.getCurrentInstance().getExternalContext());
        registerPropertyEditors = webConfig.isOptionEnabled(RegisterConverterPropertyEditors);

        passDefaultTimeZone = webConfig.isOptionEnabled(DateTimeConverterUsesSystemTimezone);
        if (passDefaultTimeZone) {
            systemTimeZone = TimeZone.getDefault();
        }
    }

    /*
     * @see jakarta.faces.application.Application#addComponent(java.lang.String, java.lang.String)
     */
    public void addComponent(String componentType, String componentClass) {
        notNull(COMPONENT_TYPE, componentType);
        notNull(COMPONENT_CLASS, componentClass);

        if (LOGGER.isLoggable(FINE) && componentMap.containsKey(componentType)) {
            LOGGER.log(FINE, "componentType {0} has already been registered.  Replacing existing component class type {1} with {2}.",
                    new Object[] { componentType, componentMap.get(componentType), componentClass });
        }

        componentMap.put(componentType, componentClass);

        if (LOGGER.isLoggable(FINE)) {
            LOGGER.fine(MessageFormat.format("added component of type ''{0}'' and class ''{1}''", componentType, componentClass));
        }
    }

    public UIComponent createComponent(ValueExpression componentExpression, FacesContext context, String componentType) throws FacesException {
        notNull(COMPONENT_EXPRESSION, componentExpression);
        notNull(CONTEXT, context);
        notNull(COMPONENT_TYPE, componentType);

        return createComponentApplyAnnotations(context, componentExpression, componentType, null, true);
    }

    public UIComponent createComponent(String componentType) throws FacesException {
        notNull(COMPONENT_TYPE, componentType);

        return createComponentApplyAnnotations(FacesContext.getCurrentInstance(), componentType, null, true);
    }

    public UIComponent createComponent(FacesContext context, Resource componentResource, ExpressionFactory expressionFactory) throws FacesException {

        // RELEASE_PENDING (rlubke,driscoll) this method needs review.

        notNull(CONTEXT, context);
        notNull("componentResource", componentResource);

        UIComponent result = null;

        // Use the application defined in the FacesContext as we may be calling
        // overriden methods
        Application app = context.getApplication();

        ViewDeclarationLanguage vdl = app.getViewHandler().getViewDeclarationLanguage(context, context.getViewRoot().getViewId());
        BeanInfo componentMetadata = vdl.getComponentMetadata(context, componentResource);

        if (componentMetadata != null) {
            BeanDescriptor componentBeanDescriptor = componentMetadata.getBeanDescriptor();

            // Step 1. See if the composite component author explicitly
            // gave a componentType as part of the composite component metadata
            ValueExpression valueExpression = (ValueExpression) componentBeanDescriptor.getValue(COMPOSITE_COMPONENT_TYPE_KEY);

            if (valueExpression != null) {
                String componentType = (String) valueExpression.getValue(context.getELContext());
                if (!isEmpty(componentType)) {
                    result = app.createComponent(componentType);
                }
            }
        }

        // Step 2. If that didn't work, if a script based resource can be
        // found for the scriptComponentResource, see if a component can be generated from it
        if (result == null) {
            Resource scriptComponentResource = vdl.getScriptComponentResource(context, componentResource);

            if (scriptComponentResource != null) {
                result = createComponentFromScriptResource(context, scriptComponentResource, componentResource);
            }
        }

        // Step 3. Use the libraryName of the resource as the java package
        // and use the resourceName as the class name. See
        // if a Java class can be loaded
        if (result == null) {
            String packageName = componentResource.getLibraryName();
            String className = componentResource.getResourceName();
            className = packageName + '.' + className.substring(0, className.lastIndexOf('.'));
            try {
                Class clazz = (Class) componentMap.get(className);
                if (clazz == null) {
                    clazz = loadClass(className, this);
                }
                if (clazz != ComponentResourceClassNotFound.class) {
                    if (!associate.isDevModeEnabled()) {
                        componentMap.put(className, clazz);
                    }
                    result = (UIComponent) clazz.newInstance();
                }
            } catch (ClassNotFoundException ex) {
                if (!associate.isDevModeEnabled()) {
                    componentMap.put(className, ComponentResourceClassNotFound.class);
                }
            } catch (InstantiationException | IllegalAccessException | ClassCastException ie) {
                throw new FacesException(ie);
            }
        }

        // Step 4. Use jakarta.faces.NamingContainer as the component type
        if (result == null) {
            result = app.createComponent("jakarta.faces.NamingContainer");
        }

        result.setRendererType("jakarta.faces.Composite");

        Map attrs = result.getAttributes();
        attrs.put(COMPONENT_RESOURCE_KEY, componentResource);
        attrs.put(BEANINFO_KEY, componentMetadata);

        associate.getAnnotationManager().applyComponentAnnotations(context, result);
        pushDeclaredDefaultValuesToAttributesMap(context, componentMetadata, attrs, result, expressionFactory);

        return result;
    }

    public UIComponent createComponent(FacesContext context, String componentType, String rendererType) {
        notNull(CONTEXT, context);
        notNull(COMPONENT_TYPE, componentType);

        return createComponentApplyAnnotations(context, componentType, rendererType, true);
    }

    public UIComponent createComponent(ValueExpression componentExpression, FacesContext context, String componentType, String rendererType) {
        notNull(COMPONENT_EXPRESSION, componentExpression);
        notNull(CONTEXT, context);
        notNull(COMPONENT_TYPE, componentType);

        return createComponentApplyAnnotations(context, componentExpression, componentType, rendererType, true);
    }

    /*
     * @see jakarta.faces.application.Application#getComponentTypes()
     */
    public Iterator getComponentTypes() {
        return componentMap.keySet().iterator();
    }

    /*
     * @see jakarta.faces.application.Application#addBehavior(String, String)
     */
    public void addBehavior(String behaviorId, String behaviorClass) {
        notNull("behaviorId", behaviorId);
        notNull("behaviorClass", behaviorClass);

        if (LOGGER.isLoggable(FINE) && behaviorMap.containsKey(behaviorId)) {
            LOGGER.log(FINE, "behaviorId {0} has already been registered.  Replacing existing behavior class type {1} with {2}.",
                    new Object[] { behaviorId, behaviorMap.get(behaviorId), behaviorClass });
        }

        behaviorMap.put(behaviorId, behaviorClass);

        if (LOGGER.isLoggable(FINE)) {
            LOGGER.fine(MessageFormat.format("added behavior of type ''{0}'' class ''{1}''", behaviorId, behaviorClass));
        }
    }

    /*
     * @see jakarta.faces.application.Application#createBehavior(String)
     */
    public Behavior createBehavior(String behaviorId) throws FacesException {
        notNull("behaviorId", behaviorId);

        Behavior behavior = createCDIBehavior(behaviorId);
        if (behavior != null) {
            return behavior;
        }

        behavior = newThing(behaviorId, behaviorMap);

        notNullNamedObject(behavior, behaviorId, "faces.cannot_instantiate_behavior_error");

        if (LOGGER.isLoggable(FINE)) {
            LOGGER.fine(MessageFormat.format("created behavior of type ''{0}''", behaviorId));
        }

        associate.getAnnotationManager().applyBehaviorAnnotations(FacesContext.getCurrentInstance(), behavior);

        return behavior;
    }

    /*
     * @see jakarta.faces.application.Application#getBehaviorIds()
     */
    public Iterator getBehaviorIds() {
        return behaviorMap.keySet().iterator();
    }

    public void addConverter(String converterId, String converterClass) {
        notNull("converterId", converterId);
        notNull("converterClass", converterClass);

        if (LOGGER.isLoggable(FINE) && converterIdMap.containsKey(converterId)) {
            LOGGER.log(FINE, "converterId {0} has already been registered.  Replacing existing converter class type {1} with {2}.",
                    new Object[] { converterId, converterIdMap.get(converterId), converterClass });
        }

        converterIdMap.put(converterId, converterClass);

        Class[] types = STANDARD_CONV_ID_TO_TYPE_MAP.get(converterId);
        if (types != null) {
            for (Class clazz : types) {
                // go directly against map to prevent cyclic method calls
                converterTypeMap.put(clazz, converterClass);
                addPropertyEditorIfNecessary(clazz);
            }
        }

        if (LOGGER.isLoggable(FINE)) {
            LOGGER.fine(format("added converter of type ''{0}'' and class ''{1}''", converterId, converterClass));
        }
    }

    /*
     * @see jakarta.faces.application.Application#addConverter(Class, String)
     */
    public void addConverter(Class targetClass, String converterClass) {
        notNull("targetClass", targetClass);
        notNull("converterClass", converterClass);

        String converterId = STANDARD_TYPE_TO_CONV_ID_MAP.get(targetClass);
        if (converterId != null) {
            addConverter(converterId, converterClass);
        } else {
            if (LOGGER.isLoggable(FINE) && converterTypeMap.containsKey(targetClass)) {
                LOGGER.log(FINE, "converter target class {0} has already been registered.  Replacing existing converter class type {1} with {2}.",
                        new Object[] { targetClass.getName(), converterTypeMap.get(targetClass), converterClass });
            }

            converterTypeMap.put(targetClass, converterClass);
            addPropertyEditorIfNecessary(targetClass);
        }

        if (LOGGER.isLoggable(FINE)) {
            LOGGER.fine(format("added converter of class type ''{0}''", converterClass));
        }
    }

    /*
     * @see jakarta.faces.application.Application#createConverter(String)
     */
    public Converter createConverter(String converterId) {
        notNull("converterId", converterId);

        Converter converter = createCDIConverter(converterId);
        if (converter != null) {
            return converter;
        }

        converter = newThing(converterId, converterIdMap);

        notNullNamedObject(converter, converterId, "faces.cannot_instantiate_converter_error");

        if (LOGGER.isLoggable(FINE)) {
            LOGGER.fine(MessageFormat.format("created converter of type ''{0}''", converterId));
        }

        if (passDefaultTimeZone && converter instanceof DateTimeConverter) {
            ((DateTimeConverter) converter).setTimeZone(systemTimeZone);
        }

        associate.getAnnotationManager().applyConverterAnnotations(FacesContext.getCurrentInstance(), converter);

        return converter;
    }

    /*
     * @see jakarta.faces.application.Application#createConverter(Class)
     */
    public Converter createConverter(Class targetClass) {
        notNull("targetClass", targetClass);
        Converter returnVal = null;

        BeanManager beanManager = getBeanManager();
        returnVal = CdiUtils.createConverter(beanManager, targetClass);
        if (returnVal != null) {
            return returnVal;
        }

        returnVal = (Converter) newConverter(targetClass, converterTypeMap, targetClass);
        if (returnVal != null) {
            if (LOGGER.isLoggable(Level.FINE)) {
                LOGGER.fine(MessageFormat.format("Created converter of type ''{0}''", returnVal.getClass().getName()));
            }
            if (passDefaultTimeZone && returnVal instanceof DateTimeConverter) {
                ((DateTimeConverter) returnVal).setTimeZone(systemTimeZone);
            }
            associate.getAnnotationManager().applyConverterAnnotations(FacesContext.getCurrentInstance(), returnVal);
            return returnVal;
        }

        // Search for converters registered to interfaces implemented by
        // targetClass
        Class[] interfaces = targetClass.getInterfaces();
        if (interfaces != null) {
            for (int i = 0; i < interfaces.length; i++) {
                returnVal = createConverterBasedOnClass(interfaces[i], targetClass);
                if (returnVal != null) {
                    if (LOGGER.isLoggable(Level.FINE)) {
                        LOGGER.fine(MessageFormat.format("Created converter of type ''{0}''", returnVal.getClass().getName()));
                    }
                    if (passDefaultTimeZone && returnVal instanceof DateTimeConverter) {
                        ((DateTimeConverter) returnVal).setTimeZone(systemTimeZone);
                    }
                    associate.getAnnotationManager().applyConverterAnnotations(FacesContext.getCurrentInstance(), returnVal);
                    return returnVal;
                }
            }
        }

        // Search for converters registered to superclasses of targetClass
        Class superclass = targetClass.getSuperclass();
        if (superclass != null) {
            returnVal = createConverterBasedOnClass(superclass, targetClass);
            if (returnVal != null) {
                if (LOGGER.isLoggable(Level.FINE)) {
                    LOGGER.fine(MessageFormat.format("Created converter of type ''{0}''", returnVal.getClass().getName()));
                }
                if (passDefaultTimeZone && returnVal instanceof DateTimeConverter) {
                    ((DateTimeConverter) returnVal).setTimeZone(systemTimeZone);
                }
                associate.getAnnotationManager().applyConverterAnnotations(FacesContext.getCurrentInstance(), returnVal);
                return returnVal;
            }
        }

        return returnVal;
    }

    /*
     * @see jakarta.faces.application.Application#getConverterIds()
     */
    public Iterator getConverterIds() {
        return converterIdMap.keySet().iterator();

    }

    /*
     * @see jakarta.faces.application.Application#getConverterTypes()
     */
    public Iterator> getConverterTypes() {
        return converterTypeMap.keySet().iterator();
    }

    /*
     * @see jakarta.faces.application.Application#addValidator(String, String)
     */
    public void addValidator(String validatorId, String validatorClass) {
        notNull("validatorId", validatorId);
        notNull("validatorClass", validatorClass);

        if (LOGGER.isLoggable(Level.FINE) && validatorMap.containsKey(validatorId)) {
            LOGGER.log(Level.FINE, "validatorId {0} has already been registered.  Replacing existing validator class type {1} with {2}.",
                    new Object[] { validatorId, validatorMap.get(validatorId), validatorClass });
        }

        validatorMap.put(validatorId, validatorClass);

        if (LOGGER.isLoggable(Level.FINE)) {
            LOGGER.fine(MessageFormat.format("added validator of type ''{0}'' class ''{1}''", validatorId, validatorClass));
        }

    }

    /*
     * @see jakarta.faces.application.Application#createValidator(String)
     */
    public Validator createValidator(String validatorId) throws FacesException {
        notNull("validatorId", validatorId);

        Validator validator = createCDIValidator(validatorId);
        if (validator != null) {
            return validator;
        }

        validator = newThing(validatorId, validatorMap);

        notNullNamedObject(validator, validatorId, "faces.cannot_instantiate_validator_error");

        if (LOGGER.isLoggable(FINE)) {
            LOGGER.fine(MessageFormat.format("created validator of type ''{0}''", validatorId));
        }

        associate.getAnnotationManager().applyValidatorAnnotations(FacesContext.getCurrentInstance(), validator);

        return validator;
    }

    /*
     * @see jakarta.faces.application.Application#getValidatorIds()
     */
    public Iterator getValidatorIds() {
        return validatorMap.keySet().iterator();
    }

    /*
     * @see jakarta.faces.application.Application#addDefaultValidatorId(String)
     */
    public synchronized void addDefaultValidatorId(String validatorId) {
        notNull("validatorId", validatorId);

        defaultValidatorInfo = null;
        defaultValidatorIds.add(validatorId);
    }

    /*
     * @see jakarta.faces.application.Application#getDefaultValidatorInfo()
     */
    public Map getDefaultValidatorInfo() {

        if (defaultValidatorInfo == null) {
            synchronized (this) {
                if (defaultValidatorInfo == null) {
                    defaultValidatorInfo = new LinkedHashMap<>();
                    if (!defaultValidatorIds.isEmpty()) {
                        for (String id : defaultValidatorIds) {
                            String validatorClass;
                            Object result = validatorMap.get(id);
                            if (null != result) {
                                if (result instanceof Class) {
                                    validatorClass = ((Class) result).getName();
                                } else {
                                    validatorClass = result.toString();
                                }
                                defaultValidatorInfo.put(id, validatorClass);
                            }
                        }

                    }
                }
            }
            defaultValidatorInfo = unmodifiableMap(defaultValidatorInfo);
        }

        return defaultValidatorInfo;

    }

    // --------------------------------------------------------- Private Methods

    private UIComponent createComponentFromScriptResource(FacesContext context, Resource scriptComponentResource, Resource componentResource) {

        UIComponent result = null;

        String className = scriptComponentResource.getResourceName();
        int lastDot = className.lastIndexOf('.');
        className = className.substring(0, lastDot);

        try {

            Class componentClass = (Class) componentMap.get(className);
            if (componentClass == null) {
                componentClass = Util.loadClass(className, this);
            }
            if (!associate.isDevModeEnabled()) {
                componentMap.put(className, componentClass);
            }
            result = (UIComponent) componentClass.newInstance();
        } catch (IllegalAccessException | InstantiationException | ClassNotFoundException ex) {
            if (LOGGER.isLoggable(Level.SEVERE)) {
                LOGGER.log(Level.SEVERE, null, ex);
            }
        }

        if (result != null) {
            // Make sure the resource is there for the annotation processor.
            result.getAttributes().put(Resource.COMPONENT_RESOURCE_KEY, componentResource);
            // In case there are any "this" references,
            // make sure they can be resolved.
            context.getAttributes().put(THIS_LIBRARY, componentResource.getLibraryName());
            try {
                associate.getAnnotationManager().applyComponentAnnotations(context, result);
            } finally {
                context.getAttributes().remove(THIS_LIBRARY);
            }
        }

        return result;

    }

    /**
     * Leveraged by
     * {@link Application#createComponent(jakarta.el.ValueExpression, jakarta.faces.context.FacesContext, String)} and
     * {@link Application#createComponent(jakarta.el.ValueExpression, jakarta.faces.context.FacesContext, String, String)}.
     * This method will apply any component and render annotations that may be present.
     */
    private UIComponent createComponentApplyAnnotations(FacesContext ctx, ValueExpression componentExpression, String componentType, String rendererType,
            boolean applyAnnotations) {

        UIComponent c;

        try {
            c = (UIComponent) componentExpression.getValue(ctx.getELContext());

            if (c == null) {
                c = this.createComponentApplyAnnotations(ctx, componentType, rendererType, applyAnnotations);
                componentExpression.setValue(ctx.getELContext(), c);
            } else if (applyAnnotations) {
                applyAnnotations(ctx, rendererType, c);
            }
        } catch (Exception ex) {
            throw new FacesException(ex);
        }

        return c;

    }

    /**
     * Leveraged by {@link Application#createComponent(String)} and
     * {@link Application#createComponent(jakarta.faces.context.FacesContext, String, String)} This method will apply any
     * component and render annotations that may be present.
     */
    private UIComponent createComponentApplyAnnotations(FacesContext ctx, String componentType, String rendererType, boolean applyAnnotations) {

        UIComponent component;
        try {
            component = newThing(componentType, componentMap);
        } catch (Exception ex) {
            if (LOGGER.isLoggable(SEVERE)) {
                LOGGER.log(Level.SEVERE, "faces.cannot_instantiate_component_error", componentType);
            }
            throw new FacesException(ex);
        }

        notNullNamedObject(component, componentType, "faces.cannot_instantiate_component_error");

        if (LOGGER.isLoggable(FINE)) {
            LOGGER.log(FINE, MessageFormat.format("Created component with component type of ''{0}''", componentType));
        }

        if (applyAnnotations) {
            applyAnnotations(ctx, rendererType, component);
        }

        return component;
    }

    /**
     * Process any annotations associated with this component/renderer.
     */
    private void applyAnnotations(FacesContext ctx, String rendererType, UIComponent c) {

        if (c != null && ctx != null) {
            associate.getAnnotationManager().applyComponentAnnotations(ctx, c);
            if (rendererType != null) {
                RenderKit rk = ctx.getRenderKit();
                Renderer r = null;
                if (rk != null) {
                    r = rk.getRenderer(c.getFamily(), rendererType);
                    if (r != null) {
                        c.setRendererType(rendererType);
                        associate.getAnnotationManager().applyRendererAnnotations(ctx, r, c);
                    }
                }
                if ((rk == null || r == null) && LOGGER.isLoggable(Level.FINE)) {
                    LOGGER.log(Level.FINE, "Unable to create Renderer with rendererType {0} for component with component type of {1}",
                            new Object[] { rendererType, c.getFamily() });
                }
            }
        }
    }

    /**
     * 

* PRECONDITIONS: the values in the Map are either Strings representing fully qualified java class names, or * java.lang.Class instances. *

*

* ALGORITHM: Look in the argument map for a value for the argument key. If found, if the value is instanceof String, * assume the String specifies a fully qualified java class name and obtain the java.lang.Class instance for that String * using Util.loadClass(). Replace the String instance in the argument map with the Class instance. If the value is * instanceof Class, proceed. Assert that the value is either instanceof java.lang.Class or java.lang.String. *

*

* Now that you have a java.lang.class, call its newInstance and return it as the result of this method. *

* * @param key Used to look up the value in the Map. * @param map The Map that will be searched. * @return The new object instance. */ @SuppressWarnings("unchecked") private T newThing(String key, ViewMemberInstanceFactoryMetadataMap map) { Object result; Class clazz; Object value; value = map.get(key); if (value == null) { return null; } assert value instanceof String || value instanceof Class; if (value instanceof String) { String cValue = (String) value; try { clazz = Util.loadClass(cValue, value); if (!associate.isDevModeEnabled()) { map.put(key, clazz); } assert clazz != null; } catch (Exception e) { throw new FacesException(e.getMessage(), e); } } else { clazz = (Class) value; } try { result = clazz.newInstance(); } catch (Throwable t) { Throwable previousT; do { previousT = t; if (LOGGER.isLoggable(Level.SEVERE)) { LOGGER.log(Level.SEVERE, "Unable to load class: ", t); } } while (null != (t = t.getCause())); t = previousT; throw new FacesException(MessageUtils.getExceptionMessageString(MessageUtils.CANT_INSTANTIATE_CLASS_ERROR_MESSAGE_ID, clazz.getName()), t); } return (T) result; } /* * This method makes it so that any cc:attribute elements that have a "default" attribute value have those values pushed * into the composite component attribute map so that programmatic access (as opposed to EL access) will find the * attribute values. * */ @SuppressWarnings("unchecked") private void pushDeclaredDefaultValuesToAttributesMap(FacesContext context, BeanInfo componentMetadata, Map attrs, UIComponent component, ExpressionFactory expressionFactory) { Collection attributesWithDeclaredDefaultValues = null; PropertyDescriptor[] propertyDescriptors = null; for (PropertyDescriptor propertyDescriptor : componentMetadata.getPropertyDescriptors()) { Object defaultValue = propertyDescriptor.getValue("default"); if (defaultValue != null) { String key = propertyDescriptor.getName(); boolean isLiteralText = false; if (defaultValue instanceof ValueExpression) { isLiteralText = ((ValueExpression) defaultValue).isLiteralText(); if (isLiteralText) { defaultValue = ((ValueExpression) defaultValue).getValue(context.getELContext()); } } // Ensure this attribute is not a method-signature. method-signature // declared default values are handled in retargetMethodExpressions. if (propertyDescriptor.getValue("method-signature") == null || propertyDescriptor.getValue("type") != null) { if (attributesWithDeclaredDefaultValues == null) { BeanDescriptor beanDescriptor = componentMetadata.getBeanDescriptor(); attributesWithDeclaredDefaultValues = (Collection) beanDescriptor.getValue(ATTRS_WITH_DECLARED_DEFAULT_VALUES); if (attributesWithDeclaredDefaultValues == null) { attributesWithDeclaredDefaultValues = new HashSet<>(); beanDescriptor.setValue(ATTRS_WITH_DECLARED_DEFAULT_VALUES, attributesWithDeclaredDefaultValues); } } attributesWithDeclaredDefaultValues.add(key); // Only store the attribute if it is literal text. If it // is a ValueExpression, it will be handled explicitly in // CompositeComponentAttributesELResolver.ExpressionEvalMap.get(). // If it is a MethodExpression, it will be dealt with in // retargetMethodExpressions. if (isLiteralText) { try { if (propertyDescriptors == null) { propertyDescriptors = getBeanInfo(component.getClass()).getPropertyDescriptors(); } } catch (IntrospectionException e) { throw new FacesException(e); } defaultValue = convertValueToTypeIfNecessary(key, defaultValue, propertyDescriptors, expressionFactory); attrs.put(key, defaultValue); } } } } } /** * Helper method to convert a value to a type as defined in PropertyDescriptor(s) * * @param name * @param value * @param propertyDescriptors * @return value */ private Object convertValueToTypeIfNecessary(String name, Object value, PropertyDescriptor[] propertyDescriptors, ExpressionFactory expressionFactory) { for (PropertyDescriptor propertyDescriptor : propertyDescriptors) { if (propertyDescriptor.getName().equals(name)) { value = expressionFactory.coerceToType(value, propertyDescriptor.getPropertyType()); break; } } return value; } /** *

* To enable EL Coercion to use Faces Custom converters, this method will call * PropertyEditorManager.registerEditor(), passing the ConverterPropertyEditor class for the * targetClass if the target class is not one of the standard by-type converter target classes. * * @param targetClass the target class for which a PropertyEditory may or may not be created */ private void addPropertyEditorIfNecessary(Class targetClass) { if (!registerPropertyEditors) { return; } PropertyEditor editor = findEditor(targetClass); if (editor != null) { return; } String className = targetClass.getName(); // Don't add a PropertyEditor for the standard by-type converters. if (targetClass.isPrimitive()) { return; } for (String standardClass : STANDARD_BY_TYPE_CONVERTER_CLASSES) { if (standardClass.indexOf(className) != -1) { return; } } Class editorClass = ConverterPropertyEditorFactory.getDefaultInstance().definePropertyEditorClassFor(targetClass); if (editorClass != null) { PropertyEditorManager.registerEditor(targetClass, editorClass); } else { if (LOGGER.isLoggable(WARNING)) { LOGGER.warning(MessageFormat.format("definePropertyEditorClassFor({0}) returned null.", targetClass.getName())); } } } private Converter createConverterBasedOnClass(Class targetClass, Class baseClass) { Converter returnVal = (Converter) newConverter(targetClass, converterTypeMap, baseClass); if (returnVal != null) { if (LOGGER.isLoggable(Level.FINE)) { LOGGER.fine(MessageFormat.format("Created converter of type ''{0}''", returnVal.getClass().getName())); } return returnVal; } // Search for converters registered to interfaces implemented by // targetClass Class[] interfaces = targetClass.getInterfaces(); if (interfaces != null) { for (int i = 0; i < interfaces.length; i++) { returnVal = createConverterBasedOnClass(interfaces[i], null); if (returnVal != null) { if (LOGGER.isLoggable(Level.FINE)) { LOGGER.fine(MessageFormat.format("Created converter of type ''{0}''", returnVal.getClass().getName())); } return returnVal; } } } // Search for converters registered to superclasses of targetClass Class superclass = targetClass.getSuperclass(); if (superclass != null) { returnVal = createConverterBasedOnClass(superclass, targetClass); if (returnVal != null) { if (LOGGER.isLoggable(Level.FINE)) { LOGGER.fine(MessageFormat.format("Created converter of type ''{0}''", returnVal.getClass().getName())); } return returnVal; } } return returnVal; } /** *

* The same as newThing except that a single argument constructor that accepts a Class is looked for before calling the * no-arg version. *

* *

* PRECONDITIONS: the values in the Map are either Strings representing fully qualified java class names, or * java.lang.Class instances. *

*

* ALGORITHM: Look in the argument map for a value for the argument key. If found, if the value is instanceof String, * assume the String specifies a fully qualified java class name and obtain the java.lang.Class instance for that String * using Util.loadClass(). Replace the String instance in the argument map with the Class instance. If the value is * instanceof Class, proceed. Assert that the value is either instanceof java.lang.Class or java.lang.String. *

*

* Now that you have a java.lang.class, call its newInstance and return it as the result of this method. *

* * @param key Used to look up the value in the Map. * @param map The Map that will be searched. * @param targetClass the target class for the single argument ctor * @return The new object instance. */ protected Object newConverter(Class key, Map, Object> map, Class targetClass) { assert key != null && map != null; Object result = null; Class clazz; Object value; value = map.get(key); if (value == null) { return null; } assert value instanceof String || value instanceof Class; if (value instanceof String) { String cValue = (String) value; try { clazz = Util.loadClass(cValue, value); if (!associate.isDevModeEnabled()) { map.put(key, clazz); } assert clazz != null; } catch (Exception e) { throw new FacesException(e.getMessage(), e); } } else { clazz = (Class) value; } Constructor ctor = ReflectionUtils.lookupConstructor(clazz, Class.class); Throwable cause = null; if (ctor != null) { try { result = ctor.newInstance(targetClass); } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { cause = e; } } else { try { result = clazz.newInstance(); } catch (InstantiationException | IllegalAccessException e) { cause = e; } } if (null != cause) { throw new FacesException(MessageUtils.getExceptionMessageString(MessageUtils.CANT_INSTANTIATE_CLASS_ERROR_MESSAGE_ID, clazz.getName()), cause); } return result; } /** * Get the bean manager. * * @return the bean manager. */ private BeanManager getBeanManager() { if (beanManager == null) { FacesContext facesContext = FacesContext.getCurrentInstance(); beanManager = Util.getCdiBeanManager(facesContext); } return beanManager; } private Behavior createCDIBehavior(String behaviorId) { return CdiUtils.createBehavior(getBeanManager(), behaviorId); } private Converter createCDIConverter(String converterId) { return CdiUtils.createConverter(getBeanManager(), converterId); } private Validator createCDIValidator(String validatorId) { return CdiUtils.createValidator(getBeanManager(), validatorId); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy