blob: f2368fddaa6131d8ce017094ada9f55f77288bfa [file] [log] [blame]
/*
* 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.openejb.cdi;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
import java.util.Stack;
import javax.enterprise.inject.Model;
import javax.enterprise.inject.Specializes;
import javax.enterprise.inject.spi.AnnotatedType;
import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.BeanManager;
import javax.enterprise.inject.spi.Decorator;
import javax.enterprise.inject.spi.InjectionPoint;
import javax.interceptor.Interceptor;
import org.apache.webbeans.annotation.AnnotationManager;
import org.apache.webbeans.component.AbstractInjectionTargetBean;
import org.apache.webbeans.component.AbstractProducerBean;
import org.apache.webbeans.component.EnterpriseBeanMarker;
import org.apache.webbeans.component.InjectionTargetBean;
import org.apache.webbeans.component.InjectionTargetWrapper;
import org.apache.webbeans.component.InterceptedMarker;
import org.apache.webbeans.component.ManagedBean;
import org.apache.webbeans.component.NewBean;
import org.apache.webbeans.component.OwbBean;
import org.apache.webbeans.component.WebBeansType;
import org.apache.webbeans.component.creation.BeanCreator.MetaDataProvider;
import org.apache.webbeans.component.creation.ManagedBeanCreatorImpl;
import org.apache.webbeans.config.DefinitionUtil;
import org.apache.webbeans.config.OWBLogConst;
import org.apache.webbeans.config.WebBeansContext;
import org.apache.webbeans.container.BeanManagerImpl;
import org.apache.webbeans.container.InjectionResolver;
import org.apache.webbeans.decorator.WebBeansDecorator;
import org.apache.webbeans.deployment.StereoTypeModel;
import org.apache.webbeans.exception.WebBeansConfigurationException;
import org.apache.webbeans.exception.WebBeansDeploymentException;
import org.apache.webbeans.exception.inject.InconsistentSpecializationException;
import org.apache.webbeans.intercept.webbeans.WebBeansInterceptor;
import org.apache.webbeans.logger.WebBeansLogger;
import org.apache.webbeans.portable.events.ProcessAnnotatedTypeImpl;
import org.apache.webbeans.portable.events.ProcessInjectionTargetImpl;
import org.apache.webbeans.portable.events.discovery.AfterBeanDiscoveryImpl;
import org.apache.webbeans.portable.events.discovery.AfterDeploymentValidationImpl;
import org.apache.webbeans.portable.events.discovery.BeforeBeanDiscoveryImpl;
import org.apache.webbeans.spi.ScannerService;
import org.apache.webbeans.spi.plugins.OpenWebBeansJavaEEPlugin;
import org.apache.webbeans.spi.plugins.OpenWebBeansWebPlugin;
import org.apache.webbeans.util.AnnotationUtil;
import org.apache.webbeans.util.ClassUtil;
import org.apache.webbeans.util.WebBeansUtil;
import org.apache.webbeans.xml.WebBeansXMLConfigurator;
/**
* @version $Rev$ $Date$
*/
/**
* 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 WebBeansLogger logger = WebBeansLogger.getLogger(BeansDeployer.class);
/**XML Configurator*/
protected final WebBeansXMLConfigurator xmlConfigurator;
private final WebBeansContext webBeansContext;
public BeansDeployer(WebBeansXMLConfigurator xmlConfigurator, WebBeansContext webBeansContext) {
this.xmlConfigurator = xmlConfigurator;
this.webBeansContext = webBeansContext;
}
/**
* Configure Default Beans.
*/
void configureDefaultBeans()
{
BeanManagerImpl beanManager = webBeansContext.getBeanManagerImpl();
WebBeansUtil webBeansUtil = webBeansContext.getWebBeansUtil();
// Register Manager built-in component
beanManager.addInternalBean(webBeansUtil.getManagerBean());
// Register Conversation built-in component
beanManager.addBean(webBeansUtil.getConversationBean());
// Register InjectionPoint bean
beanManager.addBean(webBeansUtil.getInjectionPointBean());
//Register Instance Bean
beanManager.addBean(webBeansUtil.getInstanceBean());
//Register Event Bean
beanManager.addBean(webBeansUtil.getEventBean());
//Register Provider Beans
addDefaultBean(beanManager, "org.apache.webbeans.ee.common.beans.PrincipalBean");
addDefaultBean(beanManager, "org.apache.webbeans.ee.beans.ValidatorBean");
addDefaultBean(beanManager, "org.apache.webbeans.ee.beans.ValidatorFactoryBean");
addDefaultBean(beanManager, "org.apache.webbeans.ee.beans.UserTransactionBean");
}
private void addDefaultBean(BeanManagerImpl manager,String className)
{
Bean<?> bean = null;
Class<?> beanClass = ClassUtil.getClassFromName(className);
if (beanClass != null) {
bean = (Bean) ClassUtil.newInstance(webBeansContext, beanClass);
}
if (bean != null) {
manager.addBean(bean);
}
}
/**
* Fires event before bean discovery.
*/
void fireBeforeBeanDiscoveryEvent()
{
BeanManager manager = webBeansContext.getBeanManagerImpl();
manager.fireEvent(new BeforeBeanDiscoveryImpl(webBeansContext),new Annotation[0]);
}
/**
* Fires event after bean discovery.
*/
void fireAfterBeanDiscoveryEvent()
{
BeanManagerImpl manager = webBeansContext.getBeanManagerImpl();
manager.fireEvent(new AfterBeanDiscoveryImpl(webBeansContext),new Annotation[0]);
webBeansContext.getWebBeansUtil().inspectErrorStack("There are errors that are added by AfterBeanDiscovery event observers. Look at logs for further details");
}
/**
* Fires event after deployment valdiation.
*/
void fireAfterDeploymentValidationEvent()
{
BeanManagerImpl manager = webBeansContext.getBeanManagerImpl();
manager.fireEvent(new AfterDeploymentValidationImpl(manager),new Annotation[0]);
webBeansContext.getWebBeansUtil().inspectErrorStack("There are errors that are added by AfterDeploymentValidation event observers. Look at logs for further details");
}
/**
* Validate all injection points.
*/
void validateInjectionPoints()
{
logger.debug("Validation of injection points has started.");
webBeansContext.getDecoratorsManager().validateDecoratorClasses();
webBeansContext.getInterceptorsManager().validateInterceptorClasses();
BeanManagerImpl manager = webBeansContext.getBeanManagerImpl();
Set<Bean<?>> beans = new HashSet<Bean<?>>();
//Adding decorators to validate
Set<Decorator<?>> decorators = manager.getDecorators();
for (Decorator decorator : decorators) {
WebBeansDecorator wbDec = (WebBeansDecorator) decorator;
beans.add(wbDec);
}
logger.debug("Validation of the decorator's injection points has started.");
//Validate Decorators
validate(beans);
beans.clear();
//Adding interceptors to validate
for (javax.enterprise.inject.spi.Interceptor<?> interceptor : manager.getInterceptors()) {
WebBeansInterceptor wbInt = (WebBeansInterceptor) interceptor;
beans.add(wbInt);
}
logger.debug("Validation of the interceptor's injection points has started.");
//Validate Interceptors
validate(beans);
beans.clear();
beans = manager.getBeans();
//Validate Others
validate(beans);
logger.info(OWBLogConst.INFO_0003);
}
/**
* Validates beans.
*
* @param beans deployed beans
*/
private void validate(Set<Bean<?>> beans)
{
BeanManagerImpl manager = webBeansContext.getBeanManagerImpl();
if (beans != null && beans.size() > 0) {
Stack<String> beanNames = new Stack<String>();
for (Bean<?> bean : beans) {
String beanName = bean.getName();
if (beanName != null) {
beanNames.push(beanName);
}
if (bean instanceof InjectionTargetBean) {
//Decorators not applied to interceptors/decorators/@NewBean
if (!(bean instanceof Decorator) &&
!(bean instanceof javax.enterprise.inject.spi.Interceptor) &&
!(bean instanceof NewBean)) {
new DefinitionUtil(webBeansContext).defineDecoratorStack((AbstractInjectionTargetBean<Object>) bean);
}
//If intercepted marker
if (bean instanceof InterceptedMarker) {
new DefinitionUtil(webBeansContext).defineBeanInterceptorStack((AbstractInjectionTargetBean<Object>) bean);
}
}
//Check passivation scope
checkPassivationScope(bean);
//Bean injection points
Set<InjectionPoint> injectionPoints = bean.getInjectionPoints();
//Check injection points
if (injectionPoints != null) {
for (InjectionPoint injectionPoint : injectionPoints) {
if (!injectionPoint.isDelegate()) {
manager.validate(injectionPoint);
} else {
if (!bean.getBeanClass().isAnnotationPresent(javax.decorator.Decorator.class)
&& !webBeansContext.getBeanManagerImpl().containsCustomDecoratorClass(bean.getBeanClass())) {
throw new WebBeansConfigurationException(
"Delegate injection points can not defined by beans that are not decorator. Injection point : "
+ injectionPoint);
}
}
}
}
}
//Validate Bean names
validateBeanNames(beanNames);
//Clear Names
beanNames.clear();
}
}
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) {
beans = resolver.findByAlternatives(beans);
if (beans.size() > 1) {
throw new WebBeansConfigurationException("There are two different beans with name : " + beanName + " in the deployment archieve");
}
}
} else {
if (part != null) {
if (part.equals(other)) {
throw new WebBeansConfigurationException("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);
}
}
}
}
}
}
}
/**
* Discovers and deploys classes from XML.
*
* NOTE : Currently XML file is just used for configuring.
*
* @param scanner discovery scanner
* @throws WebBeansDeploymentException if exception
*/
protected void deployFromXML(ScannerService scanner) throws WebBeansDeploymentException
{
}
/**
* Checks specialization.
* @param scanner scanner instance
*/
protected void checkSpecializations(ScannerService scanner)
{
logger.debug("Checking Specialization constraints has started.");
try {
Set<Class<?>> beanClasses = scanner.getBeanClasses();
if (beanClasses != null && beanClasses.size() > 0) {
//superClassList is used to handle the case: Car, CarToyota, Bus, SchoolBus, CarFord
//for which case, the owb should throw exception that both CarToyota and CarFord are
//specialize Car.
Class<?> superClass;
ArrayList<Class<?>> superClassList = new ArrayList<Class<?>>();
ArrayList<Class<?>> specialClassList = new ArrayList<Class<?>>();
for (Class<?> specialClass : beanClasses) {
if (AnnotationUtil.hasClassAnnotation(specialClass, Specializes.class)) {
superClass = specialClass.getSuperclass();
if (superClass.equals(Object.class)) {
throw new WebBeansConfigurationException(logger.getTokenString(OWBLogConst.EXCEPT_0003) + specialClass.getName()
+ logger.getTokenString(OWBLogConst.EXCEPT_0004));
}
if (superClassList.contains(superClass)) {
throw new InconsistentSpecializationException(logger.getTokenString(OWBLogConst.EXCEPT_0005) + superClass.getName());
}
superClassList.add(superClass);
specialClassList.add(specialClass);
}
}
webBeansContext.getWebBeansUtil().configureSpecializations(specialClassList);
}
//configure specialized producer beans.
webBeansContext.getWebBeansUtil().configureProducerMethodSpecializations();
} catch (Exception e) {
throw new WebBeansDeploymentException(e);
}
logger.debug("Checking Specialization constraints has ended.");
}
/**
* Check passivations.
*/
protected void checkPassivationScope(Bean<?> beanObj)
{
boolean validate = false;
if (EnterpriseBeanMarker.class.isAssignableFrom(beanObj.getClass())) {
EnterpriseBeanMarker marker = (EnterpriseBeanMarker) beanObj;
if (marker.isPassivationCapable()) {
validate = true;
}
} else if (webBeansContext.getBeanManagerImpl().isPassivatingScope(beanObj.getScope())) {
if (WebBeansUtil.isPassivationCapable(beanObj) == null) {
if (!(beanObj instanceof AbstractProducerBean)) {
throw new WebBeansConfigurationException("Passivation scoped defined bean must be passivation capable, " +
"but bean : " + beanObj.toString() + " is not passivation capable");
} else {
validate = true;
}
}
validate = true;
}
if (validate) {
((OwbBean<?>) beanObj).validatePassivationDependencies();
}
}
/**
* Check steretypes.
* @param scanner scanner instance
*/
protected void checkStereoTypes(ScannerService scanner)
{
logger.debug("Checking StereoType constraints has started.");
addDefaultStereoTypes();
final AnnotationManager annotationManager = webBeansContext.getAnnotationManager();
Set<Class<?>> beanClasses = scanner.getBeanClasses();
if (beanClasses != null && beanClasses.size() > 0)
{
for(Class<?> beanClass : beanClasses)
{
if(beanClass.isAnnotation())
{
Class<? extends Annotation> stereoClass = (Class<? extends Annotation>) beanClass;
if (annotationManager.isStereoTypeAnnotation(stereoClass))
{
annotationManager.checkStereoTypeClass(stereoClass, stereoClass.getDeclaredAnnotations());
StereoTypeModel model = new StereoTypeModel(webBeansContext, stereoClass);
webBeansContext.getStereoTypeManager().addStereoTypeModel(model);
}
}
}
}
logger.debug("Checking StereoType constraints has ended.");
}
/**
* Adds default stereotypes.
*/
protected void addDefaultStereoTypes()
{
StereoTypeModel model = new StereoTypeModel(webBeansContext, Model.class);
webBeansContext.getStereoTypeManager().addStereoTypeModel(model);
model = new StereoTypeModel(webBeansContext, javax.decorator.Decorator.class);
webBeansContext.getStereoTypeManager().addStereoTypeModel(model);
model = new StereoTypeModel(webBeansContext, Interceptor.class);
webBeansContext.getStereoTypeManager().addStereoTypeModel(model);
}
/**
* Defines and configures managed bean.
* @param <T> type info
* @param clazz bean class
* @return true if given class is configured as a managed bean
*/
protected <T> boolean defineManagedBean(Class<T> clazz, ProcessAnnotatedTypeImpl<T> processAnnotatedEvent)
{
//Bean manager
BeanManagerImpl manager = webBeansContext.getBeanManagerImpl();
//Create an annotated type
AnnotatedType<T> annotatedType = processAnnotatedEvent.getAnnotatedType();
//Fires ProcessInjectionTarget event for Java EE components instances
//That supports injections but not managed beans
ProcessInjectionTargetImpl<T> processInjectionTargetEvent = null;
if (webBeansContext.getWebBeansUtil().supportsJavaEeComponentInjections(clazz)) {
//Fires ProcessInjectionTarget
processInjectionTargetEvent = webBeansContext.getWebBeansUtil().fireProcessInjectionTargetEventForJavaEeComponents(clazz);
webBeansContext.getWebBeansUtil().inspectErrorStack("There are errors that are added by ProcessInjectionTarget event observers. Look at logs for further details");
//Sets custom InjectionTarget instance
if (processInjectionTargetEvent.isSet()) {
//Adding injection target
manager.putInjectionTargetWrapperForJavaEeComponents(clazz, new InjectionTargetWrapper<T>(processInjectionTargetEvent.getInjectionTarget()));
}
//Checks that not contains @Inject InjectionPoint
webBeansContext.getAnnotationManager().checkInjectionPointForInjectInjectionPoint(clazz);
}
//Check for whether this class is candidate for Managed Bean
if (webBeansContext.getManagedBeanConfigurator().isManagedBean(clazz)) {
//Check conditions
webBeansContext.getManagedBeanConfigurator().checkManagedBeanCondition(clazz);
//Temporary managed bean instance creationa
ManagedBean<T> managedBean = new ManagedBean<T>(clazz, WebBeansType.MANAGED, webBeansContext);
ManagedBeanCreatorImpl<T> managedBeanCreator = new ManagedBeanCreatorImpl<T>(managedBean);
boolean annotationTypeSet = false;
if (processAnnotatedEvent.isModifiedAnnotatedType()) {
annotationTypeSet = true;
managedBean.setAnnotatedType(annotatedType);
annotatedType = processAnnotatedEvent.getAnnotatedType();
managedBeanCreator.setAnnotatedType(annotatedType);
managedBeanCreator.setMetaDataProvider(MetaDataProvider.THIRDPARTY);
}
//If ProcessInjectionTargetEvent is not set, set it
if (processInjectionTargetEvent == null) {
processInjectionTargetEvent = webBeansContext.getWebBeansUtil().fireProcessInjectionTargetEvent(managedBean);
}
//Decorator
if (WebBeansUtil.isAnnotatedTypeDecorator(annotatedType)) {
if (logger.wblWillLogDebug()) {
logger.debug("Found Managed Bean Decorator with class name : [{0}]", annotatedType.getJavaClass().getName());
}
if (annotationTypeSet) {
webBeansContext.getWebBeansUtil().defineDecorator(annotatedType);
} else {
webBeansContext.getWebBeansUtil().defineDecorator(managedBeanCreator, processInjectionTargetEvent);
}
}
//Interceptor
else if (WebBeansUtil.isAnnotatedTypeInterceptor(annotatedType)) {
if (logger.wblWillLogDebug()) {
logger.debug("Found Managed Bean Interceptor with class name : [{0}]", annotatedType.getJavaClass().getName());
}
if (annotationTypeSet) {
webBeansContext.getWebBeansUtil().defineInterceptor(annotatedType);
} else {
webBeansContext.getWebBeansUtil().defineInterceptor(managedBeanCreator, processInjectionTargetEvent);
}
} else {
if (webBeansContext.getBeanManagerImpl().containsCustomDecoratorClass(annotatedType.getJavaClass()) ||
webBeansContext.getBeanManagerImpl().containsCustomInterceptorClass(annotatedType.getJavaClass())) {
return false;
}
if (logger.wblWillLogDebug()) {
logger.debug("Found Managed Bean with class name : [{0}]", annotatedType.getJavaClass().getName());
}
webBeansContext.getWebBeansUtil().defineManagedBean(managedBeanCreator, processInjectionTargetEvent, false);
}
return true;
}
//Not a managed bean
else {
return false;
}
}
}