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

org.jboss.as.ee.component.ComponentDescription Maven / Gradle / Ivy

There is a newer version: 35.0.0.Beta1
Show newest version
/*
 * Copyright The WildFly Authors
 * SPDX-License-Identifier: Apache-2.0
 */

package org.jboss.as.ee.component;

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.jboss.as.ee.logging.EeLogger;
import org.jboss.as.ee.component.interceptors.InterceptorClassDescription;
import org.jboss.as.naming.ManagedReferenceFactory;
import org.jboss.as.naming.deployment.ContextNames;
import org.jboss.as.server.deployment.DeploymentPhaseContext;
import org.jboss.as.server.deployment.DeploymentUnitProcessingException;
import org.jboss.as.server.deployment.reflect.ClassReflectionIndex;
import org.jboss.invocation.proxy.MethodIdentifier;
import org.jboss.modules.ModuleLoader;
import org.jboss.msc.service.ServiceBuilder;
import org.jboss.msc.service.ServiceName;
import org.jboss.msc.value.InjectedValue;

/**
 * A description of a generic Jakarta EE component.  The description is pre-classloading so it references everything by name.
 *
 * @author David M. Lloyd
 * @author Richard Opalka
 */
public class ComponentDescription implements ResourceInjectionTarget {

    private static final DefaultComponentConfigurator DEFAULT_COMPONENT_CONFIGURATOR = new DefaultComponentConfigurator();
    private static final DefaultInterceptorConfigurator DEFAULT_INTERCEPTOR_CONFIGURATOR = new DefaultInterceptorConfigurator();
    private static final DefaultComponentViewConfigurator DEFAULT_COMPONENT_VIEW_CONFIGURATOR = new DefaultComponentViewConfigurator();

    private final ServiceName serviceName;
    private ServiceName contextServiceName;
    private final String componentName;
    private final String componentClassName;
    private final EEModuleDescription moduleDescription;
    private final Set views = new HashSet();

    /**
     * Interceptors methods that have been defined by the deployment descriptor
     */
    private final Map interceptorClassOverrides = new HashMap();

    private List classInterceptors = new ArrayList();
    private List defaultInterceptors = new ArrayList();
    private final Map> methodInterceptors = new HashMap>();
    private final Set methodExcludeDefaultInterceptors = new HashSet();
    private final Set methodExcludeClassInterceptors = new HashSet();
    private Set allInterceptors;
    private boolean excludeDefaultInterceptors = false;
    private boolean ignoreLifecycleInterceptors = false;

    private final Set dependencies = new HashSet();

    private ComponentNamingMode namingMode = ComponentNamingMode.USE_MODULE;

    private DeploymentDescriptorEnvironment deploymentDescriptorEnvironment;


    // Bindings
    private final List bindingConfigurations = new ArrayList();
    //injections that have been set in the components deployment descriptor
    private final Map> resourceInjections = new HashMap>();

    private final Deque configurators = new ArrayDeque();


    /**
     * If this component is deployed in a bean deployment archive this stores the id of the BDA
     */
    private String beanDeploymentArchiveId;

    /**
     * Construct a new instance.
     *
     * @param componentName             the component name
     * @param componentClassName        the component instance class name
     * @param moduleDescription         the EE module description
     * @param deploymentUnitServiceName the service name of the DU containing this component
     */
    public ComponentDescription(final String componentName, final String componentClassName, final EEModuleDescription moduleDescription, final ServiceName deploymentUnitServiceName) {
        this.moduleDescription = moduleDescription;
        if (componentName == null) {
            throw EeLogger.ROOT_LOGGER.nullName("component");
        }
        if (componentClassName == null) {
            throw EeLogger.ROOT_LOGGER.nullVar("componentClassName", "component", componentName);
        }
        if (moduleDescription == null) {
            throw EeLogger.ROOT_LOGGER.nullVar("moduleDescription", "component", componentName);
        }
        if (deploymentUnitServiceName == null) {
            throw EeLogger.ROOT_LOGGER.nullVar("deploymentUnitServiceName", "component", componentName);
        }
        serviceName = BasicComponent.serviceNameOf(deploymentUnitServiceName, componentName);
        this.componentName = componentName;
        this.componentClassName = componentClassName;
        configurators.addLast(DEFAULT_COMPONENT_CONFIGURATOR);
        configurators.addLast(DEFAULT_INTERCEPTOR_CONFIGURATOR);
        configurators.addLast(DEFAULT_COMPONENT_VIEW_CONFIGURATOR);
    }

    public ComponentConfiguration createConfiguration(final ClassReflectionIndex classIndex, final ClassLoader moduleClassLoader, final ModuleLoader moduleLoader) {
        return new ComponentConfiguration(this, classIndex, moduleClassLoader, moduleLoader);
    }

    /**
     * Get the component name.
     *
     * @return the component name
     */
    public String getComponentName() {
        return componentName;
    }

    /**
     * Set context service name.
     *
     * @param contextServiceName
     */
    public void setContextServiceName(final ServiceName contextServiceName) {
        this.contextServiceName = contextServiceName;
    }

    /**
     * Get the context service name.
     *
     * @return the context service name
     */
    public ServiceName getContextServiceName() {
        if (contextServiceName != null) return contextServiceName;
        if (getNamingMode() == ComponentNamingMode.CREATE) {
            return ContextNames.contextServiceNameOfComponent(getApplicationName(), getModuleName(), getComponentName());
        } else if (getNamingMode() == ComponentNamingMode.USE_MODULE) {
            return ContextNames.contextServiceNameOfModule(getApplicationName(), getModuleName());
        } else {
            throw new IllegalStateException();
        }
    }

    /**
     * Get the base service name for this component.
     *
     * @return the base service name
     */
    public ServiceName getServiceName() {
        return serviceName;
    }

    /**
     * Get the service name of this components start service
     *
     * @return The start service name
     */
    public ServiceName getStartServiceName() {
        return serviceName.append("START");
    }

    /**
     * Get the service name of this components create service
     *
     * @return The create service name
     */
    public ServiceName getCreateServiceName() {
        return serviceName.append("CREATE");
    }

    /**
     * Get the component instance class name.
     *
     * @return the component class name
     */
    public String getComponentClassName() {
        return componentClassName;
    }

    /**
     * Get the component's module name.
     *
     * @return the module name
     */
    public String getModuleName() {
        return moduleDescription.getModuleName();
    }

    /**
     * Get the component's module's application name.
     *
     * @return the application name
     */
    public String getApplicationName() {
        return moduleDescription.getApplicationName();
    }

    /**
     * Get the list of interceptor classes applied directly to class. These interceptors will have lifecycle methods invoked
     *
     * @return the interceptor classes
     */
    public List getClassInterceptors() {
        return classInterceptors;
    }

    /**
     * Override the class interceptors with a new set of interceptors
     *
     * @param classInterceptors
     */
    public void setClassInterceptors(List classInterceptors) {
        this.classInterceptors = classInterceptors;
        this.allInterceptors = null;
    }

    /**
     * @return the components default interceptors
     */
    public List getDefaultInterceptors() {
        return defaultInterceptors;
    }

    public void setDefaultInterceptors(final List defaultInterceptors) {
        allInterceptors = null;
        this.defaultInterceptors = defaultInterceptors;
    }

    /**
     * Returns a combined map of class and method level interceptors
     *
     * @return all interceptors on the class
     */
    public Set getAllInterceptors() {
        if (allInterceptors == null) {
            allInterceptors = new HashSet();
            allInterceptors.addAll(classInterceptors);
            if (!excludeDefaultInterceptors) {
                allInterceptors.addAll(defaultInterceptors);
            }
            for (List interceptors : methodInterceptors.values()) {
                allInterceptors.addAll(interceptors);
            }
        }
        return allInterceptors;
    }

    /**
     * @return true if the ExcludeDefaultInterceptors annotation was applied to the class
     */
    public boolean isExcludeDefaultInterceptors() {
        return excludeDefaultInterceptors;
    }

    public void setExcludeDefaultInterceptors(boolean excludeDefaultInterceptors) {
        allInterceptors = null;
        this.excludeDefaultInterceptors = excludeDefaultInterceptors;
    }

    public boolean isIgnoreLifecycleInterceptors() {
        return ignoreLifecycleInterceptors;
    }

    /**
     * If this component should ignore lifecycle interceptors. This should generally only be set when they are going
     * to be handled by an external framework such as Weld.
     *
     */
    public void setIgnoreLifecycleInterceptors(boolean ignoreLifecycleInterceptors) {
        this.ignoreLifecycleInterceptors = ignoreLifecycleInterceptors;
    }

    /**
     * @param method The method that has been annotated @ExcludeDefaultInterceptors
     */
    public void excludeDefaultInterceptors(MethodIdentifier method) {
        methodExcludeDefaultInterceptors.add(method);
    }

    public boolean isExcludeDefaultInterceptors(MethodIdentifier method) {
        return methodExcludeDefaultInterceptors.contains(method);
    }

    /**
     * @param method The method that has been annotated @ExcludeClassInterceptors
     */
    public void excludeClassInterceptors(MethodIdentifier method) {
        methodExcludeClassInterceptors.add(method);
    }

    public boolean isExcludeClassInterceptors(MethodIdentifier method) {
        return methodExcludeClassInterceptors.contains(method);
    }

    /**
     * Add a class level interceptor.
     *
     * @param description the interceptor class description
     */
    public void addClassInterceptor(InterceptorDescription description) {
        classInterceptors.add(description);
        this.allInterceptors = null;
    }

    /**
     * Returns the {@link InterceptorDescription} for the passed interceptorClassName, if such a class
     * interceptor exists for this component description. Else returns null.
     *
     * @param interceptorClassName The fully qualified interceptor class name
     * @return
     */
    public InterceptorDescription getClassInterceptor(String interceptorClassName) {
        for (InterceptorDescription interceptor : classInterceptors) {
            if (interceptor.getInterceptorClassName().equals(interceptorClassName)) {
                return interceptor;
            }
        }
        return null;
    }

    /**
     * Get the method interceptor configurations.  The key is the method identifier, the value is
     * the set of class names of interceptors to configure on that method.
     *
     * @return the method interceptor configurations
     */
    public Map> getMethodInterceptors() {
        return methodInterceptors;
    }

    /**
     * Add a method interceptor class name.
     *
     * @param method      the method
     * @param description the interceptor descriptor
     */
    public void addMethodInterceptor(MethodIdentifier method, InterceptorDescription description) {
        //we do not add method level interceptors to the set of interceptor classes,
        //as their around invoke annotations
        List interceptors = methodInterceptors.get(method);
        if (interceptors == null) {
            methodInterceptors.put(method, interceptors = new ArrayList());
        }
        final String name = description.getInterceptorClassName();
        // add the interceptor class to the EEModuleDescription
        interceptors.add(description);
        this.allInterceptors = null;
    }

    /**
     * Sets the method level interceptors for a method, and marks it as exclude class and default level interceptors.
     * 

* This is used to set the final interceptor order after it has been modifier by the deployment descriptor * * @param identifier the method identifier * @param interceptorDescriptions The interceptors */ public void setMethodInterceptors(MethodIdentifier identifier, List interceptorDescriptions) { methodInterceptors.put(identifier, interceptorDescriptions); methodExcludeClassInterceptors.add(identifier); methodExcludeDefaultInterceptors.add(identifier); } /** * Adds an interceptor class method override, merging it with existing overrides (if any) * * @param className The class name * @param override The method override */ public void addInterceptorMethodOverride(final String className, final InterceptorClassDescription override) { interceptorClassOverrides.put(className, InterceptorClassDescription.merge(interceptorClassOverrides.get(className), override)); } /** * Get the naming mode of this component. * * @return the naming mode */ public ComponentNamingMode getNamingMode() { return namingMode; } /** * Set the naming mode of this component. May not be {@code null}. * * @param namingMode the naming mode */ public void setNamingMode(final ComponentNamingMode namingMode) { if (namingMode == null) { throw EeLogger.ROOT_LOGGER.nullVar("namingMode", "component", componentName); } this.namingMode = namingMode; } /** * @return The module description for the component */ public EEModuleDescription getModuleDescription() { return moduleDescription; } /** * Add a dependency to this component. If the same dependency is added multiple times, only the first will * take effect. * * @param serviceName the service name of the dependency */ public void addDependency(ServiceName serviceName) { if (serviceName == null) { throw EeLogger.ROOT_LOGGER.nullVar("serviceName", "component", componentName); } dependencies.add(serviceName); } /** * Get the dependency set. * * @return the dependency set */ public Set getDependencies() { return dependencies; } public DeploymentDescriptorEnvironment getDeploymentDescriptorEnvironment() { return deploymentDescriptorEnvironment; } public void setDeploymentDescriptorEnvironment(DeploymentDescriptorEnvironment deploymentDescriptorEnvironment) { this.deploymentDescriptorEnvironment = deploymentDescriptorEnvironment; } /** * Get the binding configurations for this component. This list contains bindings which are specific to the * component. * * @return the binding configurations */ public List getBindingConfigurations() { return bindingConfigurations; } /** * Get the list of views which apply to this component. * * @return the list of views */ public Set getViews() { return views; } /** * * * @return true If this component type is eligible for a timer service */ public boolean isTimerServiceApplicable() { return false; } /** * * @return true if this component has timeout methods and is eligible for a 'real' timer service */ public boolean isTimerServiceRequired() { return isTimerServiceApplicable() && !getTimerMethods().isEmpty(); } /** * * @return The set of all method identifiers for the timeout methods */ public Set getTimerMethods() { return Collections.emptySet(); } public boolean isPassivationApplicable() { return false; } /** * Get the configurators for this component. * * @return the configurators */ public Deque getConfigurators() { return configurators; } public boolean isIntercepted() { return true; } /** * @return true if errors should be ignored when installing this component */ public boolean isOptional() { return false; } static class InjectedConfigurator implements DependencyConfigurator { private final ResourceInjectionConfiguration injectionConfiguration; private final ComponentConfiguration configuration; private final DeploymentPhaseContext context; private final InjectedValue managedReferenceFactoryValue; InjectedConfigurator(final ResourceInjectionConfiguration injectionConfiguration, final ComponentConfiguration configuration, final DeploymentPhaseContext context, final InjectedValue managedReferenceFactoryValue) { this.injectionConfiguration = injectionConfiguration; this.configuration = configuration; this.context = context; this.managedReferenceFactoryValue = managedReferenceFactoryValue; } public void configureDependency(final ServiceBuilder serviceBuilder, ComponentStartService service) throws DeploymentUnitProcessingException { InjectionSource.ResolutionContext resolutionContext = new InjectionSource.ResolutionContext( configuration.getComponentDescription().getNamingMode() == ComponentNamingMode.USE_MODULE, configuration.getComponentName(), configuration.getModuleName(), configuration.getApplicationName() ); injectionConfiguration.getSource().getResourceValue(resolutionContext, serviceBuilder, context, managedReferenceFactoryValue); } } public String getBeanDeploymentArchiveId() { return beanDeploymentArchiveId; } public void setBeanDeploymentArchiveId(final String beanDeploymentArchiveId) { this.beanDeploymentArchiveId = beanDeploymentArchiveId; } public void addResourceInjection(final ResourceInjectionConfiguration injection) { String className = injection.getTarget().getClassName(); Map map = resourceInjections.get(className); if (map == null) { resourceInjections.put(className, map = new HashMap()); } map.put(injection.getTarget(), injection); } public Map getResourceInjections(final String className) { Map injections = resourceInjections.get(className); if (injections == null) { return Collections.emptyMap(); } else { return Collections.unmodifiableMap(injections); } } /** * If this method returns true then Weld will directly create the component instance, * which will apply interceptors and decorators via sub classing. * * For most components this is not necessary. * * Also not that even though Jakarta Enterprise Beans's are intercepted, their interceptor is done through * a different method that integrates with the existing Jakarta Enterprise Beans interceptor chain * */ public boolean isCDIInterceptorEnabled() { return false; } public static InterceptorClassDescription mergeInterceptorConfig(final Class clazz, final EEModuleClassDescription classDescription, final ComponentDescription description, final boolean metadataComplete) { final InterceptorClassDescription interceptorConfig; if (classDescription != null && !metadataComplete) { interceptorConfig = InterceptorClassDescription.merge(classDescription.getInterceptorClassDescription(), description.interceptorClassOverrides.get(clazz.getName())); } else { interceptorConfig = InterceptorClassDescription.merge(null, description.interceptorClassOverrides.get(clazz.getName())); } return interceptorConfig; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy