| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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.apache.webbeans.config; |
| |
| import org.apache.webbeans.annotation.AnnotationManager; |
| import org.apache.webbeans.annotation.AnyLiteral; |
| import org.apache.webbeans.component.AbstractProducerBean; |
| import org.apache.webbeans.component.BeanAttributesImpl; |
| import org.apache.webbeans.component.BuiltInOwbBean; |
| import org.apache.webbeans.component.CdiInterceptorBean; |
| import org.apache.webbeans.component.DecoratorBean; |
| import org.apache.webbeans.component.EnterpriseBeanMarker; |
| import org.apache.webbeans.component.InjectionTargetBean; |
| import org.apache.webbeans.component.ManagedBean; |
| import org.apache.webbeans.component.OwbBean; |
| import org.apache.webbeans.component.ProducerFieldBean; |
| import org.apache.webbeans.component.ProducerMethodBean; |
| import org.apache.webbeans.component.creation.BeanAttributesBuilder; |
| import org.apache.webbeans.component.creation.CdiInterceptorBeanBuilder; |
| import org.apache.webbeans.component.creation.DecoratorBeanBuilder; |
| import org.apache.webbeans.component.creation.ManagedBeanBuilder; |
| import org.apache.webbeans.component.creation.ObserverMethodsBuilder; |
| import org.apache.webbeans.component.creation.ProducerFieldBeansBuilder; |
| import org.apache.webbeans.component.creation.ProducerMethodBeansBuilder; |
| import org.apache.webbeans.container.BeanManagerImpl; |
| import org.apache.webbeans.container.InjectableBeanManager; |
| import org.apache.webbeans.container.InjectionResolver; |
| import org.apache.webbeans.corespi.se.DefaultJndiService; |
| import org.apache.webbeans.decorator.DecoratorsManager; |
| import org.apache.webbeans.deployment.StereoTypeManager; |
| import org.apache.webbeans.deployment.StereoTypeModel; |
| import org.apache.webbeans.event.ObserverMethodImpl; |
| import org.apache.webbeans.event.OwbObserverMethod; |
| import org.apache.webbeans.exception.WebBeansConfigurationException; |
| import org.apache.webbeans.exception.WebBeansDeploymentException; |
| import org.apache.webbeans.exception.WebBeansException; |
| |
| import javax.annotation.Priority; |
| import javax.enterprise.inject.Alternative; |
| import javax.enterprise.inject.Vetoed; |
| import javax.enterprise.inject.spi.BeanAttributes; |
| import javax.enterprise.inject.spi.DefinitionException; |
| |
| import org.apache.webbeans.inject.AlternativesManager; |
| import org.apache.webbeans.intercept.InterceptorsManager; |
| import org.apache.webbeans.logger.WebBeansLoggerFacade; |
| import org.apache.webbeans.portable.AbstractProducer; |
| import org.apache.webbeans.portable.AnnotatedElementFactory; |
| import org.apache.webbeans.portable.BaseProducerProducer; |
| import org.apache.webbeans.portable.events.ProcessBeanImpl; |
| import org.apache.webbeans.portable.events.ProcessSyntheticAnnotatedTypeImpl; |
| import org.apache.webbeans.portable.events.discovery.AfterBeanDiscoveryImpl; |
| import org.apache.webbeans.portable.events.discovery.AfterDeploymentValidationImpl; |
| import org.apache.webbeans.portable.events.discovery.AfterTypeDiscoveryImpl; |
| import org.apache.webbeans.portable.events.discovery.BeforeBeanDiscoveryImpl; |
| import org.apache.webbeans.portable.events.generics.GProcessAnnotatedType; |
| import org.apache.webbeans.portable.events.generics.GProcessManagedBean; |
| import org.apache.webbeans.spi.BdaScannerService; |
| import org.apache.webbeans.spi.BeanArchiveService; |
| import org.apache.webbeans.spi.JNDIService; |
| import org.apache.webbeans.spi.ScannerService; |
| import org.apache.webbeans.spi.plugins.OpenWebBeansJavaEEPlugin; |
| import org.apache.webbeans.util.AnnotationUtil; |
| import org.apache.webbeans.util.ClassUtil; |
| import org.apache.webbeans.util.ExceptionUtil; |
| import org.apache.webbeans.util.GenericsUtil; |
| import org.apache.webbeans.util.InjectionExceptionUtil; |
| import org.apache.webbeans.util.SpecializationUtil; |
| import org.apache.webbeans.util.WebBeansConstants; |
| import org.apache.webbeans.util.WebBeansUtil; |
| import org.apache.webbeans.xml.DefaultBeanArchiveInformation; |
| |
| import javax.enterprise.inject.AmbiguousResolutionException; |
| import javax.enterprise.inject.Model; |
| import javax.enterprise.inject.UnproxyableResolutionException; |
| import javax.enterprise.inject.UnsatisfiedResolutionException; |
| import javax.enterprise.inject.spi.AnnotatedField; |
| import javax.enterprise.inject.spi.AnnotatedMethod; |
| import javax.enterprise.inject.spi.AnnotatedType; |
| import javax.enterprise.inject.spi.Bean; |
| import javax.enterprise.inject.spi.Decorator; |
| import javax.enterprise.inject.spi.InjectionPoint; |
| import javax.enterprise.inject.spi.InjectionTarget; |
| import javax.enterprise.inject.spi.Interceptor; |
| import javax.enterprise.inject.spi.ObserverMethod; |
| import javax.enterprise.inject.spi.Producer; |
| |
| import java.lang.annotation.Annotation; |
| import java.lang.reflect.Constructor; |
| import java.lang.reflect.Method; |
| import java.lang.reflect.ParameterizedType; |
| import java.lang.reflect.Type; |
| import java.net.URL; |
| import java.security.PrivilegedActionException; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.IdentityHashMap; |
| import java.util.Iterator; |
| import java.util.LinkedList; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.Stack; |
| import java.util.logging.Level; |
| import java.util.logging.Logger; |
| |
| import static java.util.Arrays.asList; |
| import static org.apache.webbeans.spi.BeanArchiveService.BeanDiscoveryMode; |
| import static org.apache.webbeans.spi.BeanArchiveService.BeanArchiveInformation; |
| |
| /** |
| * Deploys the all beans that are defined in the {@link org.apache.webbeans.spi.ScannerService} at |
| * the scanner phase. |
| */ |
| @SuppressWarnings("unchecked") |
| //This class written as single threaded. |
| public class BeansDeployer |
| { |
| //Logger instance |
| private static final Logger logger = WebBeansLoggerFacade.getLogger(BeansDeployer.class); |
| public static final String JAVAX_ENTERPRISE_PACKAGE = "javax.enterprise."; |
| |
| private static final Method GET_PACKAGE; |
| static |
| { |
| try |
| { |
| GET_PACKAGE = ClassLoader.class.getDeclaredMethod("getPackage", String.class); |
| GET_PACKAGE.setAccessible(true); |
| } |
| catch (final NoSuchMethodException e) |
| { |
| throw new IllegalStateException(e); |
| } |
| } |
| |
| /**Deployment is started or not*/ |
| protected boolean deployed = false; |
| |
| /**XML Configurator*/ |
| protected BeanArchiveService beanArchiveService; |
| |
| /**Discover ejb or not*/ |
| protected boolean discoverEjb = false; |
| private final WebBeansContext webBeansContext; |
| |
| private final ScannerService scannerService; |
| private final DecoratorsManager decoratorsManager; |
| private final InterceptorsManager interceptorsManager; |
| |
| private final Map<String, Boolean> packageVetoCache = new HashMap<String, Boolean>(); |
| |
| /** |
| * This BdaInfo is used for all manually added annotated types or in case |
| * a non-Bda-aware ScannerService got configured. |
| */ |
| private final DefaultBeanArchiveInformation defaultBeanArchiveInformation; |
| |
| /** |
| * Creates a new deployer with given xml configurator. |
| * |
| * @param webBeansContext |
| */ |
| public BeansDeployer(WebBeansContext webBeansContext) |
| { |
| this.webBeansContext = webBeansContext; |
| beanArchiveService = webBeansContext.getBeanArchiveService(); |
| scannerService = webBeansContext.getScannerService(); |
| decoratorsManager = webBeansContext.getDecoratorsManager(); |
| interceptorsManager = webBeansContext.getInterceptorsManager(); |
| |
| String usage = this.webBeansContext.getOpenWebBeansConfiguration().getProperty(OpenWebBeansConfiguration.USE_EJB_DISCOVERY); |
| discoverEjb = Boolean.parseBoolean(usage); |
| |
| defaultBeanArchiveInformation = new DefaultBeanArchiveInformation(); |
| defaultBeanArchiveInformation.setBeanDiscoveryMode(BeanDiscoveryMode.ALL); |
| } |
| |
| /** |
| * Deploys all the defined web beans components in the container startup. |
| * <p> |
| * It deploys from the web-beans.xml files and from the class files. It uses |
| * the {@link org.apache.webbeans.spi.ScannerService} to get classes. |
| * </p> |
| * |
| * @throws WebBeansDeploymentException if any deployment exception occurs |
| */ |
| public synchronized void deploy(ScannerService scanner) |
| { |
| try |
| { |
| if (!deployed) |
| { |
| //Load Extensions |
| webBeansContext.getExtensionLoader().loadExtensionServices(); |
| |
| // Bind manager |
| JNDIService service = webBeansContext.getService(JNDIService.class); |
| |
| //Default jndi is just a map |
| if(service instanceof DefaultJndiService) |
| { |
| service.bind(WebBeansConstants.WEB_BEANS_MANAGER_JNDI_NAME, new InjectableBeanManager(webBeansContext.getBeanManagerImpl())); |
| } |
| //Assume, actual JNDI implementation |
| else |
| { |
| service.bind(WebBeansConstants.WEB_BEANS_MANAGER_JNDI_NAME, webBeansContext.getBeanManagerImpl().getReference()); |
| } |
| |
| // Register Manager built-in component |
| webBeansContext.getBeanManagerImpl().addInternalBean(webBeansContext.getWebBeansUtil().getManagerBean()); |
| |
| webBeansContext.getBeanManagerImpl().getInjectionResolver().setStartup(true); |
| |
| //Fire Event |
| fireBeforeBeanDiscoveryEvent(); |
| |
| //Configure Default Beans |
| configureDefaultBeans(); |
| |
| Map<BeanArchiveInformation, List<AnnotatedType<?>>> annotatedTypesPerBda = annotatedTypesFromClassPath(scanner); |
| |
| List<AnnotatedType<?>> globalBdaAnnotatedTypes = annotatedTypesPerBda.get(defaultBeanArchiveInformation); |
| |
| // Deploy additional Annotated Types which got added via BeforeBeanDiscovery#addAnnotatedType |
| addAdditionalAnnotatedTypes(webBeansContext.getBeanManagerImpl().getAdditionalAnnotatedTypes(), globalBdaAnnotatedTypes); |
| |
| for (List<AnnotatedType<?>> at : annotatedTypesPerBda.values()) |
| { |
| registerAlternativesDecoratorsAndInterceptorsWithPriority(at); |
| } |
| |
| addAdditionalAnnotatedTypes(fireAfterTypeDiscoveryEvent(), globalBdaAnnotatedTypes); |
| |
| // Also configures deployments, interceptors, decorators. |
| deployFromXML(scanner); |
| |
| final Map<BeanArchiveInformation, Map<AnnotatedType<?>, ExtendedBeanAttributes<?>>> beanAttributesPerBda |
| = getBeanAttributes(annotatedTypesPerBda); |
| |
| // shouldn't be used anymore, view is now beanAttributes |
| annotatedTypesPerBda.clear(); |
| |
| SpecializationUtil specializationUtil = new SpecializationUtil(webBeansContext); |
| specializationUtil.removeDisabledBeanAttributes(beanAttributesPerBda, null, true); |
| |
| |
| //Checking stereotype conditions |
| checkStereoTypes(scanner); |
| |
| // Handle Specialization |
| specializationUtil.removeDisabledBeanAttributes( |
| beanAttributesPerBda, |
| new SpecializationUtil.BeanAttributesProvider() |
| { |
| @Override |
| public <T> BeanAttributes get(final AnnotatedType<T> at) |
| { |
| ExtendedBeanAttributes<?> data = null; |
| for (Map<AnnotatedType<?>, ExtendedBeanAttributes<?>> beanAttributes : beanAttributesPerBda.values()) |
| { |
| data = beanAttributes.get(at); |
| if (data != null) |
| { |
| break; |
| } |
| |
| } |
| return data == null ? null : data.beanAttributes; |
| } |
| }, |
| false); |
| |
| // create beans from the discovered AnnotatedTypes |
| deployFromBeanAttributes(beanAttributesPerBda); |
| |
| webBeansContext.getWebBeansUtil().configureProducerMethodSpecializations(); |
| |
| // all beans which got 'overridden' by a Specialized version can be removed now |
| removeDisabledBeans(); |
| |
| // We are finally done with our bean discovery |
| fireAfterBeanDiscoveryEvent(); |
| |
| validateAlternatives(beanAttributesPerBda); |
| |
| validateInjectionPoints(); |
| validateDisposeParameters(); |
| |
| validateDecoratorDecoratedTypes(); |
| validateDecoratorGenericTypes(); |
| |
| webBeansContext.getBeanManagerImpl().getNotificationManager().clearCaches(); |
| |
| // fire event |
| fireAfterDeploymentValidationEvent(); |
| |
| |
| // do some cleanup after the deployment |
| scanner.release(); |
| webBeansContext.getAnnotatedElementFactory().clear(); |
| webBeansContext.getBeanManagerImpl().getInjectionResolver().setStartup(false); |
| } |
| } |
| catch (UnsatisfiedResolutionException e) |
| { |
| throw new WebBeansDeploymentException(e); |
| } |
| catch (AmbiguousResolutionException e) |
| { |
| throw new WebBeansDeploymentException(e); |
| } |
| catch (UnproxyableResolutionException e) |
| { |
| // the tck expects a DeploymentException, but it really should be a DefinitionException, see i.e. https://issues.jboss.org/browse/CDITCK-346 |
| throw new WebBeansDeploymentException(e); |
| } |
| catch (IllegalArgumentException e) |
| { |
| throw new WebBeansConfigurationException(e); |
| } |
| catch (Exception e) |
| { |
| throw ExceptionUtil.throwAsRuntimeException(e); |
| } |
| finally |
| { |
| //if bootstrapping failed, it doesn't make sense to do it again |
| //esp. because #addInternalBean might have been called already and would cause an exception in the next run |
| deployed = true; |
| } |
| } |
| |
| private Map<BeanArchiveInformation, Map<AnnotatedType<?>, ExtendedBeanAttributes<?>>> getBeanAttributes( |
| final Map<BeanArchiveInformation, List<AnnotatedType<?>>> annotatedTypesPerBda) |
| { |
| final Map<BeanArchiveInformation, Map<AnnotatedType<?>, ExtendedBeanAttributes<?>>> beanAttributesPerBda |
| = new HashMap<BeanArchiveInformation, Map<AnnotatedType<?>, ExtendedBeanAttributes<?>>>(); |
| |
| for (Map.Entry<BeanArchiveInformation, List<AnnotatedType<?>>> atEntry : annotatedTypesPerBda.entrySet()) |
| { |
| BeanArchiveInformation bdaInfo = atEntry.getKey(); |
| List<AnnotatedType<?>> annotatedTypes = atEntry.getValue(); |
| |
| boolean onlyScopedBeans = BeanDiscoveryMode.SCOPED.equals(bdaInfo.getBeanDiscoveryMode()); |
| |
| final Map<AnnotatedType<?>, ExtendedBeanAttributes<?>> bdaBeanAttributes = new IdentityHashMap<AnnotatedType<?>, ExtendedBeanAttributes<?>>(annotatedTypes.size()); |
| final Iterator<AnnotatedType<?>> iterator = annotatedTypes.iterator(); |
| while (iterator.hasNext()) |
| { |
| final AnnotatedType<?> at = iterator.next(); |
| final Class beanClass = at.getJavaClass(); |
| final boolean isEjb = discoverEjb && EJBWebBeansConfigurator.isSessionBean(beanClass, webBeansContext); |
| try |
| { |
| if (isEjb || (ClassUtil.isConcrete(beanClass) || WebBeansUtil.isDecorator(at)) && isValidManagedBean(at)) |
| { |
| final BeanAttributesImpl tBeanAttributes = BeanAttributesBuilder.forContext(webBeansContext).newBeanAttibutes(at, onlyScopedBeans).build(); |
| if (tBeanAttributes != null) |
| { |
| final BeanAttributes<?> beanAttributes = webBeansContext.getWebBeansUtil().fireProcessBeanAttributes(at, at.getJavaClass(), tBeanAttributes); |
| if (beanAttributes != null) |
| { |
| bdaBeanAttributes.put(at, new ExtendedBeanAttributes(beanAttributes, isEjb)); |
| } |
| } |
| } |
| else |
| { |
| iterator.remove(); |
| } |
| } |
| catch (final NoClassDefFoundError ncdfe) |
| { |
| logger.info("Skipping deployment of Class " + beanClass + "due to a NoClassDefFoundError: " + ncdfe.getMessage()); |
| } |
| } |
| |
| beanAttributesPerBda.put(bdaInfo, bdaBeanAttributes); |
| } |
| |
| |
| return beanAttributesPerBda; |
| } |
| |
| private void validateDisposeParameters() |
| { |
| final WebBeansUtil webBeansUtil = webBeansContext.getWebBeansUtil(); |
| for (final Bean<?> bean : webBeansContext.getBeanManagerImpl().getBeans()) |
| { |
| if (ProducerMethodBean.class.isInstance(bean)) |
| { |
| final Producer<?> producer = AbstractProducerBean.class.cast(bean).getProducer(); |
| if (BaseProducerProducer.class.isInstance(producer)) |
| { |
| final BaseProducerProducer producerProducer = BaseProducerProducer.class.cast(producer); |
| final Set<InjectionPoint> disposalIPs = producerProducer.getDisposalIPs(); |
| if (disposalIPs != null && !producerProducer.isAnyDisposal()) // any can be ambiguous but that's not an issue |
| { |
| webBeansUtil.validate(disposalIPs, bean); |
| } |
| } |
| } |
| } |
| } |
| |
| |
| /** |
| * @throws DefinitionException if {@link javax.enterprise.inject.spi.Decorator#getDecoratedTypes()} isEmpty |
| */ |
| private void validateDecoratorDecoratedTypes() |
| { |
| for (Decorator decorator : decoratorsManager.getDecorators()) |
| { |
| if (decorator.getDecoratedTypes().isEmpty()) |
| { |
| throw new WebBeansConfigurationException("Decorator must implement at least one interface (java.io.Serializeable will be ignored)"); |
| } |
| } |
| } |
| |
| // avoid delegate implementing Foo<A> and decorator implementing Foo<B> with no link between A and B |
| private void validateDecoratorGenericTypes() |
| { |
| for (final Decorator<?> decorator : decoratorsManager.getDecorators()) |
| { |
| final Type type = decorator.getDelegateType(); |
| |
| // capture ParameterizedType from decorator type |
| final Collection<Type> types = new HashSet<Type>(); |
| if (Class.class.isInstance(type)) |
| { |
| Class<?> c = Class.class.cast(type); |
| while (c != Object.class && c != null) |
| { |
| types.add(c); |
| for (final Type t : asList(c.getGenericInterfaces())) |
| { |
| if (ParameterizedType.class.isInstance(t)) |
| { |
| types.add(t); |
| } |
| } |
| final Type genericSuperclass = c.getGenericSuperclass(); |
| if (ParameterizedType.class.isInstance(genericSuperclass)) |
| { |
| types.add(genericSuperclass); |
| } |
| c = c.getSuperclass(); |
| } |
| } // else? |
| |
| // check arguments matches with decorator API |
| for (final Type api : decorator.getTypes()) |
| { |
| if (!ParameterizedType.class.isInstance(api)) // no need to check here |
| { |
| continue; |
| } |
| |
| final ParameterizedType pt1 = ParameterizedType.class.cast(api); |
| for (final Type t : types) |
| { |
| if (ParameterizedType.class.isInstance(t)) |
| { |
| final ParameterizedType pt2 = ParameterizedType.class.cast(t); |
| |
| if (pt1.getRawType() == pt2.getRawType() && |
| !GenericsUtil.isAssignableFrom(true, false, pt1, pt2)) |
| { |
| throw new WebBeansConfigurationException("Generic error matching " + api + " and " + t); |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * Remove all beans which are not enabled anymore. |
| * This might e.g. happen because they are 'overridden' |
| * by a @Specialized bean. |
| * We remove those beans now to not having to take care later |
| * during {@link org.apache.webbeans.container.BeanManagerImpl#resolve(java.util.Set)} |
| */ |
| private void removeDisabledBeans() |
| { |
| Iterator<Bean<?>> beans = webBeansContext.getBeanManagerImpl().getBeans().iterator(); |
| while(beans.hasNext()) |
| { |
| Bean<?> bean = beans.next(); |
| if (!((OwbBean) bean).isEnabled()) |
| { |
| beans.remove(); |
| } |
| } |
| } |
| |
| private void registerAlternativesDecoratorsAndInterceptorsWithPriority(List<AnnotatedType<?>> annotatedTypes) |
| { |
| AlternativesManager alternativesManager = webBeansContext.getAlternativesManager(); |
| |
| for (AnnotatedType<?> annotatedType : annotatedTypes) |
| { |
| if (annotatedType.getAnnotation(Alternative.class) != null) |
| { |
| Priority priority = annotatedType.getAnnotation(Priority.class); |
| if (priority != null) |
| { |
| alternativesManager.addPriorityClazzAlternative(annotatedType.getJavaClass(), priority); |
| } |
| } |
| if (annotatedType.getAnnotation(javax.interceptor.Interceptor.class) != null) |
| { |
| Priority priority = annotatedType.getAnnotation(Priority.class); |
| if (priority != null) |
| { |
| final Class<?> javaClass = annotatedType.getJavaClass(); |
| interceptorsManager.addPriorityClazzInterceptor(javaClass, priority); |
| } |
| } |
| if (annotatedType.getAnnotation(javax.decorator.Decorator.class) != null) |
| { |
| Priority priority = annotatedType.getAnnotation(Priority.class); |
| if (priority != null) |
| { |
| final Class<?> javaClass = annotatedType.getJavaClass(); |
| decoratorsManager.addPriorityClazzDecorator(javaClass, priority); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Configure Default Beans. |
| */ |
| private void configureDefaultBeans() |
| { |
| BeanManagerImpl beanManager = webBeansContext.getBeanManagerImpl(); |
| WebBeansUtil webBeansUtil = webBeansContext.getWebBeansUtil(); |
| |
| // Register Conversation built-in component |
| beanManager.addInternalBean(webBeansUtil.getConversationBean()); |
| |
| // Register InjectionPoint bean |
| beanManager.addInternalBean(webBeansUtil.getInjectionPointBean()); |
| |
| //Register Instance Bean |
| beanManager.addInternalBean(webBeansUtil.getInstanceBean()); |
| |
| //Register Event Bean |
| beanManager.addInternalBean(webBeansUtil.getEventBean()); |
| beanManager.addInternalBean(webBeansUtil.getEventMetadataBean()); |
| |
| //Register Metadata Beans |
| beanManager.addInternalBean(webBeansUtil.getBeanMetadataBean()); |
| beanManager.addInternalBean(webBeansUtil.getInterceptorMetadataBean()); |
| beanManager.addInternalBean(webBeansUtil.getDecoratorMetadataBean()); |
| beanManager.addInternalBean(webBeansUtil.getInterceptedOrDecoratedBeanMetadataBean()); |
| |
| // Register PrincipalBean |
| beanManager.addInternalBean(webBeansUtil.getPrincipalBean()); |
| |
| //REgister Provider Beans |
| OpenWebBeansJavaEEPlugin beanEeProvider = webBeansContext.getPluginLoader().getJavaEEPlugin(); |
| |
| if(beanEeProvider != null) |
| { |
| beanEeProvider.registerEEBeans(); |
| } |
| |
| } |
| |
| private void addDefaultBean(WebBeansContext ctx,String className) |
| { |
| Bean<?> bean = null; |
| |
| Class<?> beanClass = ClassUtil.getClassFromName(className); |
| if(beanClass != null) |
| { |
| bean = (Bean)newInstance(ctx, beanClass); |
| } |
| |
| if(bean != null) |
| { |
| ctx.getBeanManagerImpl().addInternalBean(bean); |
| } |
| } |
| |
| /** |
| * create a new instance of the class |
| */ |
| private Object newInstance(WebBeansContext wbc, Class<?> clazz) |
| { |
| try |
| { |
| if(System.getSecurityManager() != null) |
| { |
| final Constructor<?> c = webBeansContext.getSecurityService().doPrivilegedGetConstructor(clazz, WebBeansContext.class); |
| if (c == null) |
| { |
| return webBeansContext.getSecurityService().doPrivilegedObjectCreate(clazz); |
| } |
| return c.newInstance(wbc); |
| } |
| |
| if (clazz.getConstructors().length > 0) |
| { |
| try |
| { |
| return clazz.getConstructor(new Class<?>[] { WebBeansContext.class }).newInstance(wbc); |
| } |
| catch (final Exception e) |
| { |
| return clazz.newInstance(); |
| } |
| } |
| return clazz.newInstance(); |
| |
| } |
| catch(Exception e) |
| { |
| Throwable cause = e; |
| if(e instanceof PrivilegedActionException) |
| { |
| cause = e.getCause(); |
| } |
| |
| String error = "Error occurred while creating an instance of class : " + clazz.getName(); |
| logger.log(Level.SEVERE, error, cause); |
| throw new WebBeansException(error,cause); |
| } |
| } |
| |
| /** |
| * Fires event before bean discovery. |
| */ |
| private void fireBeforeBeanDiscoveryEvent() |
| { |
| BeanManagerImpl manager = webBeansContext.getBeanManagerImpl(); |
| BeforeBeanDiscoveryImpl event = new BeforeBeanDiscoveryImpl(webBeansContext); |
| manager.fireLifecycleEvent(event); |
| event.setStarted(); |
| } |
| |
| /** |
| * Fires event after bean discovery. |
| */ |
| private void fireAfterBeanDiscoveryEvent() |
| { |
| BeanManagerImpl manager = webBeansContext.getBeanManagerImpl(); |
| manager.setAfterBeanDiscoveryStart(); |
| final AfterBeanDiscoveryImpl event = new AfterBeanDiscoveryImpl(webBeansContext); |
| manager.fireLifecycleEvent(event); |
| |
| |
| webBeansContext.getWebBeansUtil().inspectDefinitionErrorStack( |
| "There are errors that are added by AfterBeanDiscovery event observers. Look at logs for further details"); |
| |
| manager.setAfterBeanDiscoveryDone(); |
| event.setStarted(); |
| } |
| |
| /** |
| * Fires event after bean discovery. |
| */ |
| private List<AnnotatedType<?>> fireAfterTypeDiscoveryEvent() |
| { |
| final BeanManagerImpl manager = webBeansContext.getBeanManagerImpl(); |
| final List<AnnotatedType<?>> newAt = new LinkedList<AnnotatedType<?>>(); |
| final List<Class<?>> interceptors = interceptorsManager.getPrioritizedInterceptors(); |
| final List<Class<?>> decorators = decoratorsManager.getPrioritizedDecorators(); |
| final List<Class<?>> alternatives = webBeansContext.getAlternativesManager().getPrioritizedAlternatives(); |
| |
| // match AfterTypeDiscovery expected order (1, 2, 3...) |
| Collections.reverse(interceptors); |
| Collections.reverse(decorators); |
| Collections.reverse(alternatives); |
| final AfterTypeDiscoveryImpl event = new AfterTypeDiscoveryImpl(webBeansContext, newAt, |
| interceptors, decorators, alternatives); |
| manager.fireLifecycleEvent(event); |
| // reverse to keep "selection" order - decorator and interceptors considers it in their sorting. |
| // NOTE: from here priorityClass.getSorted() MUST NOT be recomputed (ie no priorityClass.add(...)) |
| Collections.reverse(alternatives); |
| event.setStarted(); |
| |
| // we do not need to set back the sortedAlternatives to the AlternativesManager as the API |
| // and all layers in between use a mutable List. Not very elegant but spec conform. |
| |
| webBeansContext.getWebBeansUtil().inspectDeploymentErrorStack( |
| "There are errors that are added by AfterTypeDiscovery event observers. Look at logs for further details"); |
| return newAt; |
| } |
| |
| /** |
| * Fires event after deployment valdiation. |
| */ |
| private void fireAfterDeploymentValidationEvent() |
| { |
| final BeanManagerImpl manager = webBeansContext.getBeanManagerImpl(); |
| manager.setAfterDeploymentValidationFired(true); |
| final AfterDeploymentValidationImpl event = new AfterDeploymentValidationImpl(manager); |
| manager.fireLifecycleEvent(event); |
| |
| webBeansContext.getWebBeansUtil().inspectDeploymentErrorStack( |
| "There are errors that are added by AfterDeploymentValidation event observers. Look at logs for further details"); |
| |
| packageVetoCache.clear(); // no more needed, free the memory |
| event.setStarted(); |
| } |
| |
| /** |
| * Check if all XML configured alternatives end up as alternative beans |
| * @param beanAttributesPerBda |
| */ |
| private void validateAlternatives(Map<BeanArchiveInformation, Map<AnnotatedType<?>, ExtendedBeanAttributes<?>>> beanAttributesPerBda) |
| { |
| Set<Class<?>> xmlConfiguredAlternatives = webBeansContext.getAlternativesManager().getXmlConfiguredAlternatives(); |
| InjectionResolver injectionResolver = webBeansContext.getBeanManagerImpl().getInjectionResolver(); |
| |
| for (Class<?> alternativeClass : xmlConfiguredAlternatives) |
| { |
| if (AnnotationUtil.hasClassAnnotation(alternativeClass, Alternative.class) || |
| AnnotationUtil.hasMetaAnnotation(alternativeClass.getAnnotations(), Alternative.class)) |
| { |
| continue; |
| } |
| |
| boolean foundAlternativeClass = false; |
| |
| Set<Bean<?>> beans = injectionResolver.implResolveByType(false, alternativeClass, AnyLiteral.INSTANCE); |
| if (beans == null || beans.isEmpty()) |
| { |
| out: |
| for (Map<AnnotatedType<?>, ExtendedBeanAttributes<?>> annotatedTypeExtendedBeanAttributesMap : beanAttributesPerBda.values()) |
| { |
| for (Map.Entry<AnnotatedType<?>, ExtendedBeanAttributes<?>> exType : annotatedTypeExtendedBeanAttributesMap.entrySet()) |
| { |
| if (alternativeClass.equals(exType.getKey().getJavaClass())) |
| { |
| if (exType.getValue().beanAttributes.isAlternative() || |
| exType.getKey().getAnnotation(Alternative.class) != null) |
| { |
| foundAlternativeClass = true; |
| break out; // all fine, continue with the next |
| } |
| } |
| } |
| } |
| } |
| else |
| { |
| for (Bean<?> bean : beans) |
| { |
| if (bean.isAlternative()) |
| { |
| foundAlternativeClass = true; |
| break; |
| } |
| } |
| } |
| if (!foundAlternativeClass) |
| { |
| throw new WebBeansDeploymentException("Given alternative class : " + alternativeClass.getName() + |
| " is not annotated wih @Alternative or not an enabled bean"); |
| } |
| |
| } |
| |
| } |
| |
| |
| /** |
| * Validate all injection points. |
| */ |
| private void validateInjectionPoints() |
| { |
| logger.fine("Validation of injection points has started."); |
| |
| decoratorsManager.validateDecoratorClasses(); |
| interceptorsManager.validateInterceptorClasses(); |
| |
| //Adding decorators to validate |
| Set<Decorator<?>> decorators = decoratorsManager.getDecorators(); |
| |
| logger.fine("Validation of the decorator's injection points has started."); |
| |
| //Validate Decorators |
| validate(decorators); |
| |
| //Adding interceptors to validate |
| List<javax.enterprise.inject.spi.Interceptor<?>> interceptors = interceptorsManager.getCdiInterceptors(); |
| |
| logger.fine("Validation of the interceptor's injection points has started."); |
| |
| //Validate Interceptors |
| validate(interceptors); |
| |
| logger.fine("Validation of the beans' injection points has started."); |
| |
| Set<Bean<?>> beans = webBeansContext.getBeanManagerImpl().getBeans(); |
| |
| //Validate Others |
| validate(beans); |
| |
| logger.fine("Validation of the observer methods' injection points has started."); |
| |
| //Validate Observers |
| validateObservers(webBeansContext.getBeanManagerImpl().getNotificationManager().getObserverMethods()); |
| |
| logger.info(OWBLogConst.INFO_0003); |
| } |
| |
| /** |
| * Validates beans. |
| * |
| * @param beans deployed beans |
| */ |
| private <T, B extends Bean<?>> void validate(Collection<B> beans) |
| { |
| webBeansContext.getBeanManagerImpl().getInjectionResolver().clearCaches(); |
| |
| if (beans != null && beans.size() > 0) |
| { |
| Stack<String> beanNames = new Stack<String>(); |
| for (Bean<?> bean : beans) |
| { |
| try |
| { |
| |
| if (bean instanceof OwbBean && !((OwbBean) bean).isEnabled()) |
| { |
| // we skip disabled beans |
| continue; |
| } |
| |
| //don't validate the cdi-api |
| if (bean.getBeanClass().getName().startsWith(JAVAX_ENTERPRISE_PACKAGE)) |
| { |
| if (BuiltInOwbBean.class.isInstance(bean)) |
| { |
| final Class<?> proxyable = BuiltInOwbBean.class.cast(bean).proxyableType(); |
| if (proxyable != null) |
| { |
| final AbstractProducer producer = AbstractProducer.class.cast(OwbBean.class.cast(bean).getProducer()); |
| final AnnotatedType<?> annotatedType = webBeansContext.getAnnotatedElementFactory().newAnnotatedType(proxyable); |
| producer.defineInterceptorStack(bean, annotatedType, webBeansContext); |
| } |
| } |
| continue; |
| } |
| |
| String beanName = bean.getName(); |
| if (beanName != null) |
| { |
| beanNames.push(beanName); |
| } |
| |
| if (bean instanceof OwbBean && !(bean instanceof Interceptor) && !(bean instanceof Decorator)) |
| { |
| AbstractProducer<T> producer = null; |
| |
| OwbBean<T> owbBean = (OwbBean<T>) bean; |
| if (ManagedBean.class.isInstance(bean)) // in this case don't use producer which can be wrapped |
| { |
| producer = ManagedBean.class.cast(bean).getOriginalInjectionTarget(); |
| } |
| if (producer == null && owbBean.getProducer() instanceof AbstractProducer) |
| { |
| producer = (AbstractProducer<T>) owbBean.getProducer(); |
| } |
| if (producer != null) |
| { |
| AnnotatedType<T> annotatedType; |
| if (owbBean instanceof InjectionTargetBean) |
| { |
| annotatedType = ((InjectionTargetBean<T>) owbBean).getAnnotatedType(); |
| } |
| else |
| { |
| annotatedType = webBeansContext.getAnnotatedElementFactory().newAnnotatedType(owbBean.getReturnType()); |
| } |
| producer.defineInterceptorStack(owbBean, annotatedType, webBeansContext); |
| } |
| } |
| |
| //Bean injection points |
| Set<InjectionPoint> injectionPoints = bean.getInjectionPoints(); |
| |
| //Check injection points |
| if (injectionPoints != null) |
| { |
| webBeansContext.getWebBeansUtil().validate(injectionPoints, bean); |
| } |
| |
| //Check passivation scope |
| checkPassivationScope(bean); |
| } |
| catch (RuntimeException e) |
| { |
| throw ExceptionUtil.addInformation(e, "Problem while validating bean " + bean); |
| } |
| |
| } |
| //Validate Bean names |
| validateBeanNames(beanNames); |
| |
| //Clear Names |
| beanNames.clear(); |
| } |
| |
| } |
| |
| private void validateObservers(Collection<ObserverMethod<?>> observerMethods) |
| { |
| for (ObserverMethod<?> observerMethod: observerMethods) |
| { |
| if (observerMethod instanceof OwbObserverMethod) |
| { |
| OwbObserverMethod<?> owbObserverMethod = (OwbObserverMethod<?>)observerMethod; |
| webBeansContext.getWebBeansUtil().validate(owbObserverMethod.getInjectionPoints(), null); |
| } |
| } |
| } |
| |
| private void validateBeanNames(Stack<String> beanNames) |
| { |
| if(beanNames.size() > 0) |
| { |
| for(String beanName : beanNames) |
| { |
| for(String other : beanNames) |
| { |
| String part = null; |
| int i = beanName.lastIndexOf('.'); |
| if(i != -1) |
| { |
| part = beanName.substring(0,i); |
| } |
| |
| if(beanName.equals(other)) |
| { |
| InjectionResolver resolver = webBeansContext.getBeanManagerImpl().getInjectionResolver(); |
| Set<Bean<?>> beans = resolver.implResolveByName(beanName); |
| if(beans.size() > 1) |
| { |
| try |
| { |
| resolver.resolve(beans, null); |
| } |
| catch(AmbiguousResolutionException are) |
| { |
| // throw the Exception with even more information |
| InjectionExceptionUtil.throwAmbiguousResolutionExceptionForBeanName(beans, beanName); |
| } |
| } |
| } |
| else |
| { |
| if(part != null && part.equals(other)) |
| { |
| throw new WebBeansDeploymentException("EL name of one bean is of the form x.y, where y is a valid bean EL name, and " + |
| "x is the EL name of the other bean for the bean name : " + beanName); |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * Create AnnotatedTypes from the ClassPath via the ScannerService |
| */ |
| private Map<BeanArchiveInformation, List<AnnotatedType<?>>> annotatedTypesFromClassPath(ScannerService scanner) |
| { |
| logger.fine("Creating AnnotatedTypes from class files has started."); |
| Set<Class<?>> foundClasses = new HashSet<Class<?>>(100); |
| |
| Map<BeanArchiveInformation, List<AnnotatedType<?>>> annotatedTypesPerBda |
| = new HashMap<BeanArchiveInformation, List<AnnotatedType<?>>>(); |
| |
| if (scanner instanceof BdaScannerService) |
| { |
| Map<BeanArchiveInformation, Set<Class<?>>> beanClassesPerBda = ((BdaScannerService) scanner).getBeanClassesPerBda(); |
| |
| for (Map.Entry<BeanArchiveInformation, Set<Class<?>>> bdaEntry : beanClassesPerBda.entrySet()) |
| { |
| BeanArchiveInformation bdaInfo = bdaEntry.getKey(); |
| List<AnnotatedType<?>> annotatedTypes = annotatedTypesFromBdaClassPath(bdaEntry.getValue(), foundClasses); |
| annotatedTypesPerBda.put(bdaEntry.getKey(), annotatedTypes); |
| } |
| |
| // also add the rest of the class es to the default bda |
| // we also need this initialised in case annotatedTypes get added manually at a later step |
| annotatedTypesPerBda.put(defaultBeanArchiveInformation, annotatedTypesFromBdaClassPath(scanner.getBeanClasses(), foundClasses)); |
| } |
| else |
| { |
| // this path is only for backward compat to older ScannerService implementations |
| |
| Set<Class<?>> classIndex = scanner.getBeanClasses(); |
| List<AnnotatedType<?>> annotatedTypes = annotatedTypesFromBdaClassPath(classIndex, foundClasses); |
| |
| annotatedTypesPerBda.put(defaultBeanArchiveInformation, annotatedTypes); |
| } |
| |
| |
| return annotatedTypesPerBda; |
| } |
| |
| /** |
| * @param foundClasses classes which already got processed. To prevent picking up the same class from multiple classpaths |
| */ |
| private List<AnnotatedType<?>> annotatedTypesFromBdaClassPath(Set<Class<?>> classIndex, Set<Class<?>> foundClasses) |
| { |
| List<AnnotatedType<?>> annotatedTypes = new ArrayList<AnnotatedType<?>>(); |
| |
| //Iterating over each class |
| if (classIndex != null) |
| { |
| AnnotatedElementFactory annotatedElementFactory = webBeansContext.getAnnotatedElementFactory(); |
| |
| for (Class<?> implClass : classIndex) |
| { |
| if (foundClasses.contains(implClass)) |
| { |
| // skip this class |
| continue; |
| } |
| |
| foundClasses.add(implClass); |
| |
| if (isVetoed(implClass)) |
| { |
| if (isEEComponent(implClass)) |
| { |
| // fire injection point events and forget |
| AnnotatedType<?> annotatedType = annotatedElementFactory.newAnnotatedType(implClass); |
| InjectionTarget<?> it = webBeansContext.getBeanManagerImpl().createInjectionTarget(annotatedType); |
| for (final InjectionPoint ip : it.getInjectionPoints()) |
| { |
| webBeansContext.getWebBeansUtil().fireProcessInjectionPointEvent(ip); |
| } |
| } |
| continue; |
| } |
| |
| try |
| { |
| //Define annotation type |
| AnnotatedType<?> annotatedType = annotatedElementFactory.getAnnotatedType(implClass); |
| if (annotatedType == null) // mean no annotation created it (normal case) |
| { |
| annotatedType = annotatedElementFactory.newAnnotatedType(implClass); |
| } |
| |
| if (annotatedType == null) |
| { |
| logger.info("Could not create AnnotatedType for class " + implClass); |
| continue; |
| } |
| |
| // Fires ProcessAnnotatedType |
| if (!annotatedType.getJavaClass().isAnnotation()) |
| { |
| GProcessAnnotatedType processAnnotatedEvent = webBeansContext.getWebBeansUtil().fireProcessAnnotatedTypeEvent(annotatedType); |
| if (!processAnnotatedEvent.isVeto()) |
| { |
| annotatedTypes.add(processAnnotatedEvent.getAnnotatedType()); |
| } |
| processAnnotatedEvent.setStarted(); |
| } |
| else |
| { |
| annotatedTypes.add(annotatedType); |
| } |
| } |
| catch (NoClassDefFoundError ncdfe) |
| { |
| logger.info("Skipping deployment of Class " + implClass + "due to a NoClassDefFoundError: " + ncdfe.getMessage()); |
| } |
| } |
| } |
| |
| return annotatedTypes; |
| } |
| |
| private boolean isEEComponent(final Class<?> impl) |
| { |
| OpenWebBeansJavaEEPlugin eePlugin = webBeansContext.getPluginLoader().getJavaEEPlugin(); |
| return eePlugin != null && eePlugin.isEEComponent(impl); |
| } |
| |
| private boolean isVetoed(final Class<?> implClass) |
| { |
| if (implClass.getAnnotation(Vetoed.class) != null) |
| { |
| return true; |
| } |
| |
| ClassLoader classLoader = implClass.getClassLoader(); |
| if (classLoader == null) |
| { |
| classLoader = BeansDeployer.class.getClassLoader(); |
| } |
| |
| Package pckge = implClass.getPackage(); |
| if (pckge == null) |
| { |
| return false; |
| } |
| do |
| { |
| // yes we cache result with potentially different classloader but this is not portable by spec |
| final String name = pckge.getName(); |
| { |
| final Boolean result = packageVetoCache.get(name); |
| if (result != null && result) |
| { |
| return result; |
| } |
| } |
| if (pckge.getAnnotation(Vetoed.class) != null) |
| { |
| packageVetoCache.put(pckge.getName(), true); |
| return true; |
| } |
| else |
| { |
| packageVetoCache.put(pckge.getName(), false); |
| } |
| |
| final int idx = name.lastIndexOf('.'); |
| if (idx > 0) |
| { |
| final String previousPackage = name.substring(0, idx); |
| final Boolean result = packageVetoCache.get(previousPackage); |
| if (result != null && result) |
| { |
| return result; |
| } |
| try // this is related to classloader and not to Package actually :( so we need reflection |
| { |
| pckge = Package.class.cast(GET_PACKAGE.invoke(classLoader, previousPackage)); |
| } |
| catch (final Exception e) |
| { |
| throw new IllegalStateException(e); |
| } |
| } |
| else |
| { |
| pckge = null; |
| } |
| } while (pckge != null); |
| |
| return false; |
| } |
| |
| /** |
| * Process any AnnotatedTypes which got added by BeforeBeanDiscovery#addAnnotatedType |
| * @param annotatedTypes |
| */ |
| private void addAdditionalAnnotatedTypes(Collection<AnnotatedType<?>> toDeploy, List<AnnotatedType<?>> annotatedTypes) |
| { |
| for (AnnotatedType<?> annotatedType : toDeploy) |
| { |
| // Fires ProcessAnnotatedType |
| ProcessSyntheticAnnotatedTypeImpl<?> processAnnotatedEvent = !annotatedType.getJavaClass().isAnnotation() ? |
| webBeansContext.getWebBeansUtil().fireProcessSyntheticAnnotatedTypeEvent(annotatedType) : null; |
| |
| if (processAnnotatedEvent == null || !processAnnotatedEvent.isVeto()) |
| { |
| AnnotatedType<?> changedAnnotatedType = processAnnotatedEvent == null ? annotatedType : processAnnotatedEvent.getAnnotatedType(); |
| if (annotatedTypes.contains(changedAnnotatedType)) |
| { |
| annotatedTypes.remove(changedAnnotatedType); |
| } |
| annotatedTypes.add(changedAnnotatedType); |
| } |
| if (processAnnotatedEvent != null) |
| { |
| processAnnotatedEvent.setStarted(); |
| } |
| } |
| } |
| |
| |
| /** |
| * Discovers and deploys classes from class path. |
| * |
| * @param beanAttributesPerBda the AnnotatedTypes which got discovered so far and are not vetoed |
| * @throws ClassNotFoundException if class not found |
| */ |
| protected void deployFromBeanAttributes( Map<BeanArchiveInformation, Map<AnnotatedType<?>, ExtendedBeanAttributes<?>>> beanAttributesPerBda) |
| { |
| logger.fine("Deploying configurations from class files has started."); |
| |
| BeanManagerImpl bm = webBeansContext.getBeanManagerImpl(); |
| for (Map<AnnotatedType<?>, ExtendedBeanAttributes<?>> beanAttributesMap : beanAttributesPerBda.values()) |
| { |
| |
| // Start from the class |
| for (Map.Entry<AnnotatedType<?>, ExtendedBeanAttributes<?>> annotatedType : beanAttributesMap.entrySet()) |
| { |
| try |
| { |
| deploySingleAnnotatedType(annotatedType.getKey(), annotatedType.getValue(), beanAttributesMap); |
| } |
| catch (NoClassDefFoundError ncdfe) |
| { |
| logger.info("Skipping deployment of Class " + annotatedType.getKey().getJavaClass() + "due to a NoClassDefFoundError: " + ncdfe.getMessage()); |
| } |
| |
| // if the implClass already gets processed as part of the |
| // standard BDA scanning, then we don't need to 'additionally' |
| // deploy it anymore. |
| bm.removeAdditionalAnnotatedType(annotatedType.getKey()); |
| |
| } |
| } |
| |
| logger.fine("Deploying configurations from class files has ended."); |
| |
| } |
| |
| |
| /** |
| * Common helper method used to deploy annotated types discovered through |
| * scanning or during beforeBeanDiscovery. |
| * |
| * @param annotatedTypeData the AnnotatedType representing the bean to be deployed with their already computed data |
| */ |
| private void deploySingleAnnotatedType(AnnotatedType annotatedType, ExtendedBeanAttributes annotatedTypeData, Map<AnnotatedType<?>, ExtendedBeanAttributes<?>> annotatedTypes) |
| { |
| |
| Class beanClass = annotatedType.getJavaClass(); |
| |
| // EJBs can be defined so test them really before going for a ManagedBean |
| if (annotatedTypeData.isEjb) |
| { |
| logger.log(Level.FINE, "Found Enterprise Bean with class name : [{0}]", beanClass.getName()); |
| defineEnterpriseWebBean((Class<Object>) beanClass, annotatedType, annotatedTypeData.beanAttributes); |
| } |
| else |
| { |
| try |
| { |
| if((ClassUtil.isConcrete(beanClass) || WebBeansUtil.isDecorator(annotatedType)) |
| && isValidManagedBean(annotatedType)) |
| { |
| defineManagedBean(annotatedType, annotatedTypeData.beanAttributes, annotatedTypes); |
| } |
| } |
| catch (NoClassDefFoundError ncdfe) |
| { |
| logger.warning("Skipping deployment of Class " + beanClass + " due to a NoClassDefFoundError: " + ncdfe.getMessage()); |
| } |
| } |
| } |
| |
| private boolean isValidManagedBean(final AnnotatedType<?> type) |
| { |
| final Class<?> beanClass = type.getJavaClass(); |
| final WebBeansUtil webBeansUtil = webBeansContext.getWebBeansUtil(); |
| |
| // done separately to be able to swallow the logging when not relevant and avoid to pollute logs |
| try |
| { |
| if (!webBeansUtil.isConstructorOk(type)) |
| { |
| return false; |
| } |
| } |
| catch (final TypeNotPresentException cnfe) |
| { |
| return false; |
| } |
| |
| try |
| { |
| webBeansUtil.checkManagedBean(beanClass); |
| } |
| catch (final DefinitionException e) |
| { |
| logger.log(Level.FINE, "skipped deployment of: " + beanClass.getName() + " reason: " + e.getMessage()); |
| logger.log(Level.FINER, "skipped deployment of: " + beanClass.getName() + " details: ", e); |
| return false; |
| } |
| //we are not allowed to catch possible exceptions thrown by the following method |
| webBeansUtil.checkManagedBeanCondition(beanClass); |
| return true; |
| } |
| |
| /** |
| * Discovers and deploys alternatives, interceptors and decorators from XML. |
| * |
| * @param scanner discovery scanner |
| * |
| * @throws WebBeansDeploymentException if a problem occurs |
| */ |
| protected void deployFromXML(ScannerService scanner) |
| throws WebBeansDeploymentException |
| { |
| logger.fine("Deploying configurations from XML files has started."); |
| |
| Set<URL> bdaLocations = scanner.getBeanXmls(); |
| Iterator<URL> it = bdaLocations.iterator(); |
| |
| while (it.hasNext()) |
| { |
| URL url = it.next(); |
| |
| logger.fine("OpenWebBeans BeansDeployer configuring: " + url.toExternalForm()); |
| |
| BeanArchiveInformation beanArchiveInformation = beanArchiveService.getBeanArchiveInformation(url); |
| |
| configureDecorators(url, beanArchiveInformation.getDecorators()); |
| configureInterceptors(url, beanArchiveInformation.getInterceptors()); |
| configureAlternatives(url, beanArchiveInformation.getAlternativeClasses(), false); |
| configureAlternatives(url, beanArchiveInformation.getAlternativeStereotypes(), true); |
| configureAllowProxying(url, beanArchiveInformation.getAllowProxyingClasses()); |
| } |
| |
| logger.fine("Deploying configurations from XML has ended successfully."); |
| } |
| |
| private void configureAlternatives(URL bdaLocation, List<String> alternatives, boolean isStereotype) |
| { |
| AlternativesManager manager = webBeansContext.getAlternativesManager(); |
| AnnotatedElementFactory annotatedElementFactory = webBeansContext.getAnnotatedElementFactory(); |
| |
| // the alternatives in this beans.xml |
| // this gets used to detect multiple definitions of the |
| // same alternative in one beans.xml file. |
| Set<String> alternativesInFile = new HashSet<String>(); |
| |
| for (String alternativeName : alternatives) |
| { |
| if (alternativesInFile.contains(alternativeName)) |
| { |
| throw new WebBeansDeploymentException(createConfigurationFailedMessage(bdaLocation) + "Given alternative : " + alternativeName |
| + " is already added as @Alternative" ); |
| } |
| alternativesInFile.add(alternativeName); |
| |
| Class clazz = ClassUtil.getClassFromName(alternativeName); |
| |
| if (clazz == null) |
| { |
| throw new WebBeansDeploymentException(createConfigurationFailedMessage(bdaLocation) + "Alternative: " + alternativeName + " not found"); |
| } |
| else |
| { |
| if (isStereotype) |
| { |
| manager.addXmlStereoTypeAlternative(clazz); |
| } |
| else |
| { |
| manager.addXmlClazzAlternative(clazz); |
| } |
| } |
| } |
| } |
| |
| private void configureDecorators(URL bdaLocation, List<String> decorators) |
| { |
| Set<Class> decoratorsInFile = new HashSet<Class>(); |
| |
| for (String decorator : decorators) |
| { |
| Class<?> clazz = ClassUtil.getClassFromName(decorator); |
| |
| if (clazz == null) |
| { |
| throw new WebBeansDeploymentException(createConfigurationFailedMessage(bdaLocation) + "Decorator class : " + |
| decorator + " not found"); |
| } |
| else |
| { |
| if ((scannerService.isBDABeansXmlScanningEnabled() && !scannerService.getBDABeansXmlScanner().addDecorator(clazz, bdaLocation.toExternalForm())) || |
| decoratorsInFile.contains(clazz)) |
| { |
| throw new WebBeansDeploymentException(createConfigurationFailedMessage(bdaLocation) + "Decorator class : " + |
| decorator + " is already defined"); |
| } |
| |
| decoratorsManager.addEnabledDecorator(clazz); |
| decoratorsInFile.add(clazz); |
| } |
| } |
| } |
| |
| private void configureInterceptors(URL bdaLocation, List<String> interceptors) |
| { |
| // the interceptors in this beans.xml |
| // this gets used to detect multiple definitions of the |
| // same interceptor in one beans.xml file. |
| Set<Class> interceptorsInFile = new HashSet<Class>(); |
| |
| for (String interceptor : interceptors) |
| { |
| Class<?> clazz = ClassUtil.getClassFromName(interceptor); |
| |
| if (clazz == null) |
| { |
| throw new WebBeansDeploymentException(createConfigurationFailedMessage(bdaLocation) + "Interceptor class : " + |
| interceptor + " not found"); |
| } |
| else |
| { |
| Annotation[] classAnnotations; |
| AnnotatedType<?> annotatedType = webBeansContext.getAnnotatedElementFactory().getAnnotatedType(clazz); |
| if (annotatedType == null) |
| { |
| annotatedType = webBeansContext.getAnnotatedElementFactory().newAnnotatedType(clazz); |
| } |
| |
| GProcessAnnotatedType processAnnotatedEvent = |
| webBeansContext.getWebBeansUtil().fireProcessAnnotatedTypeEvent(annotatedType); |
| |
| // if veto() is called |
| if (processAnnotatedEvent.isVeto()) |
| { |
| return; |
| } |
| |
| annotatedType = processAnnotatedEvent.getAnnotatedType(); |
| processAnnotatedEvent.setStarted(); |
| |
| Set<Annotation> annTypeAnnotations = annotatedType.getAnnotations(); |
| if (annTypeAnnotations != null) |
| { |
| classAnnotations = annTypeAnnotations.toArray(new Annotation[annTypeAnnotations.size()]); |
| } |
| else |
| { |
| classAnnotations = new Annotation[0]; |
| } |
| |
| if (AnnotationUtil.hasAnnotation(classAnnotations, javax.interceptor.Interceptor.class) && |
| !webBeansContext.getAnnotationManager().hasInterceptorBindingMetaAnnotation(classAnnotations)) |
| { |
| throw new WebBeansDeploymentException(createConfigurationFailedMessage(bdaLocation) + "Interceptor class : " |
| + interceptor + " must have at least one @InterceptorBinding"); |
| } |
| |
| // check if the interceptor got defined twice in this beans.xml |
| if (interceptorsInFile.contains(clazz)) |
| { |
| throw new WebBeansDeploymentException(createConfigurationFailedMessage(bdaLocation) + "Interceptor class : " |
| + interceptor + " already defined in this beans.xml file!"); |
| } |
| interceptorsInFile.add(clazz); |
| |
| boolean isBDAScanningEnabled = scannerService.isBDABeansXmlScanningEnabled(); |
| if ((!isBDAScanningEnabled && interceptorsManager.isInterceptorClassEnabled(clazz)) || |
| (isBDAScanningEnabled && !scannerService.getBDABeansXmlScanner().addInterceptor(clazz, bdaLocation.toExternalForm()))) |
| { |
| logger.warning( "Interceptor class : " + interceptor + " is already defined"); |
| } |
| else |
| { |
| interceptorsManager.addEnabledInterceptorClass(clazz); |
| } |
| } |
| } |
| } |
| |
| private void configureAllowProxying(URL url, List<String> allowProxyingClasses) |
| { |
| OpenWebBeansConfiguration owbConfiguration = webBeansContext.getOpenWebBeansConfiguration(); |
| for (String allowProxyingClass : allowProxyingClasses) |
| { |
| owbConfiguration.addConfigListValue(OpenWebBeansConfiguration.ALLOW_PROXYING_PARAM, allowProxyingClass); |
| } |
| } |
| |
| |
| /** |
| * Gets error message for XML parsing of the current XML file. |
| * |
| * @return the error messages |
| */ |
| private String createConfigurationFailedMessage(URL bdaLocation) |
| { |
| return "WebBeans configuration defined in " + bdaLocation.toExternalForm() + " did fail. Reason is : "; |
| } |
| |
| |
| /** |
| * Check passivations. |
| */ |
| protected void checkPassivationScope(Bean<?> beanObj) |
| { |
| boolean validate = false; |
| |
| if(beanObj instanceof EnterpriseBeanMarker) |
| { |
| EnterpriseBeanMarker marker = (EnterpriseBeanMarker)beanObj; |
| if(marker.isPassivationCapable()) |
| { |
| validate = true; |
| } |
| } |
| else if(webBeansContext.getBeanManagerImpl().isPassivatingScope(beanObj.getScope())) |
| { |
| if(WebBeansUtil.getPassivationId(beanObj) == null) |
| { |
| if(!(beanObj instanceof AbstractProducerBean)) |
| { |
| throw new WebBeansDeploymentException("Passivation scoped defined bean must be passivation capable, " + |
| "but bean : " + beanObj.toString() + " is not passivation capable"); |
| } |
| } |
| |
| validate = true; |
| } |
| |
| if(validate) |
| { |
| webBeansContext.getDeploymentValidationService().validatePassivationCapable((OwbBean<?>)beanObj); |
| } |
| } |
| |
| /** |
| * Check steretypes. |
| * @param scanner scanner instance |
| */ |
| protected void checkStereoTypes(ScannerService scanner) |
| { |
| logger.fine("Checking StereoType constraints has started."); |
| |
| addDefaultStereoTypes(); |
| |
| final AnnotationManager annotationManager = webBeansContext.getAnnotationManager(); |
| |
| Set<Class<?>> beanClasses = scanner.getBeanClasses(); |
| if (beanClasses != null && beanClasses.size() > 0) |
| { |
| final StereoTypeManager stereoTypeManager = webBeansContext.getStereoTypeManager(); |
| for(Class<?> beanClass : beanClasses) |
| { |
| if(beanClass.isAnnotation()) |
| { |
| Class<? extends Annotation> stereoClass = (Class<? extends Annotation>) beanClass; |
| if (annotationManager.isStereoTypeAnnotation(stereoClass) |
| && stereoTypeManager.getStereoTypeModel(stereoClass.getName()) == null) |
| { |
| webBeansContext.getAnnotationManager().checkStereoTypeClass(stereoClass, stereoClass.getDeclaredAnnotations()); |
| StereoTypeModel model = new StereoTypeModel(webBeansContext, stereoClass); |
| stereoTypeManager.addStereoTypeModel(model); |
| } |
| } |
| } |
| } |
| |
| logger.fine("Checking StereoType constraints has ended."); |
| } |
| |
| /** |
| * Adds default stereotypes. |
| */ |
| protected void addDefaultStereoTypes() |
| { |
| StereoTypeModel model = new StereoTypeModel(webBeansContext, Model.class); |
| webBeansContext.getStereoTypeManager().addStereoTypeModel(model); |
| } |
| |
| /** |
| * Defines and configures managed bean. |
| * @param <T> type info |
| */ |
| protected <T> void defineManagedBean(AnnotatedType<T> annotatedType, BeanAttributes<T> attributes, Map<AnnotatedType<?>, ExtendedBeanAttributes<?>> annotatedTypes) |
| { |
| //Fires ProcessInjectionTarget event for Java EE components instances |
| //That supports injections but not managed beans |
| Class beanClass = annotatedType.getJavaClass(); |
| if(webBeansContext.getWebBeansUtil().supportsJavaEeComponentInjections(beanClass)) |
| { |
| //Fires ProcessInjectionTarget |
| webBeansContext.getWebBeansUtil().fireProcessInjectionTargetEventForJavaEeComponents(beanClass).setStarted(); |
| webBeansContext.getWebBeansUtil().inspectDeploymentErrorStack( |
| "There are errors that are added by ProcessInjectionTarget event observers. Look at logs for further details"); |
| |
| //Checks that not contains @Inject InjectionPoint |
| webBeansContext.getAnnotationManager().checkInjectionPointForInjectInjectionPoint(beanClass); |
| } |
| |
| { |
| ManagedBeanBuilder<T, ManagedBean<T>> managedBeanCreator = new ManagedBeanBuilder<T, ManagedBean<T>>(webBeansContext, annotatedType, attributes); |
| |
| if(WebBeansUtil.isDecorator(annotatedType)) |
| { |
| if (logger.isLoggable(Level.FINE)) |
| { |
| logger.log(Level.FINE, "Found Managed Bean Decorator with class name : [{0}]", annotatedType.getJavaClass().getName()); |
| } |
| |
| DecoratorBeanBuilder<T> dbb = new DecoratorBeanBuilder<T>(webBeansContext, annotatedType, attributes); |
| if (dbb.isDecoratorEnabled()) |
| { |
| dbb.defineDecoratorRules(); |
| DecoratorBean<T> decorator = dbb.getBean(); |
| decoratorsManager.addDecorator(decorator); |
| } |
| } |
| else if(WebBeansUtil.isCdiInterceptor(annotatedType)) |
| { |
| if (logger.isLoggable(Level.FINE)) |
| { |
| logger.log(Level.FINE, "Found Managed Bean Interceptor with class name : [{0}]", annotatedType.getJavaClass().getName()); |
| } |
| |
| CdiInterceptorBeanBuilder<T> ibb = new CdiInterceptorBeanBuilder<T>(webBeansContext, annotatedType, attributes); |
| if (ibb.isInterceptorEnabled()) |
| { |
| ibb.defineCdiInterceptorRules(); |
| CdiInterceptorBean<T> interceptor = ibb.getBean(); |
| interceptorsManager.addCdiInterceptor(interceptor); |
| } |
| } |
| else |
| { |
| InjectionTargetBean<T> bean = managedBeanCreator.getBean(); |
| |
| if (decoratorsManager.containsCustomDecoratorClass(annotatedType.getJavaClass()) || |
| interceptorsManager.containsCustomInterceptorClass(annotatedType.getJavaClass())) |
| { |
| return; //TODO discuss this case (it was ignored before) |
| } |
| |
| if (logger.isLoggable(Level.FINE)) |
| { |
| logger.log(Level.FINE, "Found Managed Bean with class name : [{0}]", annotatedType.getJavaClass().getName()); |
| } |
| |
| final Set<ObserverMethod<?>> observerMethods; |
| final AnnotatedType<T> beanAnnotatedType = bean.getAnnotatedType(); |
| final AnnotatedType<T> defaultAt = webBeansContext.getAnnotatedElementFactory().getAnnotatedType(beanAnnotatedType.getJavaClass()); |
| final boolean ignoreProducer = defaultAt != beanAnnotatedType && annotatedTypes.containsKey(defaultAt); |
| if(bean.isEnabled()) |
| { |
| observerMethods = new ObserverMethodsBuilder<T>(webBeansContext, beanAnnotatedType).defineObserverMethods(bean); |
| } |
| else |
| { |
| observerMethods = new HashSet<ObserverMethod<?>>(); |
| } |
| |
| final WebBeansContext wbc = bean.getWebBeansContext(); |
| Set<ProducerFieldBean<?>> producerFields = |
| ignoreProducer ? Collections.emptySet() : new ProducerFieldBeansBuilder(wbc, beanAnnotatedType).defineProducerFields(bean); |
| Set<ProducerMethodBean<?>> producerMethods = |
| ignoreProducer ? Collections.emptySet() : new ProducerMethodBeansBuilder(wbc, beanAnnotatedType).defineProducerMethods(bean, producerFields); |
| |
| ManagedBean<T> managedBean = (ManagedBean<T>)bean; |
| Map<ProducerMethodBean<?>,AnnotatedMethod<?>> annotatedMethods = |
| new HashMap<ProducerMethodBean<?>, AnnotatedMethod<?>>(); |
| |
| if (!producerFields.isEmpty() || !producerMethods.isEmpty()) |
| { |
| final Priority priority = annotatedType.getAnnotation(Priority.class); |
| if (priority != null && !webBeansContext.getAlternativesManager() |
| .isAlternative(annotatedType.getJavaClass(), Collections.<Class<? extends Annotation>>emptySet())) |
| { |
| webBeansContext.getAlternativesManager().addPriorityClazzAlternative(annotatedType.getJavaClass(), priority); |
| } |
| } |
| |
| for(ProducerMethodBean<?> producerMethod : producerMethods) |
| { |
| AnnotatedMethod<?> method = webBeansContext.getAnnotatedElementFactory().newAnnotatedMethod(producerMethod.getCreatorMethod(), annotatedType); |
| webBeansContext.getWebBeansUtil().inspectDeploymentErrorStack("There are errors that are added by ProcessProducer event observers for " |
| + "ProducerMethods. Look at logs for further details"); |
| |
| annotatedMethods.put(producerMethod, method); |
| } |
| |
| Map<ProducerFieldBean<?>,AnnotatedField<?>> annotatedFields = |
| new HashMap<ProducerFieldBean<?>, AnnotatedField<?>>(); |
| |
| for(ProducerFieldBean<?> producerField : producerFields) |
| { |
| webBeansContext.getWebBeansUtil().inspectDeploymentErrorStack("There are errors that are added by ProcessProducer event observers for" |
| + " ProducerFields. Look at logs for further details"); |
| |
| annotatedFields.put(producerField, |
| webBeansContext.getAnnotatedElementFactory().newAnnotatedField( |
| producerField.getCreatorField(), |
| webBeansContext.getAnnotatedElementFactory().newAnnotatedType(producerField.getBeanClass()))); |
| } |
| |
| Map<ObserverMethod<?>,AnnotatedMethod<?>> observerMethodsMap = |
| new HashMap<ObserverMethod<?>, AnnotatedMethod<?>>(); |
| |
| for(ObserverMethod<?> observerMethod : observerMethods) |
| { |
| ObserverMethodImpl<?> impl = (ObserverMethodImpl<?>)observerMethod; |
| AnnotatedMethod<?> method = impl.getObserverMethod(); |
| |
| observerMethodsMap.put(observerMethod, method); |
| } |
| |
| BeanManagerImpl beanManager = webBeansContext.getBeanManagerImpl(); |
| |
| //Fires ProcessManagedBean |
| ProcessBeanImpl<T> processBeanEvent = new GProcessManagedBean(managedBean, annotatedType); |
| beanManager.fireEvent(processBeanEvent, true); |
| processBeanEvent.setStarted(); |
| webBeansContext.getWebBeansUtil().inspectDefinitionErrorStack("There are errors that are added by ProcessManagedBean event observers for " + |
| "managed beans. Look at logs for further details"); |
| |
| //Fires ProcessProducerMethod |
| webBeansContext.getWebBeansUtil().fireProcessProducerMethodBeanEvent(annotatedMethods, annotatedType); |
| webBeansContext.getWebBeansUtil().inspectDefinitionErrorStack("There are errors that are added by ProcessProducerMethod event observers for " + |
| "producer method beans. Look at logs for further details"); |
| |
| //Fires ProcessProducerField |
| webBeansContext.getWebBeansUtil().fireProcessProducerFieldBeanEvent(annotatedFields); |
| webBeansContext.getWebBeansUtil().inspectDefinitionErrorStack("There are errors that are added by ProcessProducerField event observers for " + |
| "producer field beans. Look at logs for further details"); |
| |
| //Fire ObservableMethods |
| webBeansContext.getWebBeansUtil().fireProcessObservableMethodBeanEvent(observerMethodsMap); |
| webBeansContext.getWebBeansUtil().inspectDefinitionErrorStack("There are errors that are added by ProcessObserverMethod event observers for " + |
| "observer methods. Look at logs for further details"); |
| |
| if(!webBeansContext.getWebBeansUtil().isAnnotatedTypeDecoratorOrInterceptor(annotatedType)) |
| { |
| beanManager.addBean(bean); |
| for (ProducerMethodBean<?> producerMethod : producerMethods) |
| { |
| // add them one after the other to enable serialization handling et al |
| beanManager.addBean(producerMethod); |
| } |
| for (ProducerFieldBean<?> producerField : producerFields) |
| { |
| // add them one after the other to enable serialization handling et al |
| beanManager.addBean(producerField); |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * Defines enterprise bean via plugin. |
| * @param <T> bean class type |
| * @param clazz bean class |
| */ |
| protected <T> void defineEnterpriseWebBean(Class<T> clazz, AnnotatedType<T> annotatedType, BeanAttributes<T> attributes) |
| { |
| InjectionTargetBean<T> bean = (InjectionTargetBean<T>) EJBWebBeansConfigurator.defineEjbBean( |
| clazz, annotatedType, attributes, webBeansContext); |
| webBeansContext.getWebBeansUtil().setInjectionTargetBeanEnableFlag(bean); |
| } |
| |
| public static class ExtendedBeanAttributes<T> |
| { |
| private final BeanAttributes<T> beanAttributes; |
| private final boolean isEjb; |
| |
| public ExtendedBeanAttributes(final BeanAttributes<T> beanAttributes, final boolean isEjb) |
| { |
| this.beanAttributes = beanAttributes; |
| this.isEjb = isEjb; |
| } |
| } |
| } |