All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jboss.weld.bean.ManagedBean Maven / Gradle / Ivy

There is a newer version: 3.0.0.Alpha1
Show newest version
/*
 * JBoss, Home of Professional Open Source
 * Copyright 2008, Red Hat, Inc., and individual contributors
 * by the @authors tag. See the copyright.txt in the distribution for a
 * full listing of individual contributors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.jboss.weld.bean;

import static org.jboss.weld.logging.Category.BEAN;
import static org.jboss.weld.logging.LoggerFactory.loggerFactory;
import static org.jboss.weld.logging.messages.BeanMessage.BEAN_MUST_BE_DEPENDENT;
import static org.jboss.weld.logging.messages.BeanMessage.DELEGATE_INJECTION_POINT_NOT_FOUND;
import static org.jboss.weld.logging.messages.BeanMessage.ERROR_DESTROYING;
import static org.jboss.weld.logging.messages.BeanMessage.FINAL_BEAN_CLASS_WITH_DECORATORS_NOT_ALLOWED;
import static org.jboss.weld.logging.messages.BeanMessage.FINAL_BEAN_CLASS_WITH_INTERCEPTORS_NOT_ALLOWED;
import static org.jboss.weld.logging.messages.BeanMessage.NON_CONTAINER_DECORATOR;
import static org.jboss.weld.logging.messages.BeanMessage.PASSIVATING_BEAN_HAS_NON_PASSIVATION_CAPABLE_DECORATOR;
import static org.jboss.weld.logging.messages.BeanMessage.PASSIVATING_BEAN_HAS_NON_PASSIVATION_CAPABLE_INTERCEPTOR;
import static org.jboss.weld.logging.messages.BeanMessage.PASSIVATING_BEAN_NEEDS_SERIALIZABLE_IMPL;
import static org.jboss.weld.logging.messages.BeanMessage.PUBLIC_FIELD_ON_NORMAL_SCOPED_BEAN_NOT_ALLOWED;
import static org.jboss.weld.logging.messages.BeanMessage.SIMPLE_BEAN_AS_NON_STATIC_INNER_CLASS_NOT_ALLOWED;
import static org.jboss.weld.logging.messages.BeanMessage.SPECIALIZING_BEAN_MUST_EXTEND_A_BEAN;
import static org.jboss.weld.util.reflection.Reflections.cast;

import java.util.Set;

import javassist.util.proxy.MethodHandler;
import javassist.util.proxy.ProxyObject;

import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.Decorator;
import javax.enterprise.inject.spi.InjectionPoint;
import javax.enterprise.inject.spi.InjectionTarget;
import javax.enterprise.inject.spi.PassivationCapable;

import org.jboss.weld.Container;
import org.jboss.weld.bean.interceptor.WeldInterceptorClassMetadata;
import org.jboss.weld.bean.interceptor.WeldInterceptorInstantiator;
import org.jboss.weld.bean.proxy.CombinedInterceptorAndDecoratorStackMethodHandler;
import org.jboss.weld.bootstrap.BeanDeployerEnvironment;
import org.jboss.weld.bootstrap.api.ServiceRegistry;
import org.jboss.weld.context.CreationalContextImpl;
import org.jboss.weld.exceptions.DefinitionException;
import org.jboss.weld.exceptions.DeploymentException;
import org.jboss.weld.exceptions.IllegalStateException;
import org.jboss.weld.injection.CurrentInjectionPoint;
import org.jboss.weld.injection.InjectionContextImpl;
import org.jboss.weld.injection.ProxyClassConstructorInjectionPointWrapper;
import org.jboss.weld.injection.WeldInjectionPoint;
import org.jboss.weld.interceptor.proxy.DefaultInvocationContextFactory;
import org.jboss.weld.interceptor.proxy.InterceptorProxyCreatorImpl;
import org.jboss.weld.interceptor.spi.metadata.InterceptorMetadata;
import org.jboss.weld.interceptor.util.InterceptionUtils;
import org.jboss.weld.introspector.WeldClass;
import org.jboss.weld.introspector.WeldField;
import org.jboss.weld.introspector.WeldMethod;
import org.jboss.weld.manager.BeanManagerImpl;
import org.jboss.weld.metadata.cache.MetaAnnotationStore;
import org.jboss.weld.util.AnnotatedTypes;
import org.jboss.weld.util.Beans;
import org.jboss.weld.util.BeansClosure;
import org.jboss.weld.util.Proxies;
import org.jboss.weld.util.reflection.Formats;
import org.jboss.weld.util.reflection.Reflections;
import org.slf4j.cal10n.LocLogger;
import org.slf4j.ext.XLogger;
import org.slf4j.ext.XLogger.Level;

/**
 * Represents a simple bean
 *
 * @param  The type (class) of the bean
 * @author Pete Muir
 * @author Marius Bogoevici
 * @author Ales Justin
 * @author Marko Luksa
 */
