
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 extends Annotation> 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 extends Annotation> 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 extends Annotation> 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 extends Annotation> 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 extends AbstractBean, ?>> beans) {
for (AbstractBean, ?> bean : beans) {
bean.preInitialize();
}
}
protected void processBeans(Iterable extends AbstractBean, ?>> beans) {
// firstly, we handle PIT and PP
processInjectionTargetEvents(beans);
processProducerEvents(beans);
// now we move onto PBA
processBeanAttributes(beans);
}
private void processSpecializingBeans(Iterable extends AbstractBean, ?>> 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 extends AbstractBean, ?>> 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 extends Bean>> 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