| /* |
| * 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.container; |
| |
| import java.lang.annotation.Annotation; |
| import java.lang.reflect.GenericArrayType; |
| import java.lang.reflect.ParameterizedType; |
| import java.lang.reflect.Type; |
| import java.lang.reflect.TypeVariable; |
| import java.lang.reflect.WildcardType; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.Comparator; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.LinkedHashSet; |
| import java.util.LinkedList; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.concurrent.ConcurrentHashMap; |
| import java.util.concurrent.ConcurrentMap; |
| |
| import jakarta.annotation.PostConstruct; |
| import jakarta.annotation.PreDestroy; |
| import jakarta.el.ELResolver; |
| import jakarta.el.ExpressionFactory; |
| import jakarta.enterprise.context.ContextNotActiveException; |
| import jakarta.enterprise.context.Dependent; |
| import jakarta.enterprise.context.NormalScope; |
| import jakarta.enterprise.context.spi.AlterableContext; |
| import jakarta.enterprise.context.spi.Context; |
| import jakarta.enterprise.context.spi.Contextual; |
| import jakarta.enterprise.context.spi.CreationalContext; |
| import jakarta.enterprise.event.Event; |
| import jakarta.enterprise.inject.Any; |
| import jakarta.enterprise.inject.Default; |
| import jakarta.enterprise.inject.InjectionException; |
| import jakarta.enterprise.inject.Instance; |
| import jakarta.enterprise.inject.Stereotype; |
| import jakarta.enterprise.inject.Vetoed; |
| import jakarta.enterprise.inject.spi.*; |
| import jakarta.inject.Named; |
| import jakarta.inject.Scope; |
| import jakarta.interceptor.InterceptorBinding; |
| import javax.naming.NamingException; |
| import javax.naming.Reference; |
| import javax.naming.Referenceable; |
| import javax.naming.StringRefAddr; |
| |
| import org.apache.webbeans.annotation.AnyLiteral; |
| import org.apache.webbeans.annotation.DefaultLiteral; |
| import org.apache.webbeans.component.AbstractOwbBean; |
| import org.apache.webbeans.component.AbstractProducerBean; |
| 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.JmsBeanMarker; |
| import org.apache.webbeans.component.ManagedBean; |
| import org.apache.webbeans.component.OwbBean; |
| import org.apache.webbeans.component.ProducerAwareInjectionTargetBean; |
| import org.apache.webbeans.component.WebBeansType; |
| 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.FieldProducerFactory; |
| import org.apache.webbeans.component.creation.MethodProducerFactory; |
| import org.apache.webbeans.component.third.PassivationCapableThirdpartyBeanImpl; |
| import org.apache.webbeans.component.third.ThirdpartyBeanImpl; |
| import org.apache.webbeans.config.WebBeansContext; |
| import org.apache.webbeans.context.CustomAlterablePassivatingContextImpl; |
| import org.apache.webbeans.context.CustomPassivatingContextImpl; |
| import org.apache.webbeans.context.creational.CreationalContextImpl; |
| import org.apache.webbeans.decorator.DecoratorComparator; |
| import org.apache.webbeans.event.EventImpl; |
| import org.apache.webbeans.event.EventMetadataImpl; |
| import org.apache.webbeans.exception.WebBeansConfigurationException; |
| import org.apache.webbeans.exception.DuplicateDefinitionException; |
| |
| import org.apache.webbeans.intercept.InterceptorUtil; |
| import org.apache.webbeans.plugins.OpenWebBeansJmsPlugin; |
| import org.apache.webbeans.portable.AnnotatedElementFactory; |
| import org.apache.webbeans.portable.InjectionTargetImpl; |
| import org.apache.webbeans.portable.LazyInterceptorDefinedInjectionTarget; |
| import org.apache.webbeans.portable.events.discovery.ErrorStack; |
| import org.apache.webbeans.portable.events.generics.GProcessInjectionPoint; |
| import org.apache.webbeans.portable.events.generics.GProcessInjectionTarget; |
| import org.apache.webbeans.spi.adaptor.ELAdaptor; |
| import org.apache.webbeans.spi.plugins.OpenWebBeansEjbPlugin; |
| import org.apache.webbeans.util.AnnotationUtil; |
| import org.apache.webbeans.util.Asserts; |
| import org.apache.webbeans.util.ClassUtil; |
| import org.apache.webbeans.util.GenericsUtil; |
| import org.apache.webbeans.util.WebBeansUtil; |
| |
| /** |
| * Implementation of the {@link BeanManager} contract of the web beans |
| * container. |
| * |
| * <p> |
| * It is written as thread-safe. |
| * </p> |
| * |
| * @version $Rev$ $Date$ |
| * @see BeanManager |
| */ |
| @SuppressWarnings("unchecked") |
| public class BeanManagerImpl implements BeanManager, Referenceable |
| { |
| private static final long serialVersionUID = 2L; |
| |
| /** |
| * Holds the non-standard contexts with key = scope type |
| * This will get used if more than 1 scope exists. |
| * Since the contexts will only get added through the |
| * {@link org.apache.webbeans.portable.events.discovery.AfterBeanDiscoveryImpl} |
| * we don't even need a ConcurrentHashMap. |
| * @see #singleContextMap |
| */ |
| private Map<Class<? extends Annotation>, List<Context>> contextMap = new HashMap<>(); |
| |
| /** |
| * This will hold non-standard contexts where only one Context implementation got registered |
| * for the given key = scope type |
| * Since the contexts will only get added through the |
| * {@link org.apache.webbeans.portable.events.discovery.AfterBeanDiscoveryImpl} |
| * we don't even need a ConcurrentHashMap. |
| * @see #contextMap |
| */ |
| private Map<Class<? extends Annotation>, Context> singleContextMap = new HashMap<>(); |
| |
| /**Deployment archive beans*/ |
| private Set<Bean<?>> deploymentBeans = new HashSet<>(); |
| |
| /**Normal scoped cache proxies*/ |
| private Map<Contextual<?>, Object> cacheProxies = new ConcurrentHashMap<>(); |
| |
| /**Injection resolver instance*/ |
| private InjectionResolver injectionResolver; |
| |
| /** |
| * This list contains additional qualifiers which got set via the |
| * {@link jakarta.enterprise.inject.spi.BeforeBeanDiscovery#addQualifier(Class)} |
| * event function. |
| */ |
| private List<Class<? extends Annotation>> additionalQualifiers = new ArrayList<>(); |
| private Map<Class<?>, AnnotatedType<? extends Annotation>> additionalAnnotatedTypeQualifiers = new HashMap<>(); |
| |
| /** |
| * This list contains additional scopes which got set via the |
| * {@link jakarta.enterprise.inject.spi.BeforeBeanDiscovery#addScope(Class, boolean, boolean)} event function. |
| */ |
| private List<ExternalScope> additionalScopes = new ArrayList<>(); |
| |
| /** quick detection if an annotation is a scope-annotation */ |
| private Set<Class<? extends Annotation>> scopeAnnotations = new HashSet<>(); |
| |
| /** quick detection if an annotation is NOT a scope-annotation */ |
| private Set<Class<? extends Annotation>> nonscopeAnnotations = new HashSet<>(); |
| |
| |
| private ConcurrentMap<Class<?>, ConcurrentMap<String, AnnotatedType<?>>> additionalAnnotatedTypes = new ConcurrentHashMap<>(); |
| |
| private ErrorStack errorStack = new ErrorStack(); |
| |
| /** |
| * This map stores all beans along with their unique {@link jakarta.enterprise.inject.spi.PassivationCapable} id. |
| * This is used as a reference for serialization. |
| */ |
| private ConcurrentMap<String, Bean<?>> passivationBeans = new ConcurrentHashMap<>(); |
| |
| /**InjectionTargets for Java EE component instances that supports injections*/ |
| private Map<Class<?>, Producer<?>> producersForJavaEeComponents = |
| new ConcurrentHashMap<>(); |
| |
| private AnnotatedElementFactory annotatedElementFactory; |
| |
| /** |
| * A cache for bean classes which get created 'on the fly' by manually calling createInjectionTarget without a bean. |
| */ |
| private ConcurrentMap<Class<?>, Bean> unmanagedClassBeans = new ConcurrentHashMap<>(); |
| |
| |
| private final WebBeansContext webBeansContext; |
| |
| /** |
| * This flag will get set to <code>true</code> if a custom bean |
| * (all non-internal beans like {@link org.apache.webbeans.component.BeanManagerBean;} etc) |
| * gets set. |
| */ |
| private boolean inUse; |
| |
| /** |
| * This flag will get set to handle lifecyle around |
| * {@link jakarta.enterprise.inject.spi.AfterBeanDiscovery} |
| */ |
| private LifecycleState beanDiscoveryState = LifecycleState.BEFORE_DISCOVERY; |
| |
| /** |
| * This flag will get set to {@code true} after the |
| * {@link jakarta.enterprise.inject.spi.AfterDeploymentValidation} gets fired |
| */ |
| private boolean afterDeploymentValidationFired; |
| |
| /** |
| * we cache results of calls to {@link #isNormalScope(Class)} because |
| * this doesn't change at runtime. |
| * We don't need to take special care about classloader |
| * hierarchies, because each cl has other classes. |
| */ |
| private Map<Class<? extends Annotation>, Boolean> isScopeTypeNormalCache = |
| new ConcurrentHashMap<>(); |
| |
| /** |
| * Map to be able to lookup always 3rd party beans when user does lookups with custom beans. |
| */ |
| private Map<Bean<?>, Bean<?>> thirdPartyMapping = new HashMap<>(); |
| |
| /** |
| * Creates a new {@link BeanManager} instance. |
| * Called by the system. Do not use outside of the |
| * system. |
| */ |
| public BeanManagerImpl(WebBeansContext webBeansContext) |
| { |
| this.webBeansContext = webBeansContext; |
| injectionResolver = new InjectionResolver(webBeansContext); |
| annotatedElementFactory = webBeansContext.getAnnotatedElementFactory(); |
| } |
| |
| public WebBeansContext getWebBeansContext() |
| { |
| return webBeansContext; |
| } |
| |
| public <T> void putProducerForJavaEeComponent(Class<T> javaEeComponentClass, Producer<T> wrapper) |
| { |
| Asserts.assertNotNull(javaEeComponentClass); |
| Asserts.assertNotNull(wrapper); |
| |
| producersForJavaEeComponents.put(javaEeComponentClass, wrapper); |
| } |
| |
| public <T> Producer<T> getProducerForJavaEeComponent(Class<T> javaEeComponentClass) |
| { |
| Asserts.assertNotNull(javaEeComponentClass); |
| return (Producer<T>) producersForJavaEeComponents.get(javaEeComponentClass); |
| } |
| |
| public ErrorStack getErrorStack() |
| { |
| return errorStack; |
| } |
| |
| public ConcurrentMap<Class<?>, Bean> getUnmanagedClassBeans() |
| { |
| return unmanagedClassBeans; |
| } |
| |
| /** |
| * Gets injection resolver. |
| * |
| * @return injection resolver |
| */ |
| public InjectionResolver getInjectionResolver() |
| { |
| return injectionResolver; |
| } |
| |
| /** |
| * Gets the active context for the given scope type. |
| * |
| * @param scopeType scope type of the context |
| * @throws ContextNotActiveException if no active context |
| * @throws IllegalStateException if more than one active context |
| */ |
| @Override |
| public Context getContext(Class<? extends Annotation> scopeType) |
| { |
| Asserts.assertNotNull(scopeType, "scopeType"); |
| |
| Context standardContext = webBeansContext.getContextsService().getCurrentContext(scopeType); |
| |
| if(standardContext != null && standardContext.isActive()) |
| { |
| return standardContext; |
| } |
| |
| // this is by far the most case |
| Context singleContext = singleContextMap.get(scopeType); |
| if (singleContext != null) |
| { |
| if (!singleContext.isActive()) |
| { |
| throw new ContextNotActiveException("WebBeans context with scope type annotation @" |
| + scopeType.getSimpleName() |
| + " does not exist within current thread"); |
| } |
| return singleContext; |
| } |
| |
| // the spec also allows for multiple contexts existing for the same scope type |
| // but in this case only one must be active at a time (for the current thread) |
| List<Context> others = contextMap.get(scopeType); |
| Context found = null; |
| |
| if(others != null) |
| { |
| for(Context otherContext : others) |
| { |
| if(otherContext.isActive()) |
| { |
| if (found != null) |
| { |
| throw new IllegalStateException("More than one active context exists with scope type annotation @" |
| + scopeType.getSimpleName()); |
| } |
| |
| found = otherContext; |
| } |
| } |
| } |
| |
| if (found == null) |
| { |
| throw new ContextNotActiveException("WebBeans context with scope type annotation @" |
| + scopeType.getSimpleName() + " does not exist within current thread"); |
| } |
| |
| return found; |
| } |
| |
| @Override |
| public Instance<Object> createInstance() |
| { |
| return OwbCDI.current().select(DefaultLiteral.INSTANCE); |
| } |
| |
| /** |
| * Add new bean to the BeanManager. |
| * This will also set OWBs {@link #inUse} status. |
| * |
| * @param newBean new bean instance |
| * @return the this manager |
| */ |
| public BeanManager addBean(Bean<?> newBean) |
| { |
| inUse = true; |
| return addInternalBean(newBean); |
| } |
| |
| /** |
| * This method is reserved for adding 'internal beans' |
| * like e.g. a BeanManagerBean, |
| * @param newBean |
| * @return |
| */ |
| public <T> BeanManager addInternalBean(Bean<T> newBean) |
| { |
| if(newBean instanceof AbstractOwbBean) |
| { |
| addPassivationInfo(newBean); |
| deploymentBeans.add(newBean); |
| } |
| else |
| { |
| ThirdpartyBeanImpl<?> bean; |
| if (!PassivationCapable.class.isInstance(newBean)) |
| { |
| bean = new ThirdpartyBeanImpl<>(webBeansContext, newBean); |
| } |
| else |
| { |
| bean = new PassivationCapableThirdpartyBeanImpl<>(webBeansContext, newBean); |
| } |
| addPassivationInfo(bean); |
| deploymentBeans.add(bean); |
| thirdPartyMapping.put(newBean, bean); |
| } |
| |
| return this; |
| } |
| |
| |
| /** |
| * Check if the bean is has a passivation id and add it to the id store. |
| * |
| * @param bean |
| * @throws DefinitionException if the id is not unique. |
| */ |
| public void addPassivationInfo(Bean<?> bean) throws DefinitionException |
| { |
| String id = null; |
| if (bean instanceof OwbBean<?>) |
| { |
| id = ((OwbBean) bean).getId(); |
| } |
| if (id == null && bean instanceof PassivationCapable) |
| { |
| id = ((PassivationCapable) bean).getId(); |
| } |
| |
| if(id != null) |
| { |
| Bean<?> oldBean = passivationBeans.putIfAbsent(id, bean); |
| if (oldBean != null) |
| { |
| throw new DuplicateDefinitionException("PassivationCapable bean id is not unique: " + |
| id + " bean:" + bean + ", existing: " + oldBean); |
| } |
| } |
| } |
| |
| |
| public BeanManager addContext(Context context) |
| { |
| addContext(context.getScope(), wrapCustomContext(context)); |
| |
| return this; |
| |
| } |
| |
| /** |
| * If the context is passivating then we need to wrap it into a version which |
| * uses the {@link SerializableBeanVault } |
| */ |
| public Context wrapCustomContext(Context context) |
| { |
| if (isPassivatingScope(context.getScope())) |
| { |
| if (context instanceof AlterableContext) |
| { |
| return new CustomAlterablePassivatingContextImpl(webBeansContext.getSerializableBeanVault(), (AlterableContext) context); |
| } |
| else |
| { |
| return new CustomPassivatingContextImpl(webBeansContext.getSerializableBeanVault(), context); |
| } |
| } |
| |
| return context; |
| } |
| |
| |
| /** |
| * @deprecated This method got deprecated in CDI-2.0. |
| * Users should use {@link #getEvent()} instead. |
| */ |
| public void fireEvent(Object event, Annotation... bindings) |
| { |
| fireEvent(event, false, bindings); |
| } |
| |
| @Override |
| public Event<Object> getEvent() |
| { |
| return new EventImpl<>(new EventMetadataImpl(null, Object.class, null, new Annotation[]{AnyLiteral.INSTANCE}, webBeansContext), webBeansContext); |
| } |
| |
| public void fireEvent(Object event, boolean containerEvent, Annotation... bindings) |
| { |
| Type type = event.getClass(); |
| if (GenericsUtil.hasTypeParameters(type)) |
| { |
| type = GenericsUtil.getParameterizedType(type); |
| } |
| fireEvent(event, new EventMetadataImpl(null, type, null, bindings, webBeansContext), containerEvent); |
| } |
| |
| /** |
| * Fire @Initialized and @Destroyed events, but only IF any observers do exist. |
| */ |
| public void fireContextLifecyleEvent(Object payload, Annotation lifecycleQualifier) |
| { |
| if (webBeansContext.getNotificationManager().hasContextLifecycleObserver(lifecycleQualifier)) |
| { |
| fireEvent(payload, lifecycleQualifier); |
| } |
| } |
| |
| /** |
| * Like {@link #fireEvent(Object, java.lang.annotation.Annotation...)} but intended for |
| * internal CDI Container lifecycle events. The difference is that those |
| * events must only be delivered to CDI Extensions and not to normal beans. |
| */ |
| public void fireLifecycleEvent(Object event, Annotation... bindings) |
| { |
| fireEvent(event, new EventMetadataImpl(null, event.getClass(), null, bindings, webBeansContext), true); |
| } |
| |
| public void fireEvent(Object event, EventMetadataImpl metadata, boolean isLifecycleEvent) |
| { |
| webBeansContext.getNotificationManager().fireEvent(event, metadata, isLifecycleEvent, null); |
| } |
| |
| public Set<Bean<?>> getComponents() |
| { |
| return deploymentBeans; |
| } |
| |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public List<Decorator<?>> resolveDecorators(Set<Type> types, Annotation... bindingTypes) |
| { |
| webBeansContext.getAnnotationManager().checkDecoratorResolverParams(types, bindingTypes); |
| return unsafeResolveDecorators(types, bindingTypes); |
| } |
| |
| public List<Decorator<?>> unsafeResolveDecorators(Set<Type> types, Annotation[] bindingTypes) |
| { |
| webBeansContext.getAnnotationManager().checkQualifiersParams(types, bindingTypes); // checkDecoratorResolverParams is too restrictive for repeatable bindings |
| Set<Decorator<?>> intsSet = webBeansContext.getDecoratorsManager().findDeployedWebBeansDecorator(types, bindingTypes); |
| List<Decorator<?>> decoratorList = new ArrayList<>(intsSet); |
| decoratorList.sort(new DecoratorComparator(webBeansContext)); |
| return decoratorList; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public List<Interceptor<?>> resolveInterceptors(InterceptionType type, Annotation... interceptorBindings) |
| { |
| webBeansContext.getAnnotationManager().checkInterceptorResolverParams(interceptorBindings); |
| |
| return webBeansContext.getInterceptorsManager().resolveInterceptors(type, interceptorBindings); |
| } |
| |
| |
| public Set<Bean<?>> getBeans() |
| { |
| return deploymentBeans; |
| } |
| |
| private void addContext(Class<? extends Annotation> scopeType, jakarta.enterprise.context.spi.Context context) |
| { |
| Asserts.assertNotNull(scopeType, "scopeType"); |
| Asserts.assertNotNull(context, "context"); |
| |
| List<Context> contextList = contextMap.get(scopeType); |
| |
| if(contextList == null) |
| { |
| Context singleContext = singleContextMap.get(scopeType); |
| if (singleContext == null) |
| { |
| // first put them into the singleContextMap |
| singleContextMap.put(scopeType, context); |
| } |
| else |
| { |
| // from the 2nd Context for this scopetype on, we need to maintain a List for them |
| contextList = new ArrayList<>(); |
| contextList.add(singleContext); |
| contextList.add(context); |
| |
| contextMap.put(scopeType, contextList); |
| singleContextMap.remove(scopeType); |
| } |
| } |
| else |
| { |
| contextList.add(context); |
| } |
| |
| } |
| |
| @Override |
| public Reference getReference() throws NamingException |
| { |
| return new Reference(BeanManagerImpl.class.getName(), new StringRefAddr("ManagerImpl", "ManagerImpl"), ManagerObjectFactory.class.getName(), null); |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public <T> AnnotatedType<T> createAnnotatedType(Class<T> type) |
| { |
| return annotatedElementFactory.newAnnotatedType(type); |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public <T> CreationalContextImpl<T> createCreationalContext(Contextual<T> contextual) |
| { |
| if (contextual instanceof SerializableBean) |
| { |
| contextual = ((SerializableBean)contextual).getBean(); |
| } |
| |
| return webBeansContext.getCreationalContextFactory().getCreationalContext(contextual); |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public Set<Bean<?>> getBeans(Type beanType, Annotation... bindings) |
| { |
| if(ClassUtil.isTypeVariable(beanType)) |
| { |
| throw new IllegalArgumentException("Exception in getBeans method. Bean type can not be TypeVariable for bean type : " + beanType); |
| } |
| |
| webBeansContext.getAnnotationManager().checkQualifierConditions(bindings); |
| |
| return injectionResolver.implResolveByType(false, beanType, bindings); |
| |
| } |
| |
| @Override |
| public Set<Bean<?>> getBeans(String name) |
| { |
| Asserts.assertNotNull(name, "name"); |
| |
| return injectionResolver.implResolveByName(name); |
| } |
| |
| @Override |
| public ELResolver getELResolver() |
| { |
| ELAdaptor elAdaptor = webBeansContext.getService(ELAdaptor.class); |
| return elAdaptor.getOwbELResolver(); |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public Object getInjectableReference(InjectionPoint injectionPoint, CreationalContext<?> ownerCreationalContext) |
| { |
| //Injection point is null |
| if(injectionPoint == null) |
| { |
| return null; |
| } |
| |
| //Injected instance |
| Object instance; |
| |
| |
| //Find the injection point Bean |
| Bean<Object> injectedBean = (Bean<Object>)injectionResolver.getInjectionPointBean(injectionPoint); |
| |
| |
| if(WebBeansUtil.isDependent(injectedBean)) |
| { |
| if (!(ownerCreationalContext instanceof CreationalContextImpl)) |
| { |
| ownerCreationalContext = webBeansContext.getCreationalContextFactory().wrappedCreationalContext(ownerCreationalContext, injectionPoint.getBean()); |
| } |
| |
| if (injectionPoint.isDelegate() && ((CreationalContextImpl<?>)ownerCreationalContext).getDelegate() != null) |
| { |
| // this is a dirty hack for Custom Decorators which inject into @Delegate InjectionPoints |
| // by using getInjectableReference. Done in the TCK. Never seen this for real though... |
| return ((CreationalContextImpl<?>)ownerCreationalContext).getDelegate(); |
| } |
| |
| ((CreationalContextImpl<?>)ownerCreationalContext).putInjectionPoint(injectionPoint); |
| //Using owner creational context |
| //Dependents use parent creational context |
| try |
| { |
| instance = getReference(injectedBean, injectionPoint.getType(), ownerCreationalContext); |
| } |
| finally |
| { |
| ((CreationalContextImpl<?>)ownerCreationalContext).removeInjectionPoint(); |
| } |
| } |
| else |
| { |
| //New creational context for normal scoped beans |
| CreationalContextImpl<Object> injectedCreational = (CreationalContextImpl<Object>)createCreationalContext(injectedBean); |
| injectedCreational.putInjectionPoint(injectionPoint); |
| try |
| { |
| instance = getReference(injectedBean, injectionPoint.getType(), injectedCreational); |
| } |
| finally |
| { |
| injectedCreational.removeInjectionPoint(); |
| } |
| } |
| |
| return instance; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public Set<Annotation> getInterceptorBindingDefinition(Class<? extends Annotation> binding) |
| { |
| Annotation[] annotations = binding.getDeclaredAnnotations(); |
| Set<Annotation> set = new HashSet<>(); |
| |
| if(binding.isAnnotationPresent(InterceptorBinding.class)) |
| { |
| Collections.addAll(set, annotations); |
| } |
| |
| return set; |
| } |
| |
| @Override |
| public Bean<?> getPassivationCapableBean(String id) |
| { |
| return passivationBeans.get(id); |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public Object getReference(Bean<?> providedBean, Type beanType, CreationalContext<?> creationalContext) |
| { |
| Asserts.assertNotNull(providedBean, "bean parameter"); |
| |
| Context context; |
| Object instance; |
| |
| Bean<?> bean = !OwbBean.class.isInstance(providedBean) ? thirdPartyMapping.get(providedBean) : providedBean; |
| if (bean == null) // more than unlikely but still possible and not invalid (user could create new instance of bean each time, not forbidden) |
| { |
| bean = providedBean; |
| } |
| if (bean instanceof SerializableBean) |
| { |
| bean = ((SerializableBean)bean).getBean(); |
| } |
| |
| if(!(creationalContext instanceof CreationalContextImpl)) |
| { |
| creationalContext = webBeansContext.getCreationalContextFactory().wrappedCreationalContext(creationalContext, bean); |
| } |
| |
| if (ManagedBean.class.isInstance(bean)) |
| { |
| ManagedBean.class.cast(bean).valid(); |
| } |
| |
| //Check type if bean type is given |
| if(beanType != null && beanType != Object.class) |
| { |
| boolean isProducer = bean instanceof AbstractProducerBean; |
| if(!isProducer && // we have different rules for producers |
| !isBeanTypeAssignableToGivenType(bean.getTypes(), beanType, false) && |
| !GenericsUtil.satisfiesDependency(false, false, beanType, bean.getBeanClass(), new HashMap<>()) && |
| !GenericsUtil.satisfiesDependencyRaw(false, false, beanType, bean.getBeanClass(), new HashMap<>())) |
| { |
| throw new IllegalArgumentException("Given bean type : " + beanType + " is not applicable for the bean instance : " + bean); |
| } |
| |
| } |
| else if (bean instanceof OwbBean) |
| { |
| // we cannot always use getBeanClass() as this will |
| // return the containing class for producer methods and fields |
| beanType = ((OwbBean) bean).getReturnType(); |
| } |
| else |
| { |
| beanType = bean.getBeanClass(); |
| } |
| |
| //Scope is normal |
| if (isNormalScope(bean.getScope())) |
| { |
| instance = getEjbOrJmsProxyReference(bean, beanType,creationalContext); |
| |
| if(instance != null) |
| { |
| return instance; |
| } |
| |
| instance = cacheProxies.get(bean); |
| |
| if (instance == null) |
| { |
| //Create Managed Bean Proxy |
| instance = webBeansContext.getNormalScopeProxyFactory().createNormalScopeProxy(bean); |
| |
| //Cached instance |
| cacheProxies.put(bean, instance); |
| } |
| |
| } |
| //Create Pseudo-Scope Bean Instance |
| else |
| { |
| //Get bean context |
| context = getContext(bean.getScope()); |
| |
| //Get instance for ejb or jms |
| instance = getEjbOrJmsProxyReference(bean, beanType, creationalContext); |
| |
| if(instance != null) |
| { |
| return instance; |
| } |
| |
| //Get dependent from DependentContex that create contextual instance |
| instance = context.get((Bean<Object>)bean, (CreationalContext<Object>)creationalContext); |
| } |
| |
| return instance; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public BeanAttributes<?> createBeanAttributes(AnnotatedMember<?> member) |
| { |
| if (member instanceof AnnotatedField) |
| { |
| return BeanAttributesBuilder.forContext(webBeansContext).newBeanAttibutes((AnnotatedField<?>)member).build(); |
| } |
| else if (member instanceof AnnotatedMethod) |
| { |
| return BeanAttributesBuilder.forContext(webBeansContext).newBeanAttibutes((AnnotatedMethod<?>)member).build(); |
| } |
| else |
| { |
| throw new IllegalArgumentException("Unsupported member type " + member.getClass().getName()); |
| } |
| } |
| |
| @Override |
| public InjectionPoint createInjectionPoint(AnnotatedField<?> field) |
| { |
| return webBeansContext.getInjectionPointFactory().buildInjectionPoint(null, field, false); |
| } |
| |
| @Override |
| public InjectionPoint createInjectionPoint(AnnotatedParameter<?> parameter) |
| { |
| InjectionPoint injectionPoint = webBeansContext.getInjectionPointFactory().buildInjectionPoint(null, parameter, false); |
| if (AnnotatedMethod.class.isInstance(parameter.getDeclaringCallable())) |
| { |
| try |
| { |
| validate(injectionPoint); |
| } |
| catch (Exception e) |
| { |
| throw new IllegalArgumentException(e); |
| } |
| } // TODO else constructor rules are a bit different |
| GProcessInjectionPoint event = webBeansContext.getWebBeansUtil().fireProcessInjectionPointEvent(injectionPoint); |
| injectionPoint = event.getInjectionPoint(); |
| event.setStarted(); |
| return injectionPoint; |
| } |
| |
| @Override |
| public <X> ProducerFactory<X> getProducerFactory(AnnotatedField<? super X> field, Bean<X> bean) |
| { |
| return new FieldProducerFactory<>(field, bean, webBeansContext); |
| } |
| |
| @Override |
| public <X> ProducerFactory<X> getProducerFactory(AnnotatedMethod<? super X> method, Bean<X> bean) |
| { |
| return new MethodProducerFactory<>(method, bean, webBeansContext); |
| } |
| |
| @Override |
| public <X> InjectionTargetFactory<X> getInjectionTargetFactory(AnnotatedType<X> type) |
| { |
| return new ValidatingInjectionTargetFactory<>(type, webBeansContext); |
| } |
| |
| @Override |
| public <T> Bean<T> createBean(BeanAttributes<T> attributes, Class<T> type, InjectionTargetFactory<T> factory) |
| { |
| AnnotatedType annotatedType = InjectionTargetFactoryImpl.class.isInstance(factory) ? |
| InjectionTargetFactoryImpl.class.cast(factory).getAnnotatedType() : getOrCreateAnnotatedType(type); |
| |
| if (WebBeansUtil.isDecorator(annotatedType)) |
| { |
| DecoratorBeanBuilder<T> dbb = new DecoratorBeanBuilder<T>(webBeansContext, annotatedType, attributes); |
| DecoratorBean<T> decorator = null; |
| if (dbb.isDecoratorEnabled()) |
| { |
| dbb.defineDecoratorRules(); |
| decorator = dbb.getBean(); |
| webBeansContext.getDecoratorsManager().addDecorator(decorator); |
| } |
| return decorator; |
| } |
| else if(WebBeansUtil.isCdiInterceptor(annotatedType)) |
| { |
| CdiInterceptorBeanBuilder<T> ibb = new CdiInterceptorBeanBuilder<T>(webBeansContext, annotatedType, attributes); |
| CdiInterceptorBean<T> interceptor = null; |
| if (ibb.isInterceptorEnabled()) |
| { |
| ibb.defineCdiInterceptorRules(); |
| interceptor = ibb.getBean(); |
| webBeansContext.getInterceptorsManager().addCdiInterceptor(interceptor); |
| } |
| return interceptor; |
| } |
| |
| InjectionTargetBean<T> bean = new InjectionTargetBean<T>( |
| webBeansContext, |
| WebBeansType.THIRDPARTY, |
| annotatedType, |
| attributes, type, factory); |
| |
| if (webBeansContext.getOpenWebBeansConfiguration().supportsInterceptionOnProducers()) |
| { |
| bean.defineInterceptorsIfNeeded(); |
| } |
| |
| return bean; |
| } |
| |
| private <T> AnnotatedType<T> getOrCreateAnnotatedType(Class<T> type) |
| { |
| AnnotatedType<T> annotatedType = webBeansContext.getAnnotatedElementFactory().getAnnotatedType(type); |
| if (annotatedType == null) |
| { |
| annotatedType = webBeansContext.getAnnotatedElementFactory().newAnnotatedType(type); |
| } |
| return annotatedType; |
| } |
| |
| |
| private boolean isBeanTypeAssignableToGivenType(Set<Type> beanTypes, Type givenType, boolean producer) |
| { |
| for (Type beanApiType : beanTypes) |
| { |
| if (GenericsUtil.satisfiesDependency(false, producer, givenType, beanApiType, new HashMap<>())) |
| { |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| |
| private Object getEjbOrJmsProxyReference(Bean<?> bean,Type beanType, CreationalContext<?> creationalContext) |
| { |
| //Create session bean proxy |
| if(bean instanceof EnterpriseBeanMarker) |
| { |
| if(isNormalScope(bean.getScope())) |
| { |
| //Maybe it is cached |
| if(cacheProxies.containsKey(bean)) |
| { |
| return cacheProxies.get(bean); |
| } |
| } |
| |
| OpenWebBeansEjbPlugin ejbPlugin = webBeansContext.getPluginLoader().getEjbPlugin(); |
| if(ejbPlugin == null) |
| { |
| throw new IllegalStateException("There is no EJB plugin provider. Injection is failed for bean : " + bean); |
| } |
| |
| return ejbPlugin.getSessionBeanProxy(bean,ClassUtil.getClazz(beanType), creationalContext); |
| } |
| |
| //Create JMS Proxy |
| else if(bean instanceof JmsBeanMarker) |
| { |
| OpenWebBeansJmsPlugin jmsPlugin = webBeansContext.getPluginLoader().getJmsPlugin(); |
| if(jmsPlugin == null) |
| { |
| throw new IllegalStateException("There is no JMS plugin provider. Injection is failed for bean : " + bean); |
| } |
| |
| return jmsPlugin.getJmsBeanProxy(bean, ClassUtil.getClass(beanType)); |
| } |
| |
| return null; |
| } |
| |
| |
| @Override |
| public Set<Annotation> getStereotypeDefinition(Class<? extends Annotation> stereotype) |
| { |
| Annotation[] annotations = stereotype.getDeclaredAnnotations(); |
| Set<Annotation> set = new HashSet<>(); |
| |
| if(stereotype.isAnnotationPresent(Stereotype.class)) |
| { |
| Collections.addAll(set, annotations); |
| } |
| |
| return set; |
| } |
| |
| @Override |
| public boolean isQualifier(Class<? extends Annotation> annotationType) |
| { |
| return webBeansContext.getAnnotationManager().isQualifierAnnotation(annotationType); |
| } |
| |
| @Override |
| public boolean isInterceptorBinding(Class<? extends Annotation> annotationType) |
| { |
| return webBeansContext.getAnnotationManager().isInterceptorBindingAnnotation(annotationType); |
| } |
| |
| @Override |
| public boolean isScope(Class<? extends Annotation> annotationType) |
| { |
| if (nonscopeAnnotations.contains(annotationType)) |
| { |
| return false; |
| } |
| |
| if (scopeAnnotations.contains(annotationType)) |
| { |
| return true; |
| } |
| |
| boolean isScopeAnnotation = annotationType.getAnnotation(Scope.class) != null || |
| annotationType.getAnnotation(NormalScope.class) != null; |
| |
| if (!isScopeAnnotation) |
| { |
| // also check external scopes |
| for (ExternalScope es : getAdditionalScopes()) |
| { |
| if (es.getScope().equals(annotationType)) |
| { |
| isScopeAnnotation = true; |
| break; |
| } |
| } |
| } |
| |
| if (isScopeAnnotation) |
| { |
| scopeAnnotations.add(annotationType); |
| } |
| else |
| { |
| nonscopeAnnotations.add(annotationType); |
| } |
| |
| return isScopeAnnotation; |
| } |
| |
| @Override |
| public boolean isNormalScope(Class<? extends Annotation> scopeType) |
| { |
| Boolean isNormal = isScopeTypeNormalCache.get(scopeType); |
| |
| if (isNormal != null) |
| { |
| return isNormal; |
| } |
| |
| for(ExternalScope extScope : additionalScopes) |
| { |
| if (extScope.getScope().equals(scopeType)) |
| { |
| isScopeTypeNormalCache.put(scopeType, extScope.isNormal()); |
| return extScope.isNormal(); |
| } |
| } |
| |
| isNormal = scopeType.getAnnotation(NormalScope.class) != null; |
| isScopeTypeNormalCache.put(scopeType, isNormal); |
| |
| return isNormal; |
| } |
| |
| @Override |
| public boolean isPassivatingScope(Class<? extends Annotation> annotationType) |
| { |
| for(ExternalScope extScope : additionalScopes) |
| { |
| if (extScope.getScope().equals(annotationType)) |
| { |
| return extScope.isPassivating(); |
| } |
| } |
| |
| NormalScope scope = annotationType.getAnnotation(NormalScope.class); |
| |
| if(scope != null) |
| { |
| return scope.passivating(); |
| } |
| |
| return false; |
| } |
| |
| |
| @Override |
| public boolean isStereotype(Class<? extends Annotation> annotationType) |
| { |
| return AnnotationUtil.hasAnnotation(annotationType.getDeclaredAnnotations(), Stereotype.class); |
| } |
| |
| @Override |
| public boolean areInterceptorBindingsEquivalent(Annotation annotation1, Annotation annotation2) |
| { |
| return AnnotationUtil.isCdiAnnotationEqual(annotation1, annotation2); |
| } |
| |
| @Override |
| public boolean areQualifiersEquivalent(Annotation annotation1, Annotation annotation2) |
| { |
| return AnnotationUtil.isCdiAnnotationEqual(annotation1, annotation2); |
| } |
| |
| @Override |
| public int getInterceptorBindingHashCode(Annotation annotation) |
| { |
| return AnnotationUtil.getCdiAnnotationHashCode(annotation); |
| } |
| |
| @Override |
| public int getQualifierHashCode(Annotation annotation) |
| { |
| return AnnotationUtil.getCdiAnnotationHashCode(annotation); |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public <T> BeanAttributes<T> createBeanAttributes(AnnotatedType<T> type) |
| { |
| OpenWebBeansEjbPlugin ejbPlugin = webBeansContext.getPluginLoader().getEjbPlugin(); |
| if (ejbPlugin != null && ejbPlugin.isSessionBean(type.getJavaClass())) |
| { |
| return ejbPlugin.createBeanAttributes(type); |
| } |
| return BeanAttributesBuilder.forContext(webBeansContext).newBeanAttibutes(type).build(); |
| } |
| |
| @Override |
| public <T, X> Bean<T> createBean(BeanAttributes<T> attributes, Class<X> type, ProducerFactory<X> factory) |
| { |
| return new ProducerAwareInjectionTargetBean<>( |
| webBeansContext, |
| WebBeansType.THIRDPARTY, |
| attributes, |
| findClass(factory, type), |
| factory); |
| } |
| |
| private Class<?> findClass(ProducerFactory<?> factory, Class<?> type) |
| { |
| if (MethodProducerFactory.class.isInstance(factory)) |
| { |
| return MethodProducerFactory.class.cast(factory).getReturnType(); |
| } |
| if (FieldProducerFactory.class.isInstance(factory)) |
| { |
| return FieldProducerFactory.class.cast(factory).getReturnType(); |
| } |
| return type; |
| } |
| |
| public <T extends Extension> T getExtension(Class<T> type) |
| { |
| T extension = webBeansContext.getExtensionLoader().getExtension(type); |
| if (extension == null) |
| { |
| throw new IllegalArgumentException("extension " + type + " not registered"); |
| } |
| return extension; |
| } |
| |
| @Override |
| public <X> Bean<? extends X> resolve(Set<Bean<? extends X>> beans) |
| { |
| return injectionResolver.resolve(beans, null); |
| } |
| |
| @Override |
| public <T> InterceptionFactory<T> createInterceptionFactory(CreationalContext<T> creationalContext, Class<T> clazz) |
| { |
| return new InterceptionFactoryImpl( |
| webBeansContext, createAnnotatedType(clazz), AnnotationUtil.DEFAULT_AND_ANY_ANNOTATION_SET, |
| // ok, we can need to not cast that brutally |
| CreationalContextImpl.class.cast(creationalContext)); |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public void validate(InjectionPoint injectionPoint) |
| { |
| if (injectionPoint == null) |
| { |
| throw new IllegalArgumentException("InjectionPoint parameter must not be nul"); |
| } |
| |
| Bean<?> bean = injectionPoint.getBean(); |
| |
| //Check for correct injection type |
| injectionResolver.checkInjectionPointType(injectionPoint); |
| |
| Class<?> rawType = ClassUtil.getRawTypeForInjectionPoint(injectionPoint); |
| |
| // check for InjectionPoint injection |
| if (rawType.equals(InjectionPoint.class)) |
| { |
| if (AnnotationUtil.hasAnnotation(AnnotationUtil.asArray(injectionPoint.getQualifiers()), Default.class)) |
| { |
| if (!bean.getScope().equals(Dependent.class)) |
| { |
| throw new WebBeansConfigurationException("Bean " + bean.getBeanClass() + " scope can not define other scope except @Dependent to inject InjectionPoint"); |
| } |
| } |
| } |
| else |
| { |
| injectionResolver.checkInjectionPoint(injectionPoint); |
| } |
| } |
| |
| /** |
| * @deprecated This method got deprecated in CDI-1.1 and removed in CDI-4.0. |
| * Use {@link #getInjectionTargetFactory(AnnotatedType)} instead. |
| */ |
| @Deprecated |
| public <T> InjectionTarget<T> createInjectionTarget(AnnotatedType<T> type) |
| { |
| InjectionTargetFactoryImpl<T> factory = new InjectionTargetFactoryImpl<>(type, webBeansContext); |
| InterceptorUtil interceptorUtil = webBeansContext.getInterceptorUtil(); |
| InjectionTargetImpl<T> injectionTarget = new LazyInterceptorDefinedInjectionTarget<>( |
| type, |
| factory.createInjectionPoints(null), |
| webBeansContext, |
| interceptorUtil.getLifecycleMethods(type, PostConstruct.class), |
| interceptorUtil.getLifecycleMethods(type, PreDestroy.class)); |
| if (isAfterBeanDiscoveryDone()) |
| { |
| try |
| { |
| webBeansContext.getWebBeansUtil().validate(injectionTarget.getInjectionPoints(), null); |
| } |
| catch (InjectionException | DeploymentException | WebBeansConfigurationException ie) |
| { |
| throw new IllegalArgumentException(ie); |
| } |
| } |
| GProcessInjectionTarget event = webBeansContext.getWebBeansUtil().fireProcessInjectionTargetEvent(injectionTarget, type); |
| InjectionTarget it = event.getInjectionTarget(); |
| event.setStarted(); |
| return it; |
| } |
| |
| |
| @Override |
| public <T> Set<ObserverMethod<? super T>> resolveObserverMethods(T event, Annotation... qualifiers) |
| { |
| return resolveObserverMethods(event, new EventMetadataImpl(null, event.getClass(), null, qualifiers, webBeansContext)); |
| } |
| |
| public <T> Set<ObserverMethod<? super T>> resolveObserverMethods(T event, EventMetadataImpl metadata) |
| { |
| LinkedList<ObserverMethod<? super Object>> observerMethods |
| = new LinkedList<>(webBeansContext.getNotificationManager().resolveObservers(event, metadata, false)); |
| |
| // new in CDI-2.0: sort observers |
| observerMethods.sort(Comparator.comparingInt(ObserverMethod::getPriority)); |
| |
| return new LinkedHashSet<>(observerMethods); |
| } |
| |
| @Override |
| public ExpressionFactory wrapExpressionFactory(ExpressionFactory expressionFactory) |
| { |
| ELAdaptor elAdaptor = webBeansContext.getService(ELAdaptor.class); |
| return elAdaptor.getOwbWrappedExpressionFactory(expressionFactory); |
| } |
| |
| @Override |
| public Collection<Context> getContexts(Class<? extends Annotation> scopeType) |
| { |
| Asserts.assertNotNull(scopeType, "scopeType"); |
| |
| List<Context> result = new ArrayList<>(); |
| |
| Context standardContext = webBeansContext.getContextsService().getCurrentContext(scopeType, false); |
| if (standardContext != null) |
| { |
| result.add(standardContext); |
| } |
| |
| List<Context> registered = contextMap.get(scopeType); |
| if (registered != null && !registered.isEmpty()) |
| { |
| result.addAll(registered); |
| } |
| else |
| { |
| Context singleRegistered = singleContextMap.get(scopeType); |
| if (singleRegistered != null) |
| { |
| result.add(singleRegistered); |
| } |
| } |
| |
| return List.copyOf(result); |
| } |
| |
| @Override |
| public boolean isMatchingBean(Set<Type> beanTypes, Set<Annotation> beanQualifiers, Type requiredType, Set<Annotation> requiredQualifiers) |
| { |
| if (beanTypes == null) |
| { |
| throw new IllegalArgumentException("Null bean types"); |
| } |
| if (beanQualifiers == null) |
| { |
| throw new IllegalArgumentException("Null bean qualifiers"); |
| } |
| if (requiredType == null) |
| { |
| throw new IllegalArgumentException("Null bean type"); |
| } |
| if (requiredQualifiers == null) |
| { |
| throw new IllegalArgumentException("Null required qualifiers"); |
| } |
| validateAssignabilityQualifiers(beanQualifiers, "beanQualifiers annotation not a qualifier"); |
| validateAssignabilityQualifiers(requiredQualifiers, "requiredQualifiers annotation not a qualifier"); |
| |
| Set<Type> legalBeanTypes = new HashSet<>(); |
| legalBeanTypes.add(Object.class); |
| for (Type beanType : beanTypes) |
| { |
| if (!isIllegalBeanTypeForAssignability(beanType)) |
| { |
| legalBeanTypes.add(beanType); |
| } |
| } |
| |
| if (!matchesRequiredBeanType(requiredType, legalBeanTypes)) |
| { |
| return false; |
| } |
| |
| Set<Annotation> normalizedBeanQualifiers = normalizeBeanQualifiersForAssignability(beanQualifiers); |
| Set<Annotation> normalizedRequired = requiredQualifiers.isEmpty() |
| ? Collections.singleton(DefaultLiteral.INSTANCE) |
| : new HashSet<>(requiredQualifiers); |
| |
| return hasAllQualifiers(normalizedBeanQualifiers, normalizedRequired); |
| } |
| |
| @Override |
| public boolean isMatchingEvent(Type specifiedType, Set<Annotation> specifiedQualifiers, Type observedEventType, Set<Annotation> observedEventQualifiers) |
| { |
| if (specifiedType == null) |
| { |
| throw new IllegalArgumentException("Null event type"); |
| } |
| if (specifiedQualifiers == null) |
| { |
| throw new IllegalArgumentException("Null specified qualifiers"); |
| } |
| if (observedEventType == null) |
| { |
| throw new IllegalArgumentException("Null observed event type"); |
| } |
| if (observedEventQualifiers == null) |
| { |
| throw new IllegalArgumentException("Null observed event qualifiers"); |
| } |
| if (containsUnboundTypeVariable(specifiedType)) |
| { |
| throw new IllegalArgumentException("Type variable in event type"); |
| } |
| validateAssignabilityQualifiers(specifiedQualifiers, "A specifiedQualifiers annotation not a qualifier"); |
| validateAssignabilityQualifiers(observedEventQualifiers, "An observedEventQualifiers annotation not a qualifier"); |
| |
| Class<?> eventClass = ClassUtil.getClazz(specifiedType); |
| Set<Type> eventTypeClosure = GenericsUtil.getTypeClosure(specifiedType, eventClass); |
| if (GenericsUtil.containTypeVariable(eventTypeClosure)) |
| { |
| throw new IllegalArgumentException("Type variable in event type"); |
| } |
| |
| if (!matchesObservedEventType(observedEventType, eventTypeClosure)) |
| { |
| return false; |
| } |
| |
| Set<Annotation> normalizedEventQualifiers = new HashSet<>(specifiedQualifiers); |
| if (normalizedEventQualifiers.isEmpty()) |
| { |
| normalizedEventQualifiers.add(DefaultLiteral.INSTANCE); |
| } |
| normalizedEventQualifiers.add(AnyLiteral.INSTANCE); |
| |
| return hasAllQualifiers(normalizedEventQualifiers, observedEventQualifiers); |
| } |
| |
| public void addAdditionalQualifier(Class<? extends Annotation> qualifier) |
| { |
| if (!additionalQualifiers.contains(qualifier)) |
| { |
| additionalQualifiers.add(qualifier); |
| } |
| } |
| |
| public void addAdditionalQualifier(AnnotatedType<? extends Annotation> qualifier) |
| { |
| if (qualifier != null && !additionalQualifiers.contains(qualifier.getJavaClass())) |
| { |
| additionalAnnotatedTypeQualifiers.put(qualifier.getJavaClass(), qualifier); |
| additionalQualifiers.add(qualifier.getJavaClass()); |
| } |
| } |
| |
| public void addAdditionalAnnotatedType(Object extension, AnnotatedType<?> annotatedType) |
| { |
| addAdditionalAnnotatedType( |
| extension, annotatedType, |
| // ensure this string is stable accross a cluster for web scopes |
| extension.getClass().getName() + annotatedType + AnnotatedElementFactory.OWB_DEFAULT_KEY); |
| } |
| |
| public <T> void addAdditionalAnnotatedType(Object extension, AnnotatedType<T> inAnnotatedType, String id) |
| { |
| if (id == null) |
| { |
| id = AnnotatedElementFactory.OWB_DEFAULT_KEY; |
| } |
| |
| AnnotatedType<T> annotatedType = new AnnotatedTypeWrapper<>(Extension.class.cast(extension), inAnnotatedType, id); |
| if (annotatedType.getAnnotation(Vetoed.class) != null) |
| { |
| // we could check package here too but would be a lost of time 99.99% of the time |
| return; |
| } |
| |
| webBeansContext.getAnnotatedElementFactory().setAnnotatedType(annotatedType, id); |
| ConcurrentMap<String, AnnotatedType<?>> annotatedTypes = additionalAnnotatedTypes.get(annotatedType.getJavaClass()); |
| if (annotatedTypes == null) |
| { |
| annotatedTypes = new ConcurrentHashMap<>(); |
| ConcurrentMap<String, AnnotatedType<?>> oldAnnotatedTypes = additionalAnnotatedTypes.putIfAbsent(annotatedType.getJavaClass(), annotatedTypes); |
| if (oldAnnotatedTypes != null) |
| { |
| annotatedTypes = oldAnnotatedTypes; |
| } |
| } |
| annotatedTypes.put(id, annotatedType); |
| } |
| |
| public void removeAdditionalAnnotatedType(AnnotatedType<?> annotatedType) |
| { |
| removeAdditionalAnnotatedType(annotatedType, AnnotatedElementFactory.OWB_DEFAULT_KEY); |
| } |
| |
| public void removeAdditionalAnnotatedType(AnnotatedType<?> annotatedType, String id) |
| { |
| ConcurrentMap<String, AnnotatedType<?>> annotatedTypes = additionalAnnotatedTypes.get(annotatedType.getJavaClass()); |
| if (annotatedTypes == null) |
| { |
| return; |
| } |
| if (annotatedType.equals(annotatedTypes.get(id))) |
| { |
| annotatedTypes.remove(id); |
| } |
| } |
| |
| public List<Class<? extends Annotation>> getAdditionalQualifiers() |
| { |
| return additionalQualifiers; |
| } |
| |
| public Map<Class<?>, AnnotatedType<? extends Annotation>> getAdditionalAnnotatedTypeQualifiers() |
| { |
| return additionalAnnotatedTypeQualifiers; |
| } |
| |
| public void addAdditionalScope(ExternalScope additionalScope) |
| { |
| if (!additionalScopes.contains(additionalScope)) |
| { |
| additionalScopes.add(additionalScope); |
| } |
| } |
| |
| public List<ExternalScope> getAdditionalScopes() |
| { |
| return additionalScopes; |
| } |
| |
| public Collection<AnnotatedType<?>> getAdditionalAnnotatedTypes() |
| { |
| Collection<AnnotatedType<?>> annotatedTypes = new ArrayList<>(); |
| for (ConcurrentMap<String,AnnotatedType<?>> types: additionalAnnotatedTypes.values()) |
| { |
| annotatedTypes.addAll(types.values()); |
| } |
| return annotatedTypes; |
| } |
| |
| public <T> AnnotatedType<T> getAdditionalAnnotatedType(Class<T> type, String id) |
| { |
| if (id == null) |
| { |
| return annotatedElementFactory.getAnnotatedType(type); |
| } |
| |
| ConcurrentMap<String, AnnotatedType<?>> annotatedTypes = additionalAnnotatedTypes.get(type); |
| if (annotatedTypes == null) |
| { |
| return null; |
| } |
| return (AnnotatedType<T>)annotatedTypes.get(id); |
| } |
| |
| public <T> String getId(Class<T> type, AnnotatedType<T> at) |
| { |
| ConcurrentMap<String, AnnotatedType<?>> additionals = additionalAnnotatedTypes.get(type); |
| if (additionals != null) |
| { |
| for (Map.Entry<String, AnnotatedType<?>> entry : additionals.entrySet()) |
| { |
| if (entry.getValue() == at) |
| { |
| return entry.getKey(); |
| } |
| } |
| } |
| return null; |
| } |
| |
| public <T> Collection<AnnotatedType<T>> getUserAnnotatedTypes(Class<T> type) |
| { |
| final ConcurrentMap<String, AnnotatedType<?>> aTypes = additionalAnnotatedTypes.get(type); |
| if (aTypes != null) |
| { |
| Collection<AnnotatedType<T>> types = new ArrayList<>(2); |
| for (AnnotatedType at : aTypes.values()) |
| { |
| types.add(at); |
| } |
| return types; |
| } |
| return null; |
| } |
| |
| public boolean hasAdditionalDefaultAnnotatedType(AnnotatedType<?> annotatedType) |
| { |
| final ConcurrentMap<String, AnnotatedType<?>> annotatedTypes = additionalAnnotatedTypes.get(annotatedType.getJavaClass()); |
| if (annotatedTypes == null) |
| { |
| return false; |
| } |
| |
| for (AnnotatedType<?> candidate : annotatedTypes.values()) |
| { |
| if (candidate == annotatedType || !(candidate instanceof AnnotatedTypeWrapper)) |
| { |
| continue; |
| } |
| |
| AnnotatedTypeWrapper<?> wrapper = (AnnotatedTypeWrapper<?>) candidate; |
| if (wrapper.getId().endsWith(AnnotatedElementFactory.OWB_DEFAULT_KEY) && |
| candidate.getAnnotations().equals(annotatedType.getAnnotations())) // strictly it is qualifiers only but faster |
| { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| public <T> Iterable<AnnotatedType<T>> getAnnotatedTypes(Class<T> type) |
| { |
| final Collection<AnnotatedType<T>> types = new ArrayList<>(2); |
| AnnotatedType<T> annotatedType = annotatedElementFactory.getAnnotatedType(type); |
| if (annotatedType != null) |
| { |
| types.add(annotatedType); |
| } |
| final Collection<AnnotatedType<T>> userAnnotatedTypes = getUserAnnotatedTypes(type); |
| if (userAnnotatedTypes != null) |
| { |
| types.addAll(userAnnotatedTypes); |
| } |
| return types; |
| } |
| |
| public void clear() |
| { |
| additionalAnnotatedTypes.clear(); |
| additionalQualifiers.clear(); |
| additionalScopes.clear(); |
| scopeAnnotations.clear(); |
| nonscopeAnnotations.clear(); |
| clearCacheProxies(); |
| singleContextMap.clear(); |
| contextMap.clear(); |
| deploymentBeans.clear(); |
| errorStack.clear(); |
| producersForJavaEeComponents.clear(); |
| passivationBeans.clear(); |
| webBeansContext.getInterceptorsManager().clear(); |
| webBeansContext.getDecoratorsManager().clear(); |
| webBeansContext.getAnnotatedElementFactory().clear(); |
| |
| injectionResolver.clearCaches(); |
| webBeansContext.getAnnotationManager().clearCaches(); |
| |
| // finally destroy all SPI services |
| webBeansContext.clear(); |
| } |
| |
| public void clearCacheProxies() |
| { |
| cacheProxies.clear(); |
| } |
| |
| public boolean isInUse() |
| { |
| return inUse; |
| } |
| |
| public boolean isAfterDeploymentValidationFired() |
| { |
| return afterDeploymentValidationFired; |
| } |
| |
| public void setAfterDeploymentValidationFired(boolean afterDeploymentValidationFired) |
| { |
| this.afterDeploymentValidationFired = afterDeploymentValidationFired; |
| } |
| |
| public void setAfterBeanDiscoveryStart() |
| { |
| this.beanDiscoveryState = LifecycleState.DISCOVERY; |
| } |
| |
| public void setAfterBeanDiscoveryDone() |
| { |
| this.beanDiscoveryState = LifecycleState.AFTER_DISCOVERY; |
| } |
| |
| public boolean isAfterBeanDiscoveryDone() |
| { |
| return beanDiscoveryState == LifecycleState.AFTER_DISCOVERY; |
| } |
| |
| public boolean isAfterBeanDiscovery() |
| { |
| return beanDiscoveryState == LifecycleState.DISCOVERY; |
| } |
| |
| private void validateAssignabilityQualifiers(Set<Annotation> qualifiers, String failureMessage) |
| { |
| for (Annotation qualifier : qualifiers) |
| { |
| if (!isQualifier(qualifier.annotationType())) |
| { |
| throw new IllegalArgumentException(failureMessage); |
| } |
| } |
| } |
| |
| private static boolean isIllegalBeanTypeForAssignability(Type beanType) |
| { |
| if (beanType instanceof Class<?>) |
| { |
| Class<?> c = (Class<?>) beanType; |
| if (c.isPrimitive()) |
| { |
| return true; |
| } |
| if (c.isArray()) |
| { |
| Class<?> ct = c.getComponentType(); |
| while (ct.isArray()) |
| { |
| ct = ct.getComponentType(); |
| } |
| return ct.isPrimitive(); |
| } |
| return false; |
| } |
| if (beanType instanceof TypeVariable<?>) |
| { |
| return true; |
| } |
| if (beanType instanceof ParameterizedType) |
| { |
| ParameterizedType parameterizedType = (ParameterizedType) beanType; |
| for (Type typeArgument : parameterizedType.getActualTypeArguments()) |
| { |
| if (typeArgument instanceof TypeVariable<?>) |
| { |
| continue; |
| } |
| if (typeArgument instanceof WildcardType || isIllegalBeanTypeForAssignability(typeArgument)) |
| { |
| return true; |
| } |
| } |
| return false; |
| } |
| if (beanType instanceof GenericArrayType) |
| { |
| return isIllegalBeanTypeForAssignability(((GenericArrayType) beanType).getGenericComponentType()); |
| } |
| return false; |
| } |
| |
| private boolean matchesRequiredBeanType(Type requiredType, Set<Type> legalBeanTypes) |
| { |
| for (Type beanType : legalBeanTypes) |
| { |
| if (GenericsUtil.satisfiesDependency(false, false, requiredType, beanType, new HashMap<>()) |
| || GenericsUtil.satisfiesDependency(false, true, requiredType, beanType, new HashMap<>())) |
| { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| private Set<Annotation> normalizeBeanQualifiersForAssignability(Set<Annotation> beanQualifiers) |
| { |
| Set<Annotation> normalized = new HashSet<>(beanQualifiers); |
| normalized.add(AnyLiteral.INSTANCE); |
| boolean onlyAnyOrNamed = true; |
| for (Annotation a : normalized) |
| { |
| Class<? extends Annotation> t = a.annotationType(); |
| if (!Any.class.equals(t) && !Named.class.equals(t)) |
| { |
| onlyAnyOrNamed = false; |
| break; |
| } |
| } |
| if (onlyAnyOrNamed) |
| { |
| normalized.add(DefaultLiteral.INSTANCE); |
| } |
| return normalized; |
| } |
| |
| private boolean hasAllQualifiers(Set<Annotation> beanQualifiers, Set<Annotation> requiredQualifiers) |
| { |
| for (Annotation required : requiredQualifiers) |
| { |
| if (!containsEquivalentQualifier(beanQualifiers, required)) |
| { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| private boolean containsEquivalentQualifier(Set<Annotation> beanQualifiers, Annotation required) |
| { |
| for (Annotation beanQ : beanQualifiers) |
| { |
| if (!required.annotationType().equals(beanQ.annotationType())) |
| { |
| continue; |
| } |
| AnnotatedType<? extends Annotation> at = additionalAnnotatedTypeQualifiers.get(beanQ.annotationType()); |
| if (at == null) |
| { |
| if (AnnotationUtil.isCdiAnnotationEqual(beanQ, required)) |
| { |
| return true; |
| } |
| } |
| else if (AnnotationUtil.isCdiAnnotationEqual(at, beanQ, required)) |
| { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| private static boolean containsUnboundTypeVariable(Type type) |
| { |
| if (type instanceof TypeVariable<?>) |
| { |
| return true; |
| } |
| if (type instanceof ParameterizedType) |
| { |
| for (Type arg : ((ParameterizedType) type).getActualTypeArguments()) |
| { |
| if (containsUnboundTypeVariable(arg)) |
| { |
| return true; |
| } |
| } |
| } |
| else if (type instanceof GenericArrayType) |
| { |
| return containsUnboundTypeVariable(((GenericArrayType) type).getGenericComponentType()); |
| } |
| else if (type instanceof WildcardType) |
| { |
| WildcardType w = (WildcardType) type; |
| for (Type b : w.getUpperBounds()) |
| { |
| if (containsUnboundTypeVariable(b)) |
| { |
| return true; |
| } |
| } |
| for (Type b : w.getLowerBounds()) |
| { |
| if (containsUnboundTypeVariable(b)) |
| { |
| return true; |
| } |
| } |
| } |
| return false; |
| } |
| |
| private static boolean matchesObservedEventType(Type observedEventType, Set<Type> eventTypeClosure) |
| { |
| for (Type eventType : eventTypeClosure) |
| { |
| if (eventType instanceof ParameterizedType && observedEventType instanceof Class<?>) |
| { |
| if (GenericsUtil.isAssignableFrom(true, false, observedEventType, |
| ((ParameterizedType) eventType).getRawType(), new HashMap<>())) |
| { |
| return true; |
| } |
| } |
| if (GenericsUtil.isAssignableFrom(true, false, observedEventType, eventType, new HashMap<>())) |
| { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| private enum LifecycleState |
| { |
| BEFORE_DISCOVERY, DISCOVERY, AFTER_DISCOVERY |
| } |
| } |