public class ManagedBean extends AbstractClassBean {

    private abstract static class FixInjectionPoint {

        private final AbstractClassBean bean;

        private InjectionPoint originalInjectionPoint;

        private FixInjectionPoint(AbstractClassBean bean) {
            this.bean = bean;
        }

        protected abstract T work();

        private void setup() {
            if (bean.hasDecorators()) {
                Decorator decorator = bean.getDecorators().get(bean.getDecorators().size() - 1);
                InjectionPoint outerDelegateInjectionPoint = Beans.getDelegateInjectionPoint(decorator);
                if (outerDelegateInjectionPoint == null) {
                    throw new IllegalStateException(DELEGATE_INJECTION_POINT_NOT_FOUND, decorator);
                }
                CurrentInjectionPoint currentInjectionPoint = Container.instance().services().get(CurrentInjectionPoint.class);
                if (currentInjectionPoint.peek() != null) {
                    this.originalInjectionPoint = currentInjectionPoint.pop();
                    currentInjectionPoint.push(outerDelegateInjectionPoint);
                } else {
                    currentInjectionPoint.push(outerDelegateInjectionPoint);
                }
            }
        }

        public InjectionPoint getOriginalInjectionPoint() {
            return originalInjectionPoint;
        }

        private void cleanup() {
            if (bean.hasDecorators()) {
                final CurrentInjectionPoint currentInjectionPoint = Container.instance().services().get(CurrentInjectionPoint.class);
                currentInjectionPoint.pop();
                currentInjectionPoint.push(originalInjectionPoint);
            }
        }

        public T run() {
            try {
                setup();
                return work();
            } finally {
                cleanup();
            }

        }

    }

    private static class ManagedBeanInjectionTarget implements InjectionTarget {

        private final ManagedBean bean;

        private ManagedBeanInjectionTarget(ManagedBean bean) {
            this.bean = bean;
        }

        protected ManagedBean getBean() {
            return bean;
        }

        public void inject(final T instance, final CreationalContext ctx) {
            new FixInjectionPoint(bean) {

                @Override
                protected T work() {
                    new InjectionContextImpl(bean.getBeanManager(), ManagedBeanInjectionTarget.this, getBean().getWeldAnnotated(), instance) {

                        public void proceed() {
                            Beans.injectEEFields(instance, bean.getBeanManager(), bean.ejbInjectionPoints, bean.persistenceContextInjectionPoints, bean.persistenceUnitInjectionPoints, bean.resourceInjectionPoints);
                            Beans.injectFieldsAndInitializers(instance, ctx, bean.getBeanManager(), bean.getInjectableFields(), bean.getInitializerMethods());
                        }

                    }.run();
                    return null;
                }
            }.run();
        }

        public void postConstruct(T instance) {
            if (bean.hasInterceptors()) {
                InterceptionUtils.executePostConstruct(instance);
            } else {
                bean.defaultPostConstruct(instance);
            }
        }

        public void preDestroy(T instance) {
            if (bean.hasInterceptors()) {
                InterceptionUtils.executePredestroy(instance);
            } else {
                bean.defaultPreDestroy(instance);
            }
        }

        public void dispose(T instance) {
            // No-op
        }

        public Set getInjectionPoints() {
            return cast(bean.getWeldInjectionPoints());
        }

