/* * 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.lang.reflect.Type; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; import javax.decorator.Decorator; import javax.enterprise.inject.spi.AnnotatedType; import javax.enterprise.inject.spi.Bean; import javax.enterprise.inject.spi.Extension; import javax.enterprise.inject.spi.ProcessBean; import javax.enterprise.inject.spi.ProcessBeanAttributes; import javax.enterprise.inject.spi.ProcessManagedBean; import javax.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; import org.jboss.weld.util.reflection.Reflections; /** * @author Pete Muir * @author Jozef Hartinger * @author alesj * @author Marko Luksa */ public class BeanDeployer extends AbstractBeanDeployer<BeanDeployerEnvironment> { 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 <T> SlimAnnotatedTypeContext<T> addIfNotNull(SlimAnnotatedTypeContext<T> ctx) { if (ctx != null) { getEnvironment().addAnnotatedType(ctx); } return ctx; } private void processPriority(AnnotatedType<?> type) { Object priority = type.getAnnotation(annotationApi.PRIORITY_ANNOTATION_CLASS); if (priority != null) { Integer value = annotationApi.getPriority(priority); if (value != null) { 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 <T> BeanDeployer addSyntheticClass(AnnotatedType<T> 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<String> classes) { AnnotatedTypeLoader loader = createAnnotatedTypeLoader(); for (String className : classes) { addClass(className, loader); } return this; } public BeanDeployer addLoadedClasses(Iterable<Class<?>> 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<SlimAnnotatedTypeContext<?>> classesToBeAdded = new HashSet<SlimAnnotatedTypeContext<?>>(); Set<SlimAnnotatedTypeContext<?>> classesToBeRemoved = new HashSet<SlimAnnotatedTypeContext<?>>(); 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<Class<?>, 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<Class<?>, 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()); processBeanAttributes(getEnvironment().getClassBeans()); processBeanAttributes(getEnvironment().getDecorators()); processBeanAttributes(getEnvironment().getInterceptors()); // now that we know that the bean won't be vetoed, it's the right time to register @New injection points searchForNewBeanDeclarations(getEnvironment().getClassBeans()); searchForNewBeanDeclarations(getEnvironment().getDecorators()); searchForNewBeanDeclarations(getEnvironment().getInterceptors()); } private void preInitializeBeans(Iterable<? extends AbstractBean<?, ?>> beans) { for (AbstractBean<?, ?> bean : beans) { bean.preInitialize(); } } protected void processBeanAttributes(Iterable<? extends AbstractBean<?, ?>> beans) { if (!containerLifecycleEvents.isProcessBeanAttributesObserved()) { return; } if (!beans.iterator().hasNext()) { return; // exit recursion } Collection<AbstractBean<?, ?>> vetoedBeans = new HashSet<AbstractBean<?, ?>>(); Collection<AbstractBean<?, ?>> previouslySpecializedBeans = new HashSet<AbstractBean<?, ?>>(); 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 processBeanAttributes(previouslySpecializedBeans); } protected void searchForNewBeanDeclarations(Iterable<? extends AbstractBean<?, ?>> beans) { for (AbstractBean<?, ?> bean : beans) { getEnvironment().addNewBeansFromInjectionPoints(bean); } } public void createProducersAndObservers() { for (AbstractClassBean<?> bean : getEnvironment().getClassBeans()) { createObserversProducersDisposers(bean); } } public void processProducerAttributes() { processBeanAttributes(getEnvironment().getProducerFields()); searchForNewBeanDeclarations(getEnvironment().getProducerFields()); // process BeanAttributes for producer methods preInitializeBeans(getEnvironment().getProducerMethodBeans()); processBeanAttributes(getEnvironment().getProducerMethodBeans()); searchForNewBeanDeclarations(getEnvironment().getProducerMethodBeans()); } public void createNewBeans() { for (Type type : getEnvironment().getNewBeanTypes()) { Class<?> clazz = Reflections.getRawType(type); if (!ejbSupport.isEjb(clazz)) { createNewManagedBean(clazz, type); } } ejbSupport.createNewSessionBeans(getEnvironment(), getManager()); } public void deploy() { initializeBeans(); fireBeanEvents(); 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(); } }