org.apache.webbeans.container.BeanManagerImpl Maven / Gradle / Ivy
/*
* 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.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.el.ELResolver;
import javax.el.ExpressionFactory;
import javax.enterprise.context.ContextNotActiveException;
import javax.enterprise.context.Dependent;
import javax.enterprise.context.NormalScope;
import javax.enterprise.context.spi.AlterableContext;
import javax.enterprise.context.spi.Context;
import javax.enterprise.context.spi.Contextual;
import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.inject.Default;
import javax.enterprise.inject.InjectionException;
import javax.enterprise.inject.Stereotype;
import javax.enterprise.inject.Vetoed;
import javax.enterprise.inject.spi.*;
import javax.inject.Scope;
import javax.interceptor.InterceptorBinding;
import javax.naming.NamingException;
import javax.naming.Reference;
import javax.naming.Referenceable;
import javax.naming.StringRefAddr;
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.NewBean;
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.EventMetadataImpl;
import org.apache.webbeans.event.NotificationManager;
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.
*
*
* It is written as thread-safe.
*
*
* @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, List> contextMap = new HashMap, List>();
/**
* 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, Context> singleContextMap = new HashMap, Context>();
/**Deployment archive beans*/
private Set> deploymentBeans = new HashSet>();
/**Normal scoped cache proxies*/
private Map, Object> cacheProxies = new ConcurrentHashMap, Object>();
/**Event notification manager instance*/
private NotificationManager notificationManager = null;
/**Injection resolver instance*/
private InjectionResolver injectionResolver = null;
/**
* This list contains additional qualifiers which got set via the
* {@link javax.enterprise.inject.spi.BeforeBeanDiscovery#addQualifier(Class)}
* event function.
*/
private List> additionalQualifiers = new ArrayList>();
private Map, AnnotatedType extends Annotation>> additionalAnnotatedTypeQualifiers = new HashMap, AnnotatedType extends Annotation>>();
/**
* This list contains additional scopes which got set via the
* {@link javax.enterprise.inject.spi.BeforeBeanDiscovery#addScope(Class, boolean, boolean)} event function.
*/
private List additionalScopes = new ArrayList();
/** quick detection if an annotation is a scope-annotation */
private Set> scopeAnnotations = new HashSet>();
/** quick detection if an annotation is NOT a scope-annotation */
private Set> nonscopeAnnotations = new HashSet>();
private ConcurrentMap, ConcurrentMap>> additionalAnnotatedTypes = new ConcurrentHashMap, ConcurrentMap>>();
private ErrorStack errorStack = new ErrorStack();
/**
* This map stores all beans along with their unique {@link javax.enterprise.inject.spi.PassivationCapable} id.
* This is used as a reference for serialization.
*/
private ConcurrentMap> passivationBeans = new ConcurrentHashMap>();
/**InjectionTargets for Java EE component instances that supports injections*/
private Map, Producer>> producersForJavaEeComponents =
new ConcurrentHashMap, Producer>>();
private AnnotatedElementFactory annotatedElementFactory;
private final WebBeansContext webBeansContext;
/**
* This flag will get set to true
if a custom bean
* (all non-internal beans like {@link org.apache.webbeans.component.BeanManagerBean;} etc)
* gets set.
*/
private boolean inUse = false;
/**
* This flag will get set to handle lifecyle around
* {@link javax.enterprise.inject.spi.AfterBeanDiscovery}
*/
private LifecycleState beanDiscoveryState = LifecycleState.BEFORE_DISCOVERY;
/**
* This flag will get set to {@code true} after the
* {@link javax.enterprise.inject.spi.AfterDeploymentValidation} gets fired
*/
private boolean afterDeploymentValidationFired = false;
/**
* 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 static Map, Boolean> isScopeTypeNormalCache =
new ConcurrentHashMap, Boolean>();
/**
* Map to be able to lookup always 3rd party beans when user does lookups with custom beans.
*/
private Map, 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);
notificationManager = new NotificationManager(webBeansContext);
annotatedElementFactory = webBeansContext.getAnnotatedElementFactory();
}
public WebBeansContext getWebBeansContext()
{
return webBeansContext;
}
public void putProducerForJavaEeComponent(Class javaEeComponentClass, Producer wrapper)
{
Asserts.assertNotNull(javaEeComponentClass);
Asserts.assertNotNull(wrapper);
producersForJavaEeComponents.put(javaEeComponentClass, wrapper);
}
public Producer getProducerForJavaEeComponent(Class javaEeComponentClass)
{
Asserts.assertNotNull(javaEeComponentClass);
return (Producer) producersForJavaEeComponents.get(javaEeComponentClass);
}
public ErrorStack getErrorStack()
{
return errorStack;
}
/**
* Return manager notification manager.
*
* @return notification manager
*/
public NotificationManager getNotificationManager()
{
return notificationManager;
}
/**
* 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 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;
}
/**
* 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 BeanManager addInternalBean(Bean 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);
}
}
}
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;
}
/**
* {@inheritDoc}
*/
@Override
public void fireEvent(Object event, Annotation... bindings)
{
fireEvent(event, false, bindings);
}
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 (notificationManager.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)
{
notificationManager.fireEvent(event, metadata, isLifecycleEvent);
}
public Set> getComponents()
{
return deploymentBeans;
}
/**
* {@inheritDoc}
*/
@Override
public List> resolveDecorators(final Set types, final Annotation... bindingTypes)
{
webBeansContext.getAnnotationManager().checkDecoratorResolverParams(types, bindingTypes);
return unsafeResolveDecorators(types, bindingTypes);
}
public List> unsafeResolveDecorators(final Set types, final Annotation[] bindingTypes)
{
webBeansContext.getAnnotationManager().checkQualifiersParams(types, bindingTypes); // checkDecoratorResolverParams is too restrictive for repeatable bindings
final Set> intsSet = webBeansContext.getDecoratorsManager().findDeployedWebBeansDecorator(types, bindingTypes);
final List> decoratorList = new ArrayList>(intsSet);
Collections.sort(decoratorList, new DecoratorComparator(webBeansContext));
return decoratorList;
}
/**
* {@inheritDoc}
*/
@Override
public List> resolveInterceptors(InterceptionType type, Annotation... interceptorBindings)
{
webBeansContext.getAnnotationManager().checkInterceptorResolverParams(interceptorBindings);
return webBeansContext.getInterceptorsManager().resolveInterceptors(type, interceptorBindings);
}
public Set> getBeans()
{
return deploymentBeans;
}
private void addContext(Class extends Annotation> scopeType, javax.enterprise.context.spi.Context context)
{
Asserts.assertNotNull(scopeType, "scopeType");
Asserts.assertNotNull(context, "context");
List 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 AnnotatedType createAnnotatedType(final Class type)
{
return annotatedElementFactory.newAnnotatedType(type);
}
/**
* {@inheritDoc}
*/
@Override
public CreationalContextImpl createCreationalContext(Contextual contextual)
{
if (contextual instanceof SerializableBean)
{
contextual = ((SerializableBean)contextual).getBean();
}
return webBeansContext.getCreationalContextFactory().getCreationalContext(contextual);
}
/**
* {@inheritDoc}
*/
@Override
public Set> 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> 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 = null;
//Find the injection point Bean
Bean
© 2015 - 2025 Weber Informatics LLC | Privacy Policy