        public T produce(final CreationalContext ctx) {
            T instance;
            if (!bean.hasDecorators()) {
                // This should be safe, but needs verification PLM
                // Without this, the chaining of decorators will fail as the
                // incomplete instance will be resolved
                instance = bean.createInstance(ctx);
                // Do not keep dependent instances as incomplete
                if (bean.isDependent() == false) {
                    ctx.push(instance);
                }
            } else {
                instance = new FixInjectionPoint(bean) {
                    @Override
                    protected T work() {
                        // for decorated beans, creation should use the fixed injection point
                        // thus ensuring that the innermost decorator is provided as InjectionPoint
                        T undecoratedInstance = bean.createInstance(ctx);
                        return bean.applyDecorators(undecoratedInstance, ctx, getOriginalInjectionPoint());
                    }

                }.run();
            }
            if (bean.hasInterceptors()) {
                return bean.applyInterceptors(instance, ctx);
            } else {
                return instance;
            }
        }


    }

    // Logger
    private static final LocLogger log = loggerFactory().getLogger(BEAN);
    private static final XLogger xLog = loggerFactory().getXLogger(BEAN);

    // The Java EE style injection points
    private Set> ejbInjectionPoints;
    private Set> persistenceContextInjectionPoints;
    private Set> persistenceUnitInjectionPoints;
    private Set> resourceInjectionPoints;

    private ManagedBean specializedBean;

    private boolean passivationCapableBean;
    private boolean passivationCapableDependency;
    private final boolean proxiable;

    /**
     * Creates a simple, annotation defined Web Bean
     *
     * @param          The type
     * @param clazz       The class
     * @param beanManager the current manager
     * @return A Web Bean
     */
    public static  ManagedBean of(WeldClass clazz, BeanManagerImpl beanManager, ServiceRegistry services) {
        if (clazz.isDiscovered()) {
            return new ManagedBean(clazz, createSimpleId(ManagedBean.class.getSimpleName(), clazz), beanManager, services);
        } else {
            return new ManagedBean(clazz, createId(ManagedBean.class.getSimpleName(), clazz), beanManager, services);
        }
    }

    protected static String createSimpleId(String beanType, WeldClass clazz) {
        return new StringBuilder().append(beanType).append(BEAN_ID_SEPARATOR).append(clazz.getBaseType()).toString();
    }

    /**
     * create a more complete id for types that have been added through the SPI
     * to prevent duplicate id's
     */
    protected static String createId(String beanType, WeldClass clazz) {
        return new StringBuilder().append(beanType).append(BEAN_ID_SEPARATOR).append(AnnotatedTypes.createTypeId(clazz)).toString();
    }

    /**
     * Constructor
     *
     * @param type        The type of the bean
     * @param beanManager The Bean manager
     */
    protected ManagedBean(WeldClass type, String idSuffix, BeanManagerImpl beanManager, ServiceRegistry services) {
        super(type, idSuffix, beanManager, services);
        initType();
        initTypes();
        initQualifiers();
        initConstructor();
        this.proxiable = Proxies.isTypesProxyable(getTypes());
    }

    /**
     * Creates an instance of the bean
     *
     * @return The instance
     */
    public T create(CreationalContext creationalContext) {
        T instance = getInjectionTarget().produce(creationalContext);
        getInjectionTarget().inject(instance, creationalContext);
        getInjectionTarget().postConstruct(instance);
        return instance;
    }

    /**
     * Destroys an instance of the bean
     *
     * @param instance The instance
     */
    public void destroy(T instance, CreationalContext creationalContext) {
        try {
            getInjectionTarget().preDestroy(instance);
            // WELD-1010 hack?
            if (creationalContext instanceof CreationalContextImpl) {
                ((CreationalContextImpl) creationalContext).release(this, instance);
            } else {
                creationalContext.release();
            }
        } catch (Exception e) {
            log.error(ERROR_DESTROYING, this, instance);
            xLog.throwing(Level.DEBUG, e);
        }
    }

    /**
     * Initializes the bean and its metadata
     */
    @Override
    public void initialize(BeanDeployerEnvironment environment) {
        if (!isInitialized()) {
            checkConstructor();
            super.initialize(environment);
            initPostConstruct();
            initPreDestroy();
            initEEInjectionPoints();
            initPassivationCapable();
            setInjectionTarget(new ManagedBeanInjectionTarget(this));
        }
    }

    protected T createInstance(CreationalContext ctx) {
        if (!isSubclassed()) {
            return getConstructor().newInstance(beanManager, ctx);
        } else {
            ProxyClassConstructorInjectionPointWrapper constructorInjectionPointWrapper = new ProxyClassConstructorInjectionPointWrapper(this, constructorForEnhancedSubclass, getConstructor());
            return constructorInjectionPointWrapper.newInstance(beanManager, ctx);
        }
    }

    @Override
    protected void initAfterInterceptorsAndDecoratorsInitialized() {
        super.initAfterInterceptorsAndDecoratorsInitialized();

        if (this.passivationCapableBean && hasDecorators() && !allDecoratorsArePassivationCapable()) {
            this.passivationCapableBean = false;
        }
        if (this.passivationCapableBean && hasInterceptors() && !allInterceptorsArePassivationCapable()) {
            this.passivationCapableBean = false;
        }
    }

    private boolean allDecoratorsArePassivationCapable() {
        return getFirstNonPassivationCapableDecorator() == null;
    }

    private Decorator getFirstNonPassivationCapableDecorator() {
        for (Decorator decorator : getDecorators()) {
            if (!(PassivationCapable.class.isAssignableFrom(decorator.getClass())) || !((WeldDecorator) decorator).getWeldAnnotated().isSerializable()) {
                return decorator;
            }
        }
        return null;
    }

    private boolean allInterceptorsArePassivationCapable() {
        return getFirstNonPassivationCapableInterceptor() == null;
    }

    private InterceptorMetadata getFirstNonPassivationCapableInterceptor() {
        for (InterceptorMetadata interceptorMetadata : getBeanManager().getInterceptorModelRegistry().get(getType()).getAllInterceptors()) {
            if (!Reflections.isSerializable(interceptorMetadata.getInterceptorClass().getJavaClass())) {
                return interceptorMetadata;
            }
        }
        return null;
    }

    private void initPassivationCapable() {
        this.passivationCapableBean = getWeldAnnotated().isSerializable();
        this.passivationCapableDependency = isNormalScoped() || (isDependent() && passivationCapableBean);
    }

    @Override
    public boolean isPassivationCapableBean() {
        return passivationCapableBean;
    }

    @Override
    public boolean isPassivationCapableDependency() {
        return passivationCapableDependency;
    }

    private void initEEInjectionPoints() {
        this.ejbInjectionPoints = Beans.getEjbInjectionPoints(this, getWeldAnnotated(), getBeanManager());
        this.persistenceContextInjectionPoints = Beans.getPersistenceContextInjectionPoints(this, getWeldAnnotated(), getBeanManager());
        this.persistenceUnitInjectionPoints = Beans.getPersistenceUnitInjectionPoints(this, getWeldAnnotated(), getBeanManager());
        this.resourceInjectionPoints = Beans.getResourceInjectionPoints(this, getWeldAnnotated(), beanManager);
    }

    /**
     * Validates the type
     */
    @Override
    protected void checkType() {
        if (getWeldAnnotated().isAnonymousClass() || (getWeldAnnotated().isMemberClass() && !getWeldAnnotated().isStatic())) {
            throw new DefinitionException(SIMPLE_BEAN_AS_NON_STATIC_INNER_CLASS_NOT_ALLOWED, type);
        }
        if (!isDependent() && getWeldAnnotated().isParameterizedType()) {
            throw new DefinitionException(BEAN_MUST_BE_DEPENDENT, type);
        }
        boolean passivating = beanManager.getServices().get(MetaAnnotationStore.class).getScopeModel(scope).isPassivating();
        if (passivating && !isPassivationCapableBean()) {
            if (!getWeldAnnotated().isSerializable()) {
                throw new DeploymentException(PASSIVATING_BEAN_NEEDS_SERIALIZABLE_IMPL, this);
            } else if (hasDecorators() && !allDecoratorsArePassivationCapable()) {
                throw new DeploymentException(PASSIVATING_BEAN_HAS_NON_PASSIVATION_CAPABLE_DECORATOR, this, getFirstNonPassivationCapableDecorator());
            } else if (hasInterceptors() && !allInterceptorsArePassivationCapable()) {
                throw new DeploymentException(PASSIVATING_BEAN_HAS_NON_PASSIVATION_CAPABLE_INTERCEPTOR, this, getFirstNonPassivationCapableInterceptor());
            }
        }
        if (hasDecorators()) {
            if (getWeldAnnotated().isFinal()) {
                throw new DefinitionException(FINAL_BEAN_CLASS_WITH_DECORATORS_NOT_ALLOWED, this);
            }
            for (Decorator decorator : getDecorators()) {
                WeldClass decoratorClass;
                if (decorator instanceof DecoratorImpl) {
                    DecoratorImpl decoratorBean = (DecoratorImpl) decorator;
                    decoratorClass = decoratorBean.getWeldAnnotated();
                } else if (decorator instanceof CustomDecoratorWrapper) {
                    decoratorClass = ((CustomDecoratorWrapper) decorator).getWeldAnnotated();
                } else {
                    throw new IllegalStateException(NON_CONTAINER_DECORATOR, decorator);
                }

                for (WeldMethod decoratorMethod : decoratorClass.getWeldMethods()) {
                    WeldMethod method = getWeldAnnotated().getWeldMethod(decoratorMethod.getSignature());
                    if (method != null && !method.isStatic() && !method.isPrivate() && method.isFinal()) {
                        throw new DefinitionException(FINAL_BEAN_CLASS_WITH_INTERCEPTORS_NOT_ALLOWED, method, decoratorMethod);
                    }
                }
            }
        }
    }

    @Override
    protected void checkBeanImplementation() {
        super.checkBeanImplementation();
        if (isNormalScoped()) {
            for (WeldField field : getWeldAnnotated().getWeldFields()) {
                if (field.isPublic() && !field.isStatic()) {
                    throw new DefinitionException(PUBLIC_FIELD_ON_NORMAL_SCOPED_BEAN_NOT_ALLOWED, getWeldAnnotated());
                }
            }
        }
    }

    @Override
    protected void preSpecialize(BeanDeployerEnvironment environment) {
        super.preSpecialize(environment);
        BeansClosure closure = beanManager.getClosure();
        if (closure.isEJB(getWeldAnnotated().getWeldSuperclass())) {
            throw new DefinitionException(SPECIALIZING_BEAN_MUST_EXTEND_A_BEAN, this);
        }
    }

    @Override
    protected void specialize(BeanDeployerEnvironment environment) {
        BeansClosure closure = beanManager.getClosure();
        Bean specializedBean = closure.getClassBean(getWeldAnnotated().getWeldSuperclass());
        if (specializedBean == null) {
            throw new DefinitionException(SPECIALIZING_BEAN_MUST_EXTEND_A_BEAN, this);
        }
        if (!(specializedBean instanceof ManagedBean)) {
            throw new DefinitionException(SPECIALIZING_BEAN_MUST_EXTEND_A_BEAN, this);
        } else {
            this.specializedBean = (ManagedBean) specializedBean;
        }
    }

    @Override
    public ManagedBean getSpecializedBean() {
        return specializedBean;
    }

    @Override
    protected boolean isInterceptionCandidate() {
        return !Beans.isInterceptor(getWeldAnnotated()) && !Beans.isDecorator(getWeldAnnotated());
    }

    protected T applyInterceptors(T instance, final CreationalContext creationalContext) {
        try {
            WeldInterceptorInstantiator interceptorInstantiator = new WeldInterceptorInstantiator(beanManager, creationalContext);
            InterceptorProxyCreatorImpl interceptorProxyCreator = new InterceptorProxyCreatorImpl(interceptorInstantiator, new DefaultInvocationContextFactory(), beanManager.getInterceptorModelRegistry().get(getType()));
            MethodHandler methodHandler = interceptorProxyCreator.createSubclassingMethodHandler(null, WeldInterceptorClassMetadata.of(getWeldAnnotated()));
            CombinedInterceptorAndDecoratorStackMethodHandler wrapperMethodHandler = (CombinedInterceptorAndDecoratorStackMethodHandler) ((ProxyObject) instance).getHandler();
            wrapperMethodHandler.setInterceptorMethodHandler(methodHandler);
        } catch (Exception e) {
            throw new DeploymentException(e);
        }
        return instance;
    }

    @Override
    public String toString() {
        return "Managed Bean [" + getBeanClass().toString() + "] with qualifiers [" + Formats.formatAnnotations(getQualifiers()) + "]";
    }

    @Override
    public boolean isProxyable() {
        return proxiable;
    }

    @Override
    public boolean hasDefaultProducer() {
        return getInjectionTarget() instanceof ManagedBean.ManagedBeanInjectionTarget;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy