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

org.jboss.weld.bootstrap.BeanDeployer Maven / Gradle / Ivy

/*
 * JBoss, Home of Professional Open Source
 * Copyright 2008, Red Hat, Inc., and individual contributors
 * by the @authors tag. See the copyright.txt in the distribution for a
 * full listing of individual contributors.
 *
 * Licensed 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.jboss.weld.bootstrap;

import java.lang.annotation.Annotation;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import jakarta.annotation.Priority;
import jakarta.decorator.Decorator;
import jakarta.enterprise.inject.Stereotype;
import jakarta.enterprise.inject.spi.AnnotatedType;
import jakarta.enterprise.inject.spi.Bean;
import jakarta.enterprise.inject.spi.Extension;
import jakarta.enterprise.inject.spi.ProcessBean;
import jakarta.enterprise.inject.spi.ProcessBeanAttributes;
import jakarta.enterprise.inject.spi.ProcessManagedBean;
import jakarta.interceptor.Interceptor;

import org.jboss.weld.Container;
import org.jboss.weld.annotated.enhanced.EnhancedAnnotatedType;
import org.jboss.weld.annotated.slim.SlimAnnotatedType;
import org.jboss.weld.annotated.slim.SlimAnnotatedTypeContext;
import org.jboss.weld.annotated.slim.SlimAnnotatedTypeStore;
import org.jboss.weld.bean.AbstractBean;
import org.jboss.weld.bean.AbstractClassBean;
import org.jboss.weld.bean.RIBean;
import org.jboss.weld.bootstrap.api.ServiceRegistry;
import org.jboss.weld.bootstrap.enablement.GlobalEnablementBuilder;
import org.jboss.weld.bootstrap.events.ProcessAnnotatedTypeImpl;
import org.jboss.weld.logging.BootstrapLogger;
import org.jboss.weld.manager.BeanManagerImpl;
import org.jboss.weld.resources.spi.ClassFileServices;
import org.jboss.weld.resources.spi.ResourceLoader;
import org.jboss.weld.util.AnnotatedTypes;
import org.jboss.weld.util.AnnotationApiAbstraction;
import org.jboss.weld.util.Beans;
import org.jboss.weld.util.collections.SetMultimap;

/**
 * @author Pete Muir
 * @author Jozef Hartinger
 * @author alesj
 * @author Marko Luksa
 */
public class BeanDeployer extends AbstractBeanDeployer {

    private final ResourceLoader resourceLoader;
    private final SlimAnnotatedTypeStore annotatedTypeStore;
    private final GlobalEnablementBuilder globalEnablementBuilder;
    private final AnnotationApiAbstraction annotationApi;
    private final ClassFileServices classFileServices;

    public BeanDeployer(BeanManagerImpl manager, ServiceRegistry services) {
        this(manager, services, BeanDeployerEnvironmentFactory.newEnvironment(manager));
    }

    public BeanDeployer(BeanManagerImpl manager, ServiceRegistry services, BeanDeployerEnvironment environment) {
        super(manager, services, environment);
        this.resourceLoader = manager.getServices().get(ResourceLoader.class);
        this.annotatedTypeStore = manager.getServices().get(SlimAnnotatedTypeStore.class);
        this.globalEnablementBuilder = manager.getServices().get(GlobalEnablementBuilder.class);
        this.annotationApi = manager.getServices().get(AnnotationApiAbstraction.class);
        this.classFileServices = manager.getServices().get(ClassFileServices.class);
    }

    /**
     * Loads a given class, creates a {@link SlimAnnotatedTypeContext} for it and stores it in {@link BeanDeployerEnvironment}.
     */
    public BeanDeployer addClass(String className, AnnotatedTypeLoader loader) {
        addIfNotNull(loader.loadAnnotatedType(className, getManager().getId()));
        return this;
    }

    public BeanDeployer addClass(Class clazz, AnnotatedTypeLoader loader) {
        addIfNotNull(loader.loadAnnotatedType(clazz, getManager().getId()));
        return this;
    }

    private  SlimAnnotatedTypeContext addIfNotNull(SlimAnnotatedTypeContext ctx) {
        if (ctx != null) {
            getEnvironment().addAnnotatedType(ctx);
        }
        return ctx;
    }

    /**
     * Attempts to find a {@code @Priority} annotation declared on a stereotype(s) of given {@code AnnotatedType}.
     * Returns the value in this annotation, or {@code null} if none was found.
     *
     * If the {@code AnnotatedType} declares more than one stereotype and at least two of them declare different
     * {@code @Priority} values, a definition exception is thrown.
     *
     * If there are multiple {@code @Priority} values in a hierarchy of single stereotype, first annotation value is
     * used.
     *
     * @param type AnnotatedType to be searched
     * @return an Integer representing the priority value, null if none was found
     */
    private Integer findPriorityInStereotypes(AnnotatedType type) {
        // search all annotations
        Set foundPriorities = new HashSet<>();
        for (Annotation annotation : type.getAnnotations()) {
            // identify stereotypes
            Class annotationClass = annotation.annotationType();
            if (annotationClass.getAnnotation(Stereotype.class) != null) {
                recursiveStereotypeSearch(annotationClass, foundPriorities);
            }
        }
        // more than one value found, throw exception
        if (foundPriorities.size() > 1) {
            throw BootstrapLogger.LOG.multiplePriorityValuesDeclared(type);
        }
        // no priority found
        if (foundPriorities.isEmpty()) {
            return null;
        }
        // exactly one value found
        return foundPriorities.iterator().next();
    }

    private void recursiveStereotypeSearch(Class stereotype, Set foundPriorities) {
        // search each stereotype for priority annotation, store all values found
        Priority priorityAnnotation = stereotype.getAnnotation(Priority.class);
        if (priorityAnnotation != null) {
            // if found, store the value
            foundPriorities.add(priorityAnnotation.value());
        }
        // perform a recursive search for more stereotypes
        for (Annotation annotation : stereotype.getAnnotations()) {
            Class annotationClass = annotation.annotationType();
            if (annotationClass.getAnnotation(Stereotype.class) != null) {
                recursiveStereotypeSearch(annotationClass, foundPriorities);
            }
        }
    }

    private void processPriority(AnnotatedType type) {
        // check if @Priority is declared directly on the AnnotatedType
        Object priority = type.getAnnotation(annotationApi.PRIORITY_ANNOTATION_CLASS);
        Integer value;
        if (priority == null) {
            // if not declared, search in any stereotypes of given AnnotatedType
            value = findPriorityInStereotypes(type);
        } else {
            value = annotationApi.getPriority(priority);
        }
        if (value != null) {
            // if we discovered any priority, register the AnnotatedType into global enablement
            if (type.isAnnotationPresent(Interceptor.class)) {
                globalEnablementBuilder.addInterceptor(type.getJavaClass(), value);
            } else if (type.isAnnotationPresent(Decorator.class)) {
                globalEnablementBuilder.addDecorator(type.getJavaClass(), value);
            } else {
                /*
                 * An alternative may be given a priority for the application by placing the @Priority annotation on the bean
                 * class that declares the producer method, field or resource.
                 */
                globalEnablementBuilder.addAlternative(type.getJavaClass(), value);
            }
        }
    }

    public  BeanDeployer addSyntheticClass(AnnotatedType source, Extension extension, String suffix) {
        if (suffix == null) {
            suffix = AnnotatedTypes.createTypeId(source);
        }
        getEnvironment().addSyntheticAnnotatedType(
                classTransformer.getUnbackedAnnotatedType(source, getManager().getId(), suffix), extension);
        return this;
    }

    public BeanDeployer addClasses(Iterable classes) {
        AnnotatedTypeLoader loader = createAnnotatedTypeLoader();
        for (String className : classes) {
            addClass(className, loader);
        }
        return this;
    }

    public BeanDeployer addLoadedClasses(Iterable> classes) {
        AnnotatedTypeLoader loader = createAnnotatedTypeLoader();
        for (Class clazz : classes) {
            addClass(clazz, loader);
        }
        return this;
    }

    protected AnnotatedTypeLoader createAnnotatedTypeLoader() {
        if (classFileServices != null) {
            // Since FastProcessAnnotatedTypeResolver is installed after BeanDeployers are created, we need to query deploymentManager's services instead of the manager of this deployer
            final FastProcessAnnotatedTypeResolver resolver = Container.instance(getManager()).deploymentManager().getServices()
                    .get(FastProcessAnnotatedTypeResolver.class);
            if (resolver != null) {
                return new FastAnnotatedTypeLoader(getManager(), classTransformer, classFileServices, containerLifecycleEvents,
                        resolver);
            }
        }
        // if FastProcessAnnotatedTypeResolver is not available, fall back to AnnotatedTypeLoader
        return new AnnotatedTypeLoader(getManager(), classTransformer, containerLifecycleEvents);
    }

    public void processAnnotatedTypes() {
        Set> classesToBeAdded = new HashSet>();
        Set> classesToBeRemoved = new HashSet>();

        for (SlimAnnotatedTypeContext annotatedTypeContext : getEnvironment().getAnnotatedTypes()) {
            SlimAnnotatedType annotatedType = annotatedTypeContext.getAnnotatedType();
            final ProcessAnnotatedTypeImpl event = containerLifecycleEvents.fireProcessAnnotatedType(getManager(),
                    annotatedTypeContext);

            // process the result
            if (event != null) {
                if (event.isVeto()) {
                    getEnvironment().vetoJavaClass(annotatedType.getJavaClass());
                    classesToBeRemoved.add(annotatedTypeContext);
                } else {
                    boolean dirty = event.isDirty();
                    if (dirty) {
                        classesToBeRemoved.add(annotatedTypeContext); // remove the original class
                        classesToBeAdded.add(SlimAnnotatedTypeContext.of(event.getResultingAnnotatedType(),
                                annotatedTypeContext.getExtension()));
                    }
                    processPriority(event.getResultingAnnotatedType());
                }
            } else {
                processPriority(annotatedType);
            }
        }
        getEnvironment().removeAnnotatedTypes(classesToBeRemoved);
        getEnvironment().addAnnotatedTypes(classesToBeAdded);
    }

    public void registerAnnotatedTypes() {
        for (SlimAnnotatedTypeContext ctx : getEnvironment().getAnnotatedTypes()) {
            annotatedTypeStore.put(ctx.getAnnotatedType());
        }
    }

    public void createClassBeans() {
        SetMultimap, SlimAnnotatedType> otherWeldClasses = SetMultimap.newSetMultimap();

        for (SlimAnnotatedTypeContext ctx : getEnvironment().getAnnotatedTypes()) {
            createClassBean(ctx.getAnnotatedType(), otherWeldClasses);
        }
        // create session beans
        ejbSupport.createSessionBeans(getEnvironment(), otherWeldClasses, getManager());
    }

    protected void createClassBean(SlimAnnotatedType annotatedType,
            SetMultimap, SlimAnnotatedType> otherWeldClasses) {
        boolean managedBeanOrDecorator = !ejbSupport.isEjb(annotatedType.getJavaClass())
                && Beans.isTypeManagedBeanOrDecoratorOrInterceptor(annotatedType);
        if (managedBeanOrDecorator) {
            containerLifecycleEvents.preloadProcessInjectionTarget(annotatedType.getJavaClass());
            containerLifecycleEvents.preloadProcessBeanAttributes(annotatedType.getJavaClass());
            EnhancedAnnotatedType weldClass = classTransformer.getEnhancedAnnotatedType(annotatedType);
            if (weldClass.isAnnotationPresent(Decorator.class)) {
                containerLifecycleEvents.preloadProcessBean(ProcessBean.class, annotatedType.getJavaClass());
                validateDecorator(weldClass);
                createDecorator(weldClass);
            } else if (weldClass.isAnnotationPresent(Interceptor.class)) {
                containerLifecycleEvents.preloadProcessBean(ProcessBean.class, annotatedType.getJavaClass());
                validateInterceptor(weldClass);
                createInterceptor(weldClass);
            } else if (!weldClass.isAbstract()) {
                containerLifecycleEvents.preloadProcessBean(ProcessManagedBean.class, annotatedType.getJavaClass());
                createManagedBean(weldClass);
            }
        } else {
            if (Beans.isDecoratorDeclaringInAppropriateConstructor(annotatedType)) {
                BootstrapLogger.LOG.decoratorWithNonCdiConstructor(annotatedType.getJavaClass().getName());
            }
            Class scopeClass = Beans.getBeanDefiningAnnotationScope(annotatedType);
            if (scopeClass != null && !Beans.hasSimpleCdiConstructor(annotatedType)) {
                BootstrapLogger.LOG.annotatedTypeNotRegisteredAsBeanDueToMissingAppropriateConstructor(
                        annotatedType.getJavaClass().getName(),
                        scopeClass.getSimpleName());
            }
            otherWeldClasses.put(annotatedType.getJavaClass(), annotatedType);
        }
    }

    /**
     * Fires {@link ProcessBeanAttributes} for each enabled bean and updates the environment based on the events.
     */
    public void processClassBeanAttributes() {
        preInitializeBeans(getEnvironment().getClassBeans());
        preInitializeBeans(getEnvironment().getDecorators());
        preInitializeBeans(getEnvironment().getInterceptors());

        processBeans(getEnvironment().getClassBeans());
        processBeans(getEnvironment().getDecorators());
        processBeans(getEnvironment().getInterceptors());
    }

    private void preInitializeBeans(Iterable> beans) {
        for (AbstractBean bean : beans) {
            bean.preInitialize();
        }
    }

    protected void processBeans(Iterable> beans) {
        // firstly, we handle PIT and PP
        processInjectionTargetEvents(beans);
        processProducerEvents(beans);
        // now we move onto PBA
        processBeanAttributes(beans);
    }

    private void processSpecializingBeans(Iterable> previouslySpecializedBeans) {
        // For a set of previously specialized beans that are re-enabled, we need to fire PP followed by PBA
        // Note that this is intentionally different from processBeans() method which also contains PIT event
        processProducerEvents(previouslySpecializedBeans);
        processBeanAttributes(previouslySpecializedBeans);
    }

    protected void processBeanAttributes(Iterable> beans) {
        if (!containerLifecycleEvents.isProcessBeanAttributesObserved()) {
            return;
        }
        if (!beans.iterator().hasNext()) {
            return; // exit recursion
        }

        Collection> vetoedBeans = new HashSet>();
        Collection> previouslySpecializedBeans = new HashSet>();
        for (AbstractBean bean : beans) {
            // fire ProcessBeanAttributes for class beans
            boolean vetoed = fireProcessBeanAttributes(bean);
            if (vetoed) {
                vetoedBeans.add(bean);
            }
        }

        // remove vetoed class beans
        for (AbstractBean bean : vetoedBeans) {
            if (bean.isSpecializing()) {
                previouslySpecializedBeans.addAll(specializationAndEnablementRegistry.resolveSpecializedBeans(bean));
                specializationAndEnablementRegistry.vetoSpecializingBean(bean);
            }
            getEnvironment().vetoBean(bean);
        }
        // if a specializing bean was vetoed, let's process the specializing bean now
        processSpecializingBeans(previouslySpecializedBeans);
    }

    public void createProducersAndObservers() {
        for (AbstractClassBean bean : getEnvironment().getClassBeans()) {
            createObserversProducersDisposers(bean);
        }
    }

    public void processProducerAttributes() {
        processBeans(getEnvironment().getProducerFields());
        // process BeanAttributes for producer methods
        preInitializeBeans(getEnvironment().getProducerMethodBeans());
        processBeans(getEnvironment().getProducerMethodBeans());
    }

    public void deploy() {
        initializeBeans();
        fireProcessBeanEvents();
        deployBeans();
        initializeObserverMethods();
        deployObserverMethods();
    }

    protected void validateInterceptor(EnhancedAnnotatedType weldClass) {
        if (weldClass.isAnnotationPresent(Decorator.class)) {
            throw BootstrapLogger.LOG.beanIsBothInterceptorAndDecorator(weldClass.getName());
        }
    }

    protected void validateDecorator(EnhancedAnnotatedType weldClass) {
        if (weldClass.isAnnotationPresent(Interceptor.class)) {
            throw BootstrapLogger.LOG.beanIsBothInterceptorAndDecorator(weldClass.getName());
        }
    }

    public void doAfterBeanDiscovery(List> beanList) {
        for (Bean bean : beanList) {
            if (bean instanceof RIBean) {
                ((RIBean) bean).initializeAfterBeanDiscovery();
            }
        }
    }

    public void registerCdiInterceptorsForMessageDrivenBeans() {
        ejbSupport.registerCdiInterceptorsForMessageDrivenBeans(getEnvironment(), getManager());
    }

    public ResourceLoader getResourceLoader() {
        return resourceLoader;
    }

    public void cleanup() {
        getEnvironment().cleanup();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy