Package org.apache.webbeans.util

Source Code of org.apache.webbeans.util.WebBeansUtil

/*
* 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.util;

import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;


import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.decorator.Decorator;
import javax.enterprise.context.Conversation;
import javax.enterprise.context.Dependent;
import javax.enterprise.context.NormalScope;
import javax.enterprise.context.spi.Contextual;
import javax.enterprise.event.Event;
import javax.enterprise.event.Observes;
import javax.enterprise.inject.Alternative;
import javax.enterprise.inject.Disposes;
import javax.enterprise.inject.IllegalProductException;
import javax.enterprise.inject.Instance;
import javax.enterprise.inject.Produces;
import javax.enterprise.inject.Specializes;
import javax.enterprise.inject.spi.AfterBeanDiscovery;
import javax.enterprise.inject.spi.AfterDeploymentValidation;
import javax.enterprise.inject.spi.AnnotatedField;
import javax.enterprise.inject.spi.AnnotatedMethod;
import javax.enterprise.inject.spi.AnnotatedParameter;
import javax.enterprise.inject.spi.AnnotatedType;
import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.BeanManager;
import javax.enterprise.inject.spi.BeforeBeanDiscovery;
import javax.enterprise.inject.spi.BeforeShutdown;
import javax.enterprise.inject.spi.Extension;
import javax.enterprise.inject.spi.InjectionPoint;
import javax.enterprise.inject.spi.InjectionTarget;
import javax.enterprise.inject.spi.Interceptor;
import javax.enterprise.inject.spi.ObserverMethod;
import javax.enterprise.inject.spi.PassivationCapable;
import javax.enterprise.inject.spi.ProcessAnnotatedType;
import javax.enterprise.inject.spi.ProcessBean;
import javax.enterprise.inject.spi.ProcessInjectionTarget;
import javax.enterprise.inject.spi.ProcessManagedBean;
import javax.enterprise.inject.spi.ProcessObserverMethod;
import javax.enterprise.inject.spi.ProcessProducer;
import javax.enterprise.inject.spi.ProcessProducerField;
import javax.enterprise.inject.spi.ProcessProducerMethod;
import javax.enterprise.inject.spi.ProcessSessionBean;
import javax.enterprise.util.TypeLiteral;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Provider;
import javax.inject.Scope;
import javax.interceptor.AroundInvoke;
import javax.interceptor.AroundTimeout;
import javax.interceptor.InvocationContext;

import javassist.util.proxy.ProxyFactory;
import org.apache.webbeans.annotation.AnnotationManager;
import org.apache.webbeans.annotation.AnyLiteral;
import org.apache.webbeans.annotation.ApplicationScopeLiteral;
import org.apache.webbeans.annotation.DefaultLiteral;
import org.apache.webbeans.annotation.DependentScopeLiteral;
import org.apache.webbeans.annotation.NewLiteral;
import org.apache.webbeans.annotation.RequestedScopeLiteral;
import org.apache.webbeans.component.AbstractInjectionTargetBean;
import org.apache.webbeans.component.AbstractOwbBean;
import org.apache.webbeans.component.AbstractProducerBean;
import org.apache.webbeans.component.BeanManagerBean;
import org.apache.webbeans.component.ConversationBean;
import org.apache.webbeans.component.EnterpriseBeanMarker;
import org.apache.webbeans.component.EventBean;
import org.apache.webbeans.component.ExtensionBean;
import org.apache.webbeans.component.InjectionPointBean;
import org.apache.webbeans.component.InjectionTargetBean;
import org.apache.webbeans.component.InjectionTargetWrapper;
import org.apache.webbeans.component.InstanceBean;
import org.apache.webbeans.component.ManagedBean;
import org.apache.webbeans.component.NewBean;
import org.apache.webbeans.component.NewManagedBean;
import org.apache.webbeans.component.OwbBean;
import org.apache.webbeans.component.ProducerFieldBean;
import org.apache.webbeans.component.ProducerMethodBean;
import org.apache.webbeans.component.ResourceBean;
import org.apache.webbeans.component.WebBeansType;
import org.apache.webbeans.component.creation.AnnotatedTypeBeanCreatorImpl;
import org.apache.webbeans.component.creation.ManagedBeanCreatorImpl;
import org.apache.webbeans.config.DefinitionUtil;
import org.apache.webbeans.config.EJBWebBeansConfigurator;
import org.apache.webbeans.config.OWBLogConst;
import org.apache.webbeans.config.OpenWebBeansConfiguration;
import org.apache.webbeans.config.WebBeansContext;
import org.apache.webbeans.container.BeanManagerImpl;
import org.apache.webbeans.container.ExternalScope;
import org.apache.webbeans.container.InjectionResolver;
import org.apache.webbeans.conversation.ConversationImpl;
import org.apache.webbeans.decorator.DecoratorUtil;
import org.apache.webbeans.decorator.WebBeansDecoratorConfig;
import org.apache.webbeans.event.ObserverMethodImpl;
import org.apache.webbeans.exception.WebBeansConfigurationException;
import org.apache.webbeans.exception.helper.ViolationMessageBuilder;
import org.apache.webbeans.exception.inject.DefinitionException;
import org.apache.webbeans.exception.inject.DeploymentException;
import org.apache.webbeans.exception.inject.InconsistentSpecializationException;
import org.apache.webbeans.inject.AlternativesManager;
import org.apache.webbeans.intercept.InterceptorData;
import org.apache.webbeans.intercept.InterceptorDataImpl;
import javax.enterprise.inject.spi.InterceptionType;
import org.apache.webbeans.logger.WebBeansLoggerFacade;
import org.apache.webbeans.plugins.OpenWebBeansEjbLCAPlugin;
import org.apache.webbeans.plugins.PluginLoader;
import org.apache.webbeans.portable.creation.InjectionTargetProducer;
import org.apache.webbeans.portable.creation.ProducerBeansProducer;
import org.apache.webbeans.portable.events.ProcessBeanImpl;
import org.apache.webbeans.portable.events.ProcessProducerImpl;
import org.apache.webbeans.portable.events.discovery.ErrorStack;
import org.apache.webbeans.portable.events.generics.GProcessAnnotatedType;
import org.apache.webbeans.portable.events.generics.GProcessBean;
import org.apache.webbeans.portable.events.generics.GProcessInjectionTarget;
import org.apache.webbeans.portable.events.generics.GProcessManagedBean;
import org.apache.webbeans.portable.events.generics.GProcessObservableMethod;
import org.apache.webbeans.portable.events.generics.GProcessProducer;
import org.apache.webbeans.portable.events.generics.GProcessProducerField;
import org.apache.webbeans.portable.events.generics.GProcessProducerMethod;
import org.apache.webbeans.portable.events.generics.GProcessSessionBean;
import org.apache.webbeans.spi.plugins.OpenWebBeansEjbPlugin;
import org.apache.webbeans.spi.plugins.OpenWebBeansPlugin;


import static org.apache.webbeans.util.InjectionExceptionUtils.throwUnproxyableResolutionException;

/**
* Contains some utility methods used in the all project.
*
* @version $Rev: 1368948 $ $Date: 2012-08-03 15:40:12 +0200 (Fr, 03 Aug 2012) $
*/
@SuppressWarnings("unchecked")
public final class WebBeansUtil
{
    /**
     * Enforcing that interceptor callbacks should not be
     * able to throw checked exceptions is configurable
     */
    private static volatile Boolean enforceCheckedException;

    private final static Class<Instance<?>> INSTANCE_TYPE
            = new TypeLiteral<Instance<?>>()
    {
        private static final long serialVersionUID = 3555319035805031154L;
    }.getRawType();

    private final static Class<Provider<?>> PROVIDER_TYPE
            = new TypeLiteral<Provider<?>>()
    {
        private static final long serialVersionUID = -2611190564495920054L;
    }.getRawType();

    private final static Class<Event<?>>    EVENT_TYPE
            = new TypeLiteral<Event<?>>()
    {
        private static final long serialVersionUID = -1395145871249763477L;
    }.getRawType();

    private final WebBeansContext webBeansContext;

    public WebBeansUtil(WebBeansContext webBeansContext)
    {
        this.webBeansContext = webBeansContext;
    }

    /**
     * Lifycycle methods like {@link javax.annotation.PostConstruct} and
     * {@link javax.annotation.PreDestroy} must not define a checked Exception
     * regarding to the spec. But this is often unnecessary restrictive so we
     * allow to disable this check application wide.
     *
     * @return <code>true</code> if the spec rule of having no checked exception should be enforced
     */
    private boolean isNoCheckedExceptionEnforced()
    {
        if (enforceCheckedException == null)
        {
            enforceCheckedException = Boolean.parseBoolean(webBeansContext.getOpenWebBeansConfiguration().
                    getProperty(OpenWebBeansConfiguration.INTERCEPTOR_FORCE_NO_CHECKED_EXCEPTIONS, "true"));
        }

        return enforceCheckedException.booleanValue();
    }

    /**
     * Gets current classloader with current thread.
     *
     * @return Current class loader instance
     */
    public static ClassLoader getCurrentClassLoader()
    {
        ClassLoader loader =  Thread.currentThread().getContextClassLoader();

        if (loader == null)
        {
            loader = WebBeansUtil.class.getClassLoader();
        }

        return loader;
    }

    /**
     * Checks the generic type requirements.
     *
     * @param bean managed bean instance
     */
    public static void checkGenericType(Bean<?> bean)
    {
        Asserts.assertNotNull(bean);

        Class<?> clazz = bean.getBeanClass();

        if (ClassUtil.isDefinitionContainsTypeVariables(clazz))
        {
            if(!bean.getScope().equals(Dependent.class))
            {
                throw new WebBeansConfigurationException("Generic type may only defined with scope @Dependent " +
                        "for ManagedBean class : " + clazz.getName());
            }
        }
    }


    /**
     * Check producer method/field bean return type.
     * @param bean producer bean instance
     * @param member related member instance
     */
    public static void checkProducerGenericType(Bean<?> bean,Member member)
    {
        Asserts.assertNotNull(bean,"Bean is null");

        Type type = null;

        if(bean instanceof ProducerMethodBean)
        {
            type = ((ProducerMethodBean<?>)bean).getCreatorMethod().getGenericReturnType();
        }
        else if(bean instanceof ProducerFieldBean)
        {
            type = ((ProducerFieldBean<?>)bean).getCreatorField().getGenericType();
        }
        else
        {
            throw new IllegalArgumentException("Bean must be Producer Field or Method Bean instance : " + bean);
        }

        String messageTemplate = "Producer Field/Method Bean with name : %s" +
                         " in bean class : %s";

        String memberName = member.getName();
        String declaringClassName = member.getDeclaringClass().getName();
        if(checkGenericForProducers(type, messageTemplate, memberName, declaringClassName))
        {
            if(!bean.getScope().equals(Dependent.class))
            {
                String message = format(messageTemplate, memberName, declaringClassName);
                throw new WebBeansConfigurationException(message + " scope must bee @Dependent");
            }
        }
    }

    /**
     * Check generic types for producer method and fields.
     * @param type generic return type
     * @param messageTemplate error message
     * @return true if parametrized type argument is TypeVariable
     */
    //Helper method
    private static boolean checkGenericForProducers(Type type, String messageTemplate, Object... errorMessageArgs)
    {
        boolean result = false;

        if(type instanceof TypeVariable)
        {
            String message = format(messageTemplate, errorMessageArgs);
            throw new WebBeansConfigurationException(message + " return type can not be type variable");
        }

        if(ClassUtil.isParametrizedType(type))
        {
            Type[] actualTypes = ClassUtil.getActualTypeArguments(type);

            if(actualTypes.length == 0)
            {
                String message = format(messageTemplate, errorMessageArgs);
                throw new WebBeansConfigurationException(message +
                        " return type must define actual type arguments or type variable");
            }

            for(Type actualType : actualTypes)
            {
                if(ClassUtil.isWildCardType(actualType))
                {
                    String message = format(messageTemplate, errorMessageArgs);
                    throw new WebBeansConfigurationException(message +
                            " return type can not define wildcard actual type argument");
                }

                if(ClassUtil.isTypeVariable(actualType))
                {
                    result = true;
                }
            }
        }

        return result;
    }

    /**
     * Return <code>true</code> if the given class is ok for manage bean conditions,
     * <code>false</code> otherwise.
     *
     * @param clazz class in hand
     * @return <code>true</code> if the given class is ok for simple web bean conditions.
     */
    public void isManagedBeanClass(Class<?> clazz)
    {
        Asserts.nullCheckForClass(clazz, "Class is null");

        int modifier = clazz.getModifiers();

        if (!Modifier.isStatic(modifier) && ClassUtil.isInnerClazz(clazz))
        {
            throw new WebBeansConfigurationException("Bean implementation class : "
                                                     + clazz.getName() + " can not be non-static inner class");
        }

        if (!ClassUtil.isConcrete(clazz) && !AnnotationUtil.hasClassAnnotation(clazz, Decorator.class))
        {
            throw new WebBeansConfigurationException("Bean implementation class : " + clazz.getName()
                                                     + " have to be concrete if not defines as @Decorator");
        }

        if (!isConstructureOk(clazz))
        {
            throw new WebBeansConfigurationException("Bean implementation class : " + clazz.getName()
                                                     + " must define at least one Constructor");
        }

        if(Extension.class.isAssignableFrom(clazz))
        {
            throw new WebBeansConfigurationException("Bean implementation class can not implement "
                                                     + "javax.enterprise.inject.spi.Extension.!");
        }

        Class<?>[] interfaces = clazz.getInterfaces();
        if(interfaces != null && interfaces.length > 0)
        {
            for(Class<?> intr : interfaces)
            {
                if(intr.getName().equals("javax.ejb.EnterpriseBean"))
                {
                    throw new WebBeansConfigurationException("Bean implementation class can not implement "
                                                             + "javax.ejb.EnterpriseBean");
                }
            }
        }

        // and finally call all checks which are defined in plugins like JSF, JPA, etc
        List<OpenWebBeansPlugin> plugins = webBeansContext.getPluginLoader().getPlugins();
        for (OpenWebBeansPlugin plugin : plugins)
        {
            try
            {
                plugin.isManagedBean(clazz);
            }
            catch (Exception e)
            {
                PluginLoader.throwsException(e);
            }
        }
    }

    /**
     * Returns true if given class supports injections,
     * false otherwise.
     * <p>
     * Each plugin is asked with given class that supports
     * injections or not.
     * </p>
     * @param clazz scanned class
     * @return  true if given class supports injections
     */
    public boolean supportsJavaEeComponentInjections(Class<?> clazz)
    {
        if (clazz.isInterface() || clazz.isAnnotation() || clazz.isEnum())
        {
            // interfaces, annotations and enums are no subject of injection
            return false;
        }

        // and finally call all checks which are defined in plugins like JSF, JPA, etc
        List<OpenWebBeansPlugin> plugins = webBeansContext.getPluginLoader().getPlugins();
        for (OpenWebBeansPlugin plugin : plugins)
        {
            //Ejb plugin handles its own events
            //Also EJb beans supports injections
            if(!(plugin instanceof OpenWebBeansEjbPlugin))
            {
                if(plugin.supportsJavaEeComponentInjections(clazz))
                {
                    return true;
                }
            }
        }

        return false;
    }

    /**
     * Defines applicable constructor.
     * @param <T> type info
     * @param clazz class type
     * @return constructor
     * @throws WebBeansConfigurationException any configuration exception
     */
    public <T> Constructor<T> defineConstructor(Class<T> clazz) throws WebBeansConfigurationException
    {
        Asserts.nullCheckForClass(clazz);
        Constructor<?>[] constructors = webBeansContext.getSecurityService().doPrivilegedGetDeclaredConstructors(clazz);

        return defineConstructor(constructors, clazz);

    }


    public <T> Constructor<T> defineConstructor(Constructor<?>[] constructors, Class<T> clazz)
    {
        Constructor<T> result = null;

        boolean inAnnotation = false;

        /* Check for @Initializer */
        for (Constructor<?> constructor : constructors)
        {
            if (constructor.getAnnotation(Inject.class) != null)
            {
                if (inAnnotation)// duplicate @In
                {
                    throw new WebBeansConfigurationException("There are more than one Constructor with "
                                                             + "Initializer annotation in class " + clazz.getName());
                }
                inAnnotation = true;
                result = (Constructor<T>) constructor;
            }
        }

        if (result == null)
        {
            result = getNoArgConstructor(clazz);

            if(result == null)
            {
                throw new WebBeansConfigurationException("No constructor is found for the class : " + clazz.getName());
            }
        }


        Annotation[][] parameterAnns = result.getParameterAnnotations();
        for (Annotation[] parameters : parameterAnns)
        {
            for (Annotation param : parameters)
            {
                if (param.annotationType().equals(Disposes.class))
                {
                    throw new WebBeansConfigurationException("Constructor parameter annotations can not contain " +
                            "@Disposes annotation in class : " + clazz.getName());
                }

                if(param.annotationType().equals(Observes.class))
                {
                    throw new WebBeansConfigurationException("Constructor parameter annotations can not contain " +
                            "@Observes annotation in class : " + clazz.getName());
                }
            }

        }

        return result;

    }

    /**
     * Check that simple web beans class has compatible constructor.
     * @param clazz web beans simple class
     * @throws WebBeansConfigurationException if the web beans has incompatible
     *             constructor
     */
    public boolean isConstructureOk(Class<?> clazz) throws WebBeansConfigurationException
    {
        Asserts.nullCheckForClass(clazz);

        if (getNoArgConstructor(clazz) != null)
        {
            return true;
        }

        Constructor<?>[] constructors = webBeansContext.getSecurityService().doPrivilegedGetDeclaredConstructors(clazz);

        for (Constructor<?> constructor : constructors)
        {
            if (constructor.getAnnotation(Inject.class) != null)
            {
                return true;
            }
        }

        return false;
    }

    /**
     * Check producer method is ok for deployment.
     *
     * @param method producer method
     * @param parentImplClazzName parent class name
     */
    public static void checkProducerMethodForDeployment(Method method, String parentImplClazzName)
    {
        Asserts.assertNotNull(method, "Method argument can not be null");

        if (AnnotationUtil.hasMethodAnnotation(method, Inject.class) ||
            AnnotationUtil.hasMethodParameterAnnotation(method, Disposes.class) ||
            AnnotationUtil.hasMethodParameterAnnotation(method, Observes.class))
        {
            throw new WebBeansConfigurationException("Producer Method Bean with name : " + method.getName()
                                                     + " in bean class : " + parentImplClazzName
                                                     + " can not be annotated with @Initializer/@Destructor annotation "
                                                     + "or has a parameter annotated with @Disposes/@Observes");
        }
    }

    /**
     * CheckProducerMethodDisposal.
     * @param disposalMethod disposal method
     * @param definedBeanClassName bean class name
     */
    public static void checkProducerMethodDisposal(Method disposalMethod, String definedBeanClassName)
    {
        if (AnnotationUtil.hasMethodMultipleParameterAnnotation(disposalMethod, Disposes.class))
        {
            throw new WebBeansConfigurationException("Disposal method : " + disposalMethod.getName() + " in class "
                                                     + definedBeanClassName
                                                     + " has multiple @Disposes annotation parameter");
        }

        if (AnnotationUtil.hasMethodAnnotation(disposalMethod, Inject.class) ||
            AnnotationUtil.hasMethodParameterAnnotation(disposalMethod, Observes.class) ||
            AnnotationUtil.hasMethodAnnotation(disposalMethod, Produces.class))
        {
            throw new WebBeansConfigurationException("Disposal method : " + disposalMethod.getName()
                                                     + " in the class : " + definedBeanClassName
                                                     + " can not be annotated with @Initializer/@Destructor/@Produces "
                                                     + "annotation or has a parameter annotated with @Observes");
        }

    }

    /**
     * New WebBeans component class.
     *
     * @param <T>
     * @param clazz impl. class
     * @return the new component
     */
    public <T> NewManagedBean<T> createNewComponent(Class<T> clazz, Type apiType)
    {
        Asserts.nullCheckForClass(clazz);

        NewManagedBean<T> comp;
        DefinitionUtil definitionUtil = webBeansContext.getDefinitionUtil();


        if (webBeansContext.getManagedBeanConfigurator().isManagedBean(clazz))
        {
            comp = new NewManagedBean<T>(clazz, WebBeansType.MANAGED, webBeansContext);
            comp.setImplScopeType(new DependentScopeLiteral());
            comp.setConstructor(defineConstructor(clazz));
            definitionUtil.addConstructorInjectionPointMetaData(comp, comp.getConstructor());

            definitionUtil.defineInjectedFields(comp);
            definitionUtil.defineInjectedMethods(comp);
        }
        else if (EJBWebBeansConfigurator.isSessionBean(clazz, webBeansContext))
        {
            comp = new NewManagedBean<T>(clazz, WebBeansType.ENTERPRISE, webBeansContext);
            comp.setImplScopeType(new DependentScopeLiteral());
        }
        else
        {
            throw new WebBeansConfigurationException("@New annotation on type : " + clazz.getName()
                                                     + " must defined as a simple or an enterprise web bean");
        }

        comp.addQualifier(new NewLiteral(clazz));
        comp.setName(null);
        if(apiType == null)
        {
            comp.addApiType(clazz);
        }
        else
        {
            comp.getTypes().add(apiType);
        }

        comp.addApiType(Object.class);

        return comp;
    }

    /**
     * Creates a new extension bean.
     *
     * @param <T> extension service class
     * @param clazz impl. class
     * @return a new extension service bean
     */
    public <T> ExtensionBean<T> createExtensionComponent(Class<T> clazz)
    {
        Asserts.nullCheckForClass(clazz);

        ExtensionBean<T> comp = null;
        comp = new ExtensionBean<T>(clazz, webBeansContext);
        comp.setEnabled(true);

        DefinitionUtil definitionUtil = webBeansContext.getDefinitionUtil();
        definitionUtil.defineApiTypes(comp, clazz);

        comp.setImplScopeType(new ApplicationScopeLiteral());
        comp.addQualifier(new DefaultLiteral());

        definitionUtil.defineObserverMethods(comp, clazz);

        return comp;
    }


    /**
     * Creates a new manager bean instance.
     * @return new manager bean instance
     */
    public BeanManagerBean getManagerBean()
    {
        BeanManagerBean managerComponent = new BeanManagerBean(webBeansContext);

        managerComponent.setImplScopeType(new DependentScopeLiteral());
        managerComponent.addQualifier(new DefaultLiteral());
        managerComponent.addQualifier(new AnyLiteral());
        managerComponent.addApiType(BeanManager.class);
        managerComponent.addApiType(Object.class);

        return managerComponent;
    }

    /**
     * Creates a new instance bean.
     * @return new instance bean
     */
    @SuppressWarnings("serial")
    public <T> InstanceBean<T> getInstanceBean()
    {
        InstanceBean<T> instanceBean = new InstanceBean<T>(webBeansContext);

        instanceBean.getTypes().add(INSTANCE_TYPE);
        instanceBean.getTypes().add(PROVIDER_TYPE);
        instanceBean.addApiType(Object.class);

        instanceBean.addQualifier(new AnyLiteral());
        instanceBean.setImplScopeType(new DependentScopeLiteral());
        instanceBean.setName(null);

        return instanceBean;
    }

    /**
     * Creates a new event bean.
     * @return new event bean
     */
    @SuppressWarnings("serial")
    public <T> EventBean<T> getEventBean()
    {
        EventBean<T> eventBean = new EventBean<T>(webBeansContext);

        eventBean.getTypes().add(EVENT_TYPE);
        eventBean.addApiType(Object.class);

        eventBean.addQualifier(new AnyLiteral());
        eventBean.setImplScopeType(new DependentScopeLiteral());
        eventBean.setName(null);

        return eventBean;
    }


    /**
     * Returns new conversation bean instance.
     * The name is explicitly specified in 6.7.2 and is not the normal default name.
     * @return new conversation bean
     */
    public ConversationBean getConversationBean()
    {
        ConversationBean conversationComp = new ConversationBean(webBeansContext);

        conversationComp.addApiType(Conversation.class);
        conversationComp.addApiType(ConversationImpl.class);
        conversationComp.addApiType(Object.class);
        conversationComp.setImplScopeType(new RequestedScopeLiteral());
        conversationComp.addQualifier(new DefaultLiteral());
        conversationComp.addQualifier(new AnyLiteral());
        conversationComp.setName("javax.enterprise.context.conversation");

        WebBeansDecoratorConfig.configureDecorators(conversationComp);

        return conversationComp;
    }

    /**
     * Returns a new injected point bean instance.
     * @return new injected point bean
     */
    public InjectionPointBean getInjectionPointBean()
    {
        return new InjectionPointBean(webBeansContext);
    }

    /**
     * Check the {@link PostConstruct} or {@link PreDestroy} annotated method
     * criterias, and return post construct or pre destroyDependents method.
     * <p>
     * Web Beans container is responsible for setting the post construct or pre
     * destroyDependents annotation if the web beans component is not an EJB components,
     * in this case EJB container is responsible for this.
     * </p>
     *
     * @param clazz checked class
     * @param commonAnnotation post construct or predestroy annotation
     * @param invocationContext whether the takes an invocationContext, as in
     *            interceptors defiend outside of the bean class.
     * @return post construct or predestroy method
     */
    public Method checkCommonAnnotationCriterias(Class<?> clazz, Class<? extends Annotation> commonAnnotation, boolean invocationContext)
    {
        Asserts.nullCheckForClass(clazz);

        Method[] methods = ClassUtil.getDeclaredMethods(clazz);
        Method result = null;
        boolean found = false;
        for (Method method : methods)
        {
            if (AnnotationUtil.hasMethodAnnotation(method, commonAnnotation))
            {
                if (ClassUtil.isMoreThanOneMethodWithName(method.getName(), clazz))
                {
                    continue;
                }

                if (found)
                {
                    throw new WebBeansConfigurationException("@" + commonAnnotation.getSimpleName()
                            + " annotation is declared more than one method in the class : " + clazz.getName());
                }

                found = true;
                result = method;

                // Check method criterias
                if (ClassUtil.isMethodHasParameter(method))
                {
                    // Check method criterias
                    Class<?>[] params = ClassUtil.getMethodParameterTypes(method);
                    if (params.length != 1 || !params[0].equals(InvocationContext.class))
                    {
                        throw new WebBeansConfigurationException("@" + commonAnnotation.getSimpleName()
                                + " annotated method : " + method.getName() + " in class : " + clazz.getName()
                                + " can not take any formal arguments other than InvocationContext");
                    }
                }
                else if(invocationContext)
                {
                    // Maybe it just intercepts itself, but we were looking at it like an @Interceptor
                    return null;
                }

                if (!ClassUtil.getReturnType(method).equals(Void.TYPE))
                {
                    throw new WebBeansConfigurationException("@" + commonAnnotation.getSimpleName()
                            + " annotated method : " + method.getName() + " in class : " + clazz.getName()
                            + " must return void type");
                }

                if (isNoCheckedExceptionEnforced() && ClassUtil.isMethodHasCheckedException(method))
                {
                    throw new WebBeansConfigurationException("@" + commonAnnotation.getSimpleName()
                            + " annotated method : " + method.getName() + " in class : " + clazz.getName()
                            + " can not throw any checked exception");
                }

                if (Modifier.isStatic(method.getModifiers()))
                {
                    throw new WebBeansConfigurationException("@" + commonAnnotation.getSimpleName()
                            + " annotated method : " + method.getName() + " in class : "
                            + clazz.getName() + " can not be static");
                }
            }
        }

        return result;
    }

    public <T> Method checkCommonAnnotationCriterias(AnnotatedType<T> annotatedType, Class<? extends Annotation> commonAnnotation, boolean invocationContext)
    {
        Class<?> clazz = annotatedType.getJavaClass();

        Method result = null;
        boolean found = false;
        Set<AnnotatedMethod<? super T>> methods = annotatedType.getMethods();
        for(AnnotatedMethod<? super T> methodA : methods)
        {
            AnnotatedMethod<T> methodB = (AnnotatedMethod<T>)methodA;
            Method method = methodB.getJavaMember();
            if (method.isAnnotationPresent(commonAnnotation))
            {
                if (ClassUtil.isMoreThanOneMethodWithName(method.getName(), clazz))
                {
                    continue;
                }

                if (found)
                {
                    throw new WebBeansConfigurationException("@" + commonAnnotation.getSimpleName()
                            + " annotation is declared more than one method in the class : " + clazz.getName());
                }
                found = true;
                result = method;

                // Check method criterias
                if (methodB.getParameters().isEmpty())
                {
                    if (!invocationContext)
                    {
                        throw new WebBeansConfigurationException("@" + commonAnnotation.getSimpleName()
                                + " annotated method : " + method.getName() + " in class : " + clazz.getName()
                                + " can not take any formal arguments");
                    }

                    List<AnnotatedParameter<T>> parameters = methodB.getParameters();
                    List<Class<?>> clazzParameters = new ArrayList<Class<?>>();
                    for(AnnotatedParameter<T> parameter : parameters)
                    {
                        clazzParameters.add(ClassUtil.getClazz(parameter.getBaseType()));
                    }

                    Class<?>[] params = clazzParameters.toArray(new Class<?>[clazzParameters.size()]);
                    if (params.length != 1 || !params[0].equals(InvocationContext.class))
                    {
                        throw new WebBeansConfigurationException("@" + commonAnnotation.getSimpleName()
                                + " annotated method : " + method.getName() + " in class : " + clazz.getName()
                                + " can not take any formal arguments other than InvocationContext");
                    }
                }
                else if(invocationContext)
                {
                    throw new WebBeansConfigurationException("@" + commonAnnotation.getSimpleName()
                            + " annotated method : " + method.getName() + " in class : " + clazz.getName()
                            + " must take a parameter with class type javax.interceptor.InvocationContext.");
                }

                if (!ClassUtil.getReturnType(method).equals(Void.TYPE))
                {
                    throw new WebBeansConfigurationException("@" + commonAnnotation.getSimpleName()
                            + " annotated method : " + method.getName() + " in class : " + clazz.getName()
                            + " must return void type");
                }

                if (isNoCheckedExceptionEnforced() && ClassUtil.isMethodHasCheckedException(method))
                {
                    throw new WebBeansConfigurationException("@" + commonAnnotation.getSimpleName()
                            + " annotated method : " + method.getName() + " in class : " + clazz.getName()
                            + " can not throw any checked exception");
                }

                if (Modifier.isStatic(method.getModifiers()))
                {
                    throw new WebBeansConfigurationException("@" + commonAnnotation.getSimpleName()
                            + " annotated method : " + method.getName() + " in class : " + clazz.getName()
                            + " can not be static");
                }
            }

        }


        return result;
    }

    /**
     * Check the {@link AroundInvoke} annotated method criterias, and return
     * around invoke method.
     * <p>
     * Web Beans container is responsible for setting around invoke annotation
     * if the web beans component is not an EJB components, in this case EJB
     * container is responsible for this.
     * </p>
     *
     * @param clazz checked class
     * @return around invoke method
     */
    public static Method checkAroundInvokeAnnotationCriterias(Class<?> clazz, Class<? extends Annotation> annot)
    {
        Asserts.nullCheckForClass(clazz);

        Method[] methods = ClassUtil.getDeclaredMethods(clazz);
        Method result = null;
        boolean found = false;
        for (Method method : methods)
        {
            if (AnnotationUtil.hasMethodAnnotation(method, annot))
            {
                // Overriden methods
                if (ClassUtil.isMoreThanOneMethodWithName(method.getName(), clazz))
                {
                    continue;
                }

                if (found)
                {
                    throw new WebBeansConfigurationException("@" + annot.getSimpleName()
                            + " annotation is declared more than one method in the class : " + clazz.getName());
                }

                found = true;
                result = method;

                // Check method criterias
                Class<?>[] params = ClassUtil.getMethodParameterTypes(method);
                if (params.length != 1 || !params[0].equals(InvocationContext.class))
                {
                    throw new WebBeansConfigurationException("@" + annot.getSimpleName() + " annotated method : "
                            + method.getName() + " in class : " + clazz.getName()
                            + " can not take any formal arguments other than InvocationContext");
                }

                if (!ClassUtil.getReturnType(method).equals(Object.class))
                {
                    throw new WebBeansConfigurationException("@" + annot.getSimpleName() + " annotated method : "
                            + method.getName() + " in class : " + clazz.getName() + " must return Object type");
                }

                if (Modifier.isStatic(method.getModifiers()) || ClassUtil.isFinal(method.getModifiers()))
                {
                    throw new WebBeansConfigurationException("@" + annot.getSimpleName() + " annotated method : "
                            + method.getName() + " in class : " + clazz.getName() + " can not be static or final");
                }
            }
        }

        return result;
    }

    public static <T> Method checkAroundInvokeAnnotationCriterias(AnnotatedType<T> annotatedType, Class<? extends Annotation> annot)
    {
        Method result = null;
        boolean found = false;
        Set<AnnotatedMethod<? super T>> methods = annotatedType.getMethods();
        for(AnnotatedMethod<? super T> methodA : methods)
        {
            AnnotatedMethod<T> method = (AnnotatedMethod<T>)methodA;

            if (method.isAnnotationPresent(annot))
            {
                // Overriden methods
                if (ClassUtil.isMoreThanOneMethodWithName(method.getJavaMember().getName(),
                                                          annotatedType.getJavaClass()))
                {
                    continue;
                }

                if (found)
                {
                    throw new WebBeansConfigurationException("@" + annot.getSimpleName()
                            + " annotation is declared more than one method in the class : "
                            + annotatedType.getJavaClass().getName());
                }

                found = true;
                result = method.getJavaMember();

                List<AnnotatedParameter<T>> parameters = method.getParameters();
                List<Class<?>> clazzParameters = new ArrayList<Class<?>>();
                for(AnnotatedParameter<T> parameter : parameters)
                {
                    clazzParameters.add(ClassUtil.getClazz(parameter.getBaseType()));
                }

                Class<?>[] params = clazzParameters.toArray(new Class<?>[clazzParameters.size()]);

                if (params.length != 1 || !params[0].equals(InvocationContext.class))
                {
                    throw new WebBeansConfigurationException("@" + annot.getSimpleName() + " annotated method : "
                            + method.getJavaMember().getName() + " in class : " + annotatedType.getJavaClass().getName()
                            + " can not take any formal arguments other than InvocationContext");
                }

                if (!ClassUtil.getReturnType(method.getJavaMember()).equals(Object.class))
                {
                    throw new WebBeansConfigurationException("@" + annot.getSimpleName() + " annotated method : "
                            + method.getJavaMember().getName()+ " in class : " + annotatedType.getJavaClass().getName()
                            + " must return Object type");
                }

                if (Modifier.isStatic(method.getJavaMember().getModifiers()) ||
                    ClassUtil.isFinal(method.getJavaMember().getModifiers()))
                {
                    throw new WebBeansConfigurationException("@" + annot.getSimpleName() + " annotated method : "
                            + method.getJavaMember().getName( )+ " in class : " + annotatedType.getJavaClass().getName()
                            + " can not be static or final");
                }
            }
        }

        return result;
    }


    /**
     * Configures the interceptor stack of the web beans component.
     *
     * @param interceptorClass interceptor class
     * @param interceptionType annotation type
     * @param definedInInterceptorClass check if annotation is defined in
     *            interceptor class (as opposed to bean class)
     * @param definedInMethod check if the interceptor is defined in the comp.
     *            method
     * @param stack interceptor stack
     * @param annotatedInterceptorClassMethod if definedInMethod, this specify
     *            method
     * @param defineWithInterceptorBinding if interceptor is defined with WebBeans
     *            spec, not EJB spec
     */
    public void configureInterceptorMethods(Interceptor<?> webBeansInterceptor,
                                             Class<?> interceptorClass,
                                             Class<? extends Annotation> interceptionType,
                                             boolean definedInInterceptorClass,
                                             boolean definedInMethod,
                                             List<InterceptorData> stack,
                                             Method annotatedInterceptorClassMethod,
                                             boolean defineWithInterceptorBinding)
    {
        InterceptorData intData = null;
        Method method = null;
        OpenWebBeansEjbLCAPlugin ejbPlugin = null;
        Class<? extends Annotation> prePassivateClass  = null;
        Class<? extends Annotation> postActivateClass  = null;

        ejbPlugin = webBeansContext.getPluginLoader().getEjbLCAPlugin();
        if(ejbPlugin != null)
        {
            prePassivateClass  = ejbPlugin.getPrePassivateClass();
            postActivateClass  = ejbPlugin.getPostActivateClass();
        }

        //Check for default constructor of EJB based interceptor
        if(webBeansInterceptor == null)
        {
            if(definedInInterceptorClass)
            {
                Constructor<?> ct = getNoArgConstructor(interceptorClass);
                if (ct == null)
                {
                    throw new WebBeansConfigurationException("class : " + interceptorClass.getName()
                            + " must have no-arg constructor");
                }
            }
        }

        if (interceptionType.equals(AroundInvoke.class) || interceptionType.equals(AroundTimeout.class))
        {
            method = WebBeansUtil.checkAroundInvokeAnnotationCriterias(interceptorClass, interceptionType);
        }
        else if (interceptionType.equals(PostConstruct.class) || ((postActivateClass != null) && (interceptionType.equals(postActivateClass)))
                 || interceptionType.equals(PreDestroy.class) || ((prePassivateClass != null) && (interceptionType.equals(prePassivateClass))))
        {
            method = checkCommonAnnotationCriterias(interceptorClass, interceptionType, definedInInterceptorClass);
        }

        if (method != null)
        {
            intData = new InterceptorDataImpl(defineWithInterceptorBinding, webBeansContext);
            intData.setDefinedInInterceptorClass(definedInInterceptorClass);
            intData.setDefinedInMethod(definedInMethod);
            intData.setInterceptorBindingMethod(annotatedInterceptorClassMethod);
            intData.setWebBeansInterceptor(webBeansInterceptor);

            if (definedInInterceptorClass)
            {
                intData.setInterceptorClass(interceptorClass);
            }

            intData.setInterceptorMethod(method, interceptionType);

            stack.add(intData);
        }
    }


    public <T> void configureInterceptorMethods(Interceptor<?> webBeansInterceptor,
                                                 AnnotatedType<T> annotatedType,
                                                 Class<? extends Annotation> annotation,
                                                 boolean definedInInterceptorClass,
                                                 boolean definedInMethod,
                                                 List<InterceptorData> stack,
                                                 Method annotatedInterceptorClassMethod)
    {
        InterceptorData intData = null;
        Method method = null;
        OpenWebBeansEjbLCAPlugin ejbPlugin = null;
        Class<? extends Annotation> prePassivateClass  = null;
        Class<? extends Annotation> postActivateClass  = null;

        ejbPlugin = webBeansContext.getPluginLoader().getEjbLCAPlugin();
        if(ejbPlugin != null)
        {
            prePassivateClass  = ejbPlugin.getPrePassivateClass();
            postActivateClass  = ejbPlugin.getPostActivateClass();
        }

        if (annotation.equals(AroundInvoke.class) ||
                annotation.equals(AroundTimeout.class))
        {
            method = WebBeansUtil.checkAroundInvokeAnnotationCriterias(annotatedType, annotation);
        }
        else if (annotation.equals(PostConstruct.class) || ((postActivateClass != null) && (annotation.equals(postActivateClass)))
                 || annotation.equals(PreDestroy.class) || ((prePassivateClass != null) && (annotation.equals(prePassivateClass))))
        {
            method = checkCommonAnnotationCriterias(annotatedType, annotation, definedInInterceptorClass);
        }

        if (method != null)
        {
            intData = new InterceptorDataImpl(true, webBeansContext);
            intData.setDefinedInInterceptorClass(definedInInterceptorClass);
            intData.setDefinedInMethod(definedInMethod);
            intData.setInterceptorBindingMethod(annotatedInterceptorClassMethod);
            intData.setWebBeansInterceptor(webBeansInterceptor);
            intData.setInterceptorMethod(method, annotation);
            intData.setInterceptorClass(webBeansInterceptor.getBeanClass());

            stack.add(intData);
        }
    }


    /**
     * Create a new instance of the given class using it's default constructor
     * regardless if the constructor is visible or not.
     * This is needed to construct some package scope classes in the TCK.
     *
     * @param <T>
     * @param clazz
     * @return
     * @throws WebBeansConfigurationException
     */
    public <T> T newInstanceForced(Class<T> clazz) throws WebBeansConfigurationException
    {
        // FIXME: This new instance should have JCDI injection performed
        Constructor<T> ct = getNoArgConstructor(clazz);
        if (ct == null)
        {
            throw new WebBeansConfigurationException("class : " + clazz.getName() + " must have no-arg constructor");
        }

        if (!ct.isAccessible())
        {
            webBeansContext.getSecurityService().doPrivilegedSetAccessible(ct, true);
        }

        try
        {
            return ct.newInstance();
        }
        catch( IllegalArgumentException e )
        {
            throw new WebBeansConfigurationException("class : " + clazz.getName() + " is not constructable", e);
        }
        catch( IllegalAccessException e )
        {
            throw new WebBeansConfigurationException("class : " + clazz.getName() + " is not constructable", e);
        }
        catch( InvocationTargetException e )
        {
            throw new WebBeansConfigurationException("class : " + clazz.getName() + " is not constructable", e);
        }
        catch( InstantiationException e )
        {
            throw new WebBeansConfigurationException("class : " + clazz.getName() + " is not constructable", e);
        }
    }

    /**
     * Returns true if interceptor stack contains interceptor with given type.
     *
     * @param stack interceptor stack
     * @param type interceptor type
     * @return true if stack contains the interceptor with given type
     */
    public static boolean isContainsInterceptorMethod(List<InterceptorData> stack, InterceptionType type)
    {
        if (stack.size() > 0)
        {
            Iterator<InterceptorData> it = stack.iterator();
            while (it.hasNext())
            {
                Method m = null;
                InterceptorData data = it.next();

                if (type.equals(InterceptionType.AROUND_INVOKE))
                {
                    m = data.getAroundInvoke();
                }
                else if (type.equals(InterceptionType.AROUND_TIMEOUT))
                {
                    m = data.getAroundTimeout();
                }
                else if (type.equals(InterceptionType.POST_CONSTRUCT))
                {
                    m = data.getPostConstruct();
                }
                else if (type.equals(InterceptionType.POST_ACTIVATE))
                {
                    m = data.getPostActivate();
                }
                else if (type.equals(InterceptionType.PRE_DESTROY))
                {
                    m = data.getPreDestroy();
                }
                else if (type.equals(InterceptionType.PRE_PASSIVATE))
                {
                    m = data.getPrePassivate();
                }

                if (m != null)
                {
                    return true;
                }

            }
        }

        return false;
    }

    public static String getManagedBeanDefaultName(String clazzName)
    {
        Asserts.assertNotNull(clazzName);

        if(clazzName.length() > 0)
        {
            StringBuilder name = new StringBuilder(clazzName);
            name.setCharAt(0, Character.toLowerCase(name.charAt(0)));

            return name.toString();
        }

        return clazzName;
    }

    public static String getProducerDefaultName(String methodName)
    {
        StringBuilder buffer = new StringBuilder(methodName);

        if (buffer.length() > 3 &&  (buffer.substring(0, 3).equals("get") || buffer.substring(0, 3).equals("set")))
        {

            if(Character.isUpperCase(buffer.charAt(3)))
            {
                buffer.setCharAt(3, Character.toLowerCase(buffer.charAt(3)));
            }

            return buffer.substring(3);
        }
        else if ((buffer.length() > 2 &&  buffer.substring(0, 2).equals("is")))
        {
            if(Character.isUpperCase(buffer.charAt(2)))
            {
                buffer.setCharAt(2, Character.toLowerCase(buffer.charAt(2)));
            }

            return buffer.substring(2);
        }

        else
        {
            buffer.setCharAt(0, Character.toLowerCase(buffer.charAt(0)));
            return buffer.toString();
        }
    }

    /**
     * Return true if a list of beans are directly specialized/extended each other.
     *
     * @param beans, a set of specialized beans.
     *
     * @return
     */
    protected static boolean isDirectlySpecializedBeanSet(Set<Bean<?>> beans)
    {

        ArrayList<AbstractOwbBean<?>> beanList = new ArrayList<AbstractOwbBean<?>>();

        for(Bean<?> bb : beans)
        {
            AbstractOwbBean<?>bean = (AbstractOwbBean<?>)bb;
            beanList.add(bean);
        }

        java.util.Collections.sort(beanList, new java.util.Comparator()
        {
            public int compare(Object o1, Object o2)
            {
                AbstractOwbBean<?> b1 = (AbstractOwbBean<?>)o1;
                AbstractOwbBean<?> b2 = (AbstractOwbBean<?>)o2;
                Class c1 = b1.getReturnType();
                Class c2 = b2.getReturnType();
                if (c2.isAssignableFrom(c1))
                {
                    return 1;
                }

                if (c1.isAssignableFrom(c2))
                {
                    return -1;
                }

                throw new InconsistentSpecializationException(c1 + " and " + c2 + "are not assignable to each other." );
            }
        });

        for(int i=0; i<beanList.size() - 1; i++)
        {
            if (!beanList.get(i).getReturnType().equals(beanList.get(i+1).getReturnType().getSuperclass()))
            {
                return false;
            }
        }
        return true;
    }

    public void configureSpecializations(List<Class<?>> beanClasses)
    {
        for(Class<?> clazz : beanClasses)
        {
            configureSpecializations(clazz, beanClasses);
        }
    }

    /**
     * Configures the bean specializations.
     * <p>
     * Specialized beans inherit the <code>name</code> property
     * from their parents. Specialized bean deployment priority
     * must be higher than its super class related bean.
     * </p>
     *
     * @param specializedClass specialized class
     * @throws DefinitionException if name is defined
     * @throws InconsistentSpecializationException related with priority
     * @throws WebBeansConfigurationException any other exception
     */
    protected void configureSpecializations(Class<?> specializedClass, List<Class<?>> beanClasses)
    {
        Asserts.nullCheckForClass(specializedClass);

        Bean<?> superBean = null;
        Bean<?> specialized = null;
        Set<Bean<?>> resolvers = isConfiguredWebBeans(specializedClass, true);
        AlternativesManager altManager = webBeansContext.getAlternativesManager();

        if (resolvers != null)
        {
            if(resolvers.isEmpty())
            {
                throw new InconsistentSpecializationException("Specialized bean for class : " + specializedClass
                        + " is not enabled in the deployment.");
            }

            specialized = resolvers.iterator().next();

            if(resolvers.size() > 1)
            {
                if (!isDirectlySpecializedBeanSet(resolvers))
                {
                    throw new InconsistentSpecializationException("More than one specialized bean for class : "
                            + specializedClass + " is enabled in the deployment.");
                }
                // find the widest bean which satisfies the specializedClass
                for( Bean<?> sp : resolvers)
                {
                    if (sp == specialized)
                    {
                        continue;
                    }

                    if (((AbstractOwbBean<?>)sp).getReturnType().
                            isAssignableFrom(((AbstractOwbBean<?>)specialized).getReturnType()))
                    {
                        specialized = sp;
                    }
                }
            }

            Class<?> superClass = specializedClass.getSuperclass();

            resolvers = isConfiguredWebBeans(superClass,false);

            for(Bean<?> candidates : resolvers)
            {
                AbstractOwbBean<?> candidate = (AbstractOwbBean<?>)candidates;

                if(!(candidate instanceof NewBean))
                {
                    if(candidate.getReturnType().equals(superClass))
                    {
                        superBean = candidates;
                        break;
                    }
                }
            }

            if (superBean != null)
            {
                // Recursively configure super class first if super class is also a special bean.
                // So the name and bean meta data could be populated to this beanclass.
                if (beanClasses.contains(superClass) && ((AbstractOwbBean<?>)superBean).isEnabled())
                {
                    configureSpecializations(superClass, beanClasses);
                }

                if (!AnnotationUtil.hasClassAnnotation(specializedClass, Alternative.class))
                {
                    //disable superbean if the current bean is not an alternative
                    ((AbstractOwbBean<?>)superBean).setEnabled(false);
                }
                else if(altManager.isClassAlternative(specializedClass))
                {
                    //disable superbean if the current bean is an enabled alternative
                    ((AbstractOwbBean<?>)superBean).setEnabled(false);
                }

                AbstractOwbBean<?> comp = (AbstractOwbBean<?>)specialized;
                if (comp.isSpecializedBean())
                {
                    // This comp is already configured in previous invocation
                    // return directly, else Exception might be fired when set
                    // bean name again.
                    return;
                }

                //Check types of the beans
                if(comp.getClass() != superBean.getClass())
                {
                    throw new DefinitionException("@Specialized Class : " + specializedClass.getName()
                            + " and its super class may be the same type of bean,i.e, ManagedBean, SessionBean etc.");
                }

                if(superBean.getName() != null)
                {
                    if(comp.getName() != null)
                    {
                        throw new DefinitionException("@Specialized Class : " + specializedClass.getName()
                                + " may not explicitly declare a bean name");
                    }

                    comp.setName(superBean.getName());
                    comp.setSpecializedBean(true);
                }

                specialized.getQualifiers().addAll(superBean.getQualifiers());
            }

            else
            {
                throw new InconsistentSpecializationException("WebBean component class : " + specializedClass.getName()
                        + " is not enabled for specialized by the " + specializedClass + " class");
            }
        }

    }

    /**
     * Configure a list of producer method beans, which override the same method
     * and the bean classes are directly extended each other.
     *
     * @param sortedProducerBeans
     */
    protected void configSpecializedProducerMethodBeans(List<ProducerMethodBean> sortedProducerBeans)
    {
        if (sortedProducerBeans.isEmpty())
        {
            return;
        }

        AlternativesManager altManager = webBeansContext.getAlternativesManager();
        Method superMethod = sortedProducerBeans.get(0).getCreatorMethod();

        for(int i=1; i<sortedProducerBeans.size(); i++)
        {
            ProducerMethodBean bean = sortedProducerBeans.get(i);
            ProducerMethodBean superBean = sortedProducerBeans.get(i - 1);

            // inherit superbean qualifiers
            Set<Annotation> qualifiers = superBean.getQualifiers();
            for(Annotation an : qualifiers)
            {
                bean.addQualifier(an);
            }
            // inherit name is super class has name
            boolean isSuperHasName = configuredProducerSpecializedName(bean, bean.getCreatorMethod(), superMethod);

            // disable super bean if needed
            if (bean.getCreatorMethod().getAnnotation(Alternative.class) == null)
            {
                //disable superbean if the current bean is not an alternative
                superBean.setEnabled(false);
            }
            else if(altManager.isClassAlternative(bean.getBeanClass()))
            {
                //disable superbean if the current bean is an enabled alternative
                superBean.setEnabled(false);
            }

            //if no name defined, set superMethod to this bean since this
            //bean's method might have name defined.
            if (!isSuperHasName)
            {
                superMethod = bean.getCreatorMethod();
            }
        }
    }

    /**
     * Configure direct/indirect specialized producer method beans.
     */
    public void configureProducerMethodSpecializations()
    {
        Method method;
        ProducerMethodBean pbean;
        ProducerMethodBean pLeft;
        ProducerMethodBean pRight;

        // collect all producer method beans
        Set<Bean<?>> beans = webBeansContext.getBeanManagerImpl().getBeans();
        List<ProducerMethodBean> producerBeans = new ArrayList<ProducerMethodBean>();
        for(Bean b : beans)
        {
            if (b instanceof ProducerMethodBean)
            {
                producerBeans.add((ProducerMethodBean)b);
            }
        }

        // create sorted bean helper.
        SortedListHelper<ProducerMethodBean> producerBeanListHelper = new
                SortedListHelper<ProducerMethodBean>(new ArrayList<ProducerMethodBean>(),
                new Comparator<ProducerMethodBean> ()
                {
                    public int compare(ProducerMethodBean e1, ProducerMethodBean e2)
                    {
                        if (e1.getBeanClass().isAssignableFrom(e2.getBeanClass()))
                        {
                            return -1;
                        }
                        else if (e1.equals(e2))
                        {
                            return 0;
                        }
                        return 1;
                    }
                });

        while(true)
        {
            pbean = null;
            method = null;
            producerBeanListHelper.clear();

            //locate a specialized bean
            for(ProducerMethodBean pb : producerBeans)
            {
                if (pb.isSpecializedBean())
                {
                    pbean = pb;
                    method = pb.getCreatorMethod();
                    producerBeanListHelper.add(pb);
                    break;
                }
            }
            if (pbean == null)
            {
                break;
            }

            pRight = pbean;
            pLeft = pRight;
            boolean pLeftContinue = true;
            boolean pRightContinue = true;

            // find all pbean's super beans and sub sub beans
            while(pLeftContinue || pRightContinue)
            {
                pRightContinue = false;
                pLeftContinue = false;
                for(ProducerMethodBean pb : producerBeans)
                {
                    //left
                    if (pLeft!= null &&
                        pLeft.getBeanClass().getSuperclass().equals(pb.getBeanClass()))
                    {
                        Method superMethod = ClassUtil.getClassMethodWithTypes(pb.getBeanClass(), method.getName(),
                                Arrays.asList(method.getParameterTypes()));

                        //Added by GE, method check is necessary otherwise getting wrong method qualifier annotations
                        if (superMethod != null && superMethod.equals(pb.getCreatorMethod()))
                        {
                            producerBeanListHelper.add(pb);
                            pLeft = (pb.isSpecializedBean()) ? pb : null;
                        }
                        else
                        {
                            pLeft = null;
                        }
                        if (pLeft != null)
                        {
                            pLeftContinue = true;
                        }
                    }
                    //right
                    if (pRight != null &&
                        pb.getBeanClass().getSuperclass().equals(pRight.getBeanClass()))
                    {
                        if (!pb.isSpecializedBean())
                        {
                            pRight = null;
                        }
                        else
                        {
                            Method superMethod = ClassUtil.getClassMethodWithTypes(pb.getBeanClass(), method.getName(),
                                    Arrays.asList(method.getParameterTypes()));
                            //Added by GE, method check is necessary otherwise getting wrong method qualifier annotations
                            if (superMethod != null && superMethod.equals(pb.getCreatorMethod()))
                            {
                                producerBeanListHelper.add(pb);
                                pRight = pb;
                            }
                            else
                            {
                                pRight = null;
                            }
                        }
                        if (pRight != null)
                        {
                            pRightContinue = true;
                        }
                    }
                } // for
            } // while

            //remove the group from producer bean list
            for(ProducerMethodBean pb : producerBeanListHelper.getList())
            {
                producerBeans.remove(pb);
            }
            //configure the directly extended producer beans
            configSpecializedProducerMethodBeans(producerBeanListHelper.getList());
        }
    }


    public Set<Bean<?>> isConfiguredWebBeans(Class<?> clazz,boolean annotate)
    {
        Asserts.nullCheckForClass(clazz);

        Set<Bean<?>> beans = new HashSet<Bean<?>>();

        Set<Bean<?>> components = webBeansContext.getBeanManagerImpl().getComponents();
        Iterator<Bean<?>> it = components.iterator();

        while (it.hasNext())
        {
            AbstractOwbBean<?> bean = (AbstractOwbBean<?>)it.next();

            boolean enterprise = false;
            if(bean instanceof EnterpriseBeanMarker)
            {
                enterprise = true;
            }

            if (bean.getTypes().contains(clazz) ||
                    (enterprise && bean.getBeanClass().equals(clazz)))
            {
                if(annotate)
                {
                    if(bean.getReturnType().isAnnotationPresent(Specializes.class))
                    {
                        if(!(bean instanceof NewBean))
                        {
                            beans.add(bean);
                        }
                    }
                }
                else
                {
                    beans.add(bean);
                }
            }
        }

        return beans;
    }

    /**
     * Checks the unproxiable condition.
     * @param bean managed bean
     * @param scopeType scope type
     * @throws WebBeansConfigurationException if
     *  bean is not proxied by the container
     */
    public void checkUnproxiableApiType(Bean<?> bean, Class<? extends Annotation> scopeType)
    {
        Asserts.assertNotNull("bean", "bean parameter can not be null");
        Asserts.assertNotNull(scopeType, "scopeType parameter can not be null");

        //Unproxiable test for NormalScoped beans
        if (isScopeTypeNormal(scopeType))
        {
            Set<Type> types = bean.getTypes();

            ViolationMessageBuilder violationMessage = ViolationMessageBuilder.newViolation();

            for(Type type : types)
            {
                Class<?> beanClass = ClassUtil.getClass(type);

                if(!beanClass.isInterface() && beanClass != Object.class)
                {
                    if(beanClass.isPrimitive())
                    {
                        violationMessage.addLine("It isn't possible to use a primitive type (" + beanClass.getName(), ")");
                    }

                    if(ClassUtil.isArray(beanClass))
                    {
                        violationMessage.addLine("It isn't possible to use an array type (", beanClass.getName(), ")");
                    }

                    if(!violationMessage.containsViolation())
                    {
                        if (ClassUtil.isFinal(beanClass.getModifiers()))
                        {
                            violationMessage.addLine(beanClass.getName(), " is a final class! CDI doesn't allow that.");
                        }

                        Method[] methods = SecurityUtil.doPrivilegedGetDeclaredMethods(beanClass);
                        for (Method m : methods)
                        {
                            int modifiers = m.getModifiers();
                            if (ClassUtil.isFinal(modifiers) && !Modifier.isPrivate(modifiers) &&
                                !m.isSynthetic() && !m.isBridge())
                            {
                                violationMessage.addLine(beanClass.getName(), " has final method "+ m + " CDI doesn't allow that.");
                            }
                        }

                        Constructor<?> cons = getNoArgConstructor(beanClass);
                        if (cons == null)
                        {
                            violationMessage.addLine(beanClass.getName(), " has no explicit no-arg constructor!",
                                    "A public or protected constructor without args is required!");
                        }
                        else if (Modifier.isPrivate(cons.getModifiers()))
                        {
                            violationMessage.addLine(beanClass.getName(), " has a >private< no-arg constructor! CDI doesn't allow that.");
                        }
                    }

                    //Throw Exception
                    if(violationMessage.containsViolation())
                    {
                        throwUnproxyableResolutionException(violationMessage);
                    }
                }
            }
        }
    }

    private <T> Constructor<T> getNoArgConstructor(Class<T> clazz)
    {
        return webBeansContext.getSecurityService().doPrivilegedGetDeclaredConstructor(clazz);
    }

    /**
     * Configures the producer method specialization.
     *
     * @param component producer method component
     * @param method specialized producer method
     * @param superClass bean super class that has overriden method
     * @throws DefinitionException if the name is exist on the producer method when
     *         parent also has name
     * @throws WebBeansConfigurationException any other exceptions
     */
    public static void configureProducerSpecialization(AbstractOwbBean<?> component, Method method, Class<?> superClass)
    {
        Method superMethod = ClassUtil.getClassMethodWithTypes(superClass, method.getName(), Arrays.asList(method.getParameterTypes()));
        if (superMethod == null)
        {
            throw new WebBeansConfigurationException("Producer method specialization is failed. Method "
                    + method.getName() + " not found in super class : " + superClass.getName());
        }

        if (!AnnotationUtil.hasAnnotation(superMethod.getAnnotations(), Produces.class))
        {
            throw new WebBeansConfigurationException("Producer method specialization is failed. Method "
                    + method.getName() + " found in super class : " + superClass.getName()
                    + " is not annotated with @Produces");
        }

        component.setSpecializedBean(true);

    }

    /**
     * Configures the name of the producer method for specializing the parent.
     *
     * @param component producer method component
     * @param method specialized producer method
     * @param superMethod overriden super producer method
     */
    public boolean configuredProducerSpecializedName(AbstractOwbBean<?> component, Method method, Method superMethod)
    {
        return webBeansContext.getAnnotationManager().configuredProducerSpecializedName(component, method, superMethod);
    }

    public static void checkInjectedMethodParameterConditions(Method method, Class<?> clazz)
    {
        Asserts.assertNotNull(method, "method parameter can not be null");
        Asserts.nullCheckForClass(clazz);

        if (AnnotationUtil.hasMethodParameterAnnotation(method, Disposes.class) ||
            AnnotationUtil.hasMethodParameterAnnotation(method, Observes.class))
        {
            throw new WebBeansConfigurationException("Initializer method parameters in method : " + method.getName()
                    + " in class : " + clazz.getName() + " can not be annotated with @Disposes or @Observers");

        }

    }

    /**
     * Returns true if instance injection point false otherwise.
     *
     * @param injectionPoint injection point definition
     * @return true if instance injection point
     */
    public static boolean checkObtainsInjectionPointConditions(InjectionPoint injectionPoint)
    {
        Type type = injectionPoint.getType();

        Class<?> candidateClazz = null;
        if(type instanceof Class)
        {
            candidateClazz = (Class<?>)type;
        }
        else if(type instanceof ParameterizedType)
        {
            ParameterizedType pt = (ParameterizedType)type;
            candidateClazz = (Class<?>)pt.getRawType();
        }

        if(!candidateClazz.isAssignableFrom(Instance.class))
        {
            return false;
        }

        Class<?> rawType;

        if(ClassUtil.isParametrizedType(injectionPoint.getType()))
        {
            ParameterizedType pt = (ParameterizedType)injectionPoint.getType();

            rawType = (Class<?>) pt.getRawType();

            Type[] typeArgs = pt.getActualTypeArguments();

            if(!(rawType.isAssignableFrom(Instance.class)))
            {
                throw new WebBeansConfigurationException("<Instance> field injection " + injectionPoint.toString()
                        + " must have type javax.inject.Instance");
            }
            else
            {
                if(typeArgs.length != 1)
                {
                    throw new WebBeansConfigurationException("<Instance> field injection " + injectionPoint.toString()
                            + " must not have more than one actual type argument");
                }
            }
        }
        else
        {
            throw new WebBeansConfigurationException("<Instance> field injection " + injectionPoint.toString()
                    + " must be defined as ParameterizedType with one actual type argument");
        }

        return true;
    }

    public <T> void defineInterceptor(ManagedBeanCreatorImpl<T> managedBeanCreator, ProcessInjectionTarget<T> injectionTargetEvent)
    {
        Class<?> clazz = injectionTargetEvent.getAnnotatedType().getJavaClass();
        AnnotatedType annotatedType = injectionTargetEvent.getAnnotatedType();

        if (webBeansContext.getInterceptorsManager().isInterceptorEnabled(clazz))
        {
            ManagedBean<T> component;

            webBeansContext.getInterceptorUtil().checkInterceptorConditions(annotatedType);
            component = defineManagedBean(managedBeanCreator, injectionTargetEvent, false);

            if (component != null)
            {
                Annotation[] anns = annotatedType.getAnnotations().toArray(new Annotation[annotatedType.getAnnotations().size()]);
                webBeansContext.getWebBeansInterceptorConfig().configureInterceptorClass(component,
                        webBeansContext.getAnnotationManager().getInterceptorBindingMetaAnnotations(anns));
            }
            else
            {
                // TODO could probably be a bit more descriptive
                throw new DeploymentException("Cannot create Interceptor for class" + injectionTargetEvent.getAnnotatedType());
            }
        }

    }


    /**
     * Define decorator bean.
     * @param <T> type info
     * @param creator bean creator
     * @param processInjectionTargetEvent
     */
    public <T> void defineDecorator(ManagedBeanCreatorImpl<T> creator, ProcessInjectionTarget<T> processInjectionTargetEvent)
    {
        Class<T> clazz = processInjectionTargetEvent.getAnnotatedType().getJavaClass();
        if (webBeansContext.getDecoratorsManager().isDecoratorEnabled(clazz))
        {
            ManagedBean<T> delegate = null;

            DecoratorUtil.checkDecoratorConditions(clazz);

            if(Modifier.isAbstract(clazz.getModifiers()))
            {
                delegate = defineAbstractDecorator(creator, processInjectionTargetEvent);
            }
            else
            {
                delegate = defineManagedBean(creator, processInjectionTargetEvent, false);
            }

            if (delegate != null)
            {
                WebBeansDecoratorConfig.configureDecoratorClass(delegate);
            }
            else
            {
                // TODO could probably be a bit more descriptive
                throw new DeploymentException("Cannot create Decorator for class" + processInjectionTargetEvent.getAnnotatedType());
            }
        }
    }

    /**
     * The result of this invocation get's cached
     * @see #isScopeTypeNormalCache
     * @param scopeType
     * @return <code>true</code> if the given scopeType represents a
     *         {@link javax.enterprise.context.NormalScope}d bean
     */
    public boolean isScopeTypeNormal(Class<? extends Annotation> scopeType)
    {
        Asserts.assertNotNull(scopeType, "scopeType argument can not be null");

        Boolean isNormal = isScopeTypeNormalCache.get(scopeType);

        if (isNormal != null)
        {
            return isNormal.booleanValue();
        }


        if (scopeType.isAnnotationPresent(NormalScope.class))
        {
            isScopeTypeNormalCache.put(scopeType, Boolean.TRUE);
            return true;
        }

        if(scopeType.isAnnotationPresent(Scope.class))
        {
            isScopeTypeNormalCache.put(scopeType, Boolean.FALSE);
            return false;
        }

        List<ExternalScope> additionalScopes = webBeansContext.getBeanManagerImpl().getAdditionalScopes();
        for (ExternalScope additionalScope : additionalScopes)
        {
            if (additionalScope.getScope().equals(scopeType))
            {
                isNormal = additionalScope.isNormal() ? Boolean.TRUE : Boolean.FALSE;
                isScopeTypeNormalCache.put(scopeType, isNormal);
                return isNormal.booleanValue();
            }
        }

        // no scopetype found so far -> kawumms
        throw new IllegalArgumentException("scopeType argument must be annotated with @Scope or @NormalScope");
    }

    /**
     * we cache results of calls to {@link #isScopeTypeNormalCache} 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<Class<? extends Annotation>, Boolean> isScopeTypeNormalCache =
            new ConcurrentHashMap<Class<? extends Annotation>, Boolean>();
   
    public static void checkNullInstance(Object instance, Class<? > scopeType, String errorMessage,
            Object... errorMessageArgs)
    {
        if (instance == null)
        {
            if (!scopeType.equals(Dependent.class))
            {
                String message = format(errorMessage, errorMessageArgs);
                throw new IllegalProductException(message);
            }
        }
    }

    public void checkSerializableScopeType(Class<? extends Annotation> scopeType, boolean isSerializable, String errorMessage,
            Object... errorMessageArgs)
    {
        if (webBeansContext.getBeanManagerImpl().isPassivatingScope(scopeType))
        {
            if (!isSerializable)
            {
                String message = format(errorMessage, errorMessageArgs);
                throw new IllegalProductException(message);
            }
        }
    }

    public static Bean<?> getMostSpecializedBean(BeanManager manager, Bean<?> component)
    {
         Set<Bean<?>> beans;

         if (component instanceof EnterpriseBeanMarker)
         {
             beans = new HashSet<Bean<?>>();
             Set<Bean<?>> allBeans = ((BeanManagerImpl)(manager)).getBeans(Object.class, AnnotationUtil.getAnnotationsFromSet(component.getQualifiers()));

             for(Bean<?> candidateBean : allBeans)
             {
                 if (candidateBean instanceof EnterpriseBeanMarker)
                 {
                     /*
                      * If a bean class of a session bean X is annotated @Specializes, then the bean class of X must directly extend
                      * the bean class of another session bean Y. Then X directly specializes Y, as defined in Section 4.3, ‚"Specialization".
                      */
                     Class<?> candidateSuperClass = candidateBean.getBeanClass().getSuperclass();
                     if (candidateSuperClass.equals(component.getBeanClass()))
                     {
                         beans.add(candidateBean);
                     }
                 }
             }
         }
         else
         {
             beans = manager.getBeans(component.getBeanClass(),
                     AnnotationUtil.getAnnotationsFromSet(component.getQualifiers()));
         }

        for(Bean<?> bean : beans)
        {
            Bean<?> find = bean;

            if(!find.equals(component))
            {
                if(AnnotationUtil.hasClassAnnotation(find.getBeanClass(), Specializes.class))
                {
                    return getMostSpecializedBean(manager, find);
                }
            }
        }

        return component;
    }

    /**
     * Returns <code>ProcessAnnotatedType</code> event.
     * @param <T> bean type
     * @param annotatedType bean class
     * @return event
     */
    public <T> GProcessAnnotatedType fireProcessAnnotatedTypeEvent(AnnotatedType<T> annotatedType)
    {
        GProcessAnnotatedType processAnnotatedEvent = new GProcessAnnotatedType(annotatedType);

        //Fires ProcessAnnotatedType
        webBeansContext.getBeanManagerImpl().fireEvent(processAnnotatedEvent,AnnotationUtil.EMPTY_ANNOTATION_ARRAY);

        if (processAnnotatedEvent.isModifiedAnnotatedType())
        {
            webBeansContext.getAnnotatedElementFactory().setAnnotatedType(processAnnotatedEvent.getAnnotatedType());
        }

        return processAnnotatedEvent;
    }

    /**
     * Returns <code>ProcessInjectionTarget</code> event.
     * @param <T> bean type
     * @param bean bean instance
     * @return event
     */
    public <T> GProcessInjectionTarget fireProcessInjectionTargetEvent(AbstractInjectionTargetBean<T> bean)
    {
        GProcessInjectionTarget processInjectionTargetEvent = createProcessInjectionTargetEvent(bean);
        return fireProcessInjectionTargetEvent(processInjectionTargetEvent);


    }

    public GProcessInjectionTarget fireProcessInjectionTargetEvent(GProcessInjectionTarget processInjectionTargetEvent)
    {
        //Fires ProcessInjectionTarget
        webBeansContext.getBeanManagerImpl().fireEvent(processInjectionTargetEvent, AnnotationUtil.EMPTY_ANNOTATION_ARRAY);

        return processInjectionTargetEvent;
    }

    public <T> GProcessInjectionTarget createProcessInjectionTargetEvent(AbstractInjectionTargetBean<T> bean)
    {
        AnnotatedType<T> annotatedType = webBeansContext.getAnnotatedElementFactory().newAnnotatedType(bean.getReturnType());
        InjectionTargetProducer<T> injectionTarget = new InjectionTargetProducer<T>(bean);
        return new GProcessInjectionTarget(injectionTarget, annotatedType);
    }


    /**
     * Returns <code>ProcessInjectionTarget</code> event.
     * @param <T> bean type
     * @return event
     */
    public <T> GProcessInjectionTarget fireProcessInjectionTargetEventForJavaEeComponents(Class<T> componentClass)
    {
        AnnotatedType<T> annotatedType = webBeansContext.getAnnotatedElementFactory().newAnnotatedType(componentClass);
        InjectionTarget<T> injectionTarget = webBeansContext.getBeanManagerImpl().createInjectionTarget(annotatedType);
        GProcessInjectionTarget processInjectionTargetEvent = new GProcessInjectionTarget(injectionTarget,annotatedType);

        //Fires ProcessInjectionTarget
        return fireProcessInjectionTargetEvent(processInjectionTargetEvent);

    }


    public GProcessProducer fireProcessProducerEventForMethod(ProducerMethodBean<?> producerMethod, AnnotatedMethod<?> method)
    {
        GProcessProducer producerEvent = new GProcessProducer(new ProducerBeansProducer(producerMethod),method);

        //Fires ProcessProducer for methods
        webBeansContext.getBeanManagerImpl().fireEvent(producerEvent, AnnotationUtil.EMPTY_ANNOTATION_ARRAY);

        return producerEvent;
    }

    public GProcessProducer fireProcessProducerEventForField(ProducerFieldBean<?> producerField, AnnotatedField<?> field)
    {
        GProcessProducer producerEvent = new GProcessProducer(new ProducerBeansProducer(producerField),field);

        //Fires ProcessProducer for fields
        webBeansContext.getBeanManagerImpl().fireEvent(producerEvent, AnnotationUtil.EMPTY_ANNOTATION_ARRAY);

        return producerEvent;
    }

    public void fireProcessProducerMethodBeanEvent(Map<ProducerMethodBean<?>, AnnotatedMethod<?>> annotatedMethods, AnnotatedType<?> annotatedType)
    {
        WebBeansContext webBeansContext = this.webBeansContext;
        AnnotationManager annotationManager = webBeansContext.getAnnotationManager();

        for(Map.Entry<ProducerMethodBean<?>, AnnotatedMethod<?>> beanEntry : annotatedMethods.entrySet())
        {
            ProducerMethodBean<?> bean = beanEntry.getKey();
            AnnotatedMethod<?> annotatedMethod = beanEntry.getValue();
            Annotation[] annotationsFromSet = AnnotationUtil.getAnnotationsFromSet(bean.getQualifiers());
            Method disposal = annotationManager.getDisposalWithGivenAnnotatedMethod(annotatedType, bean.getReturnType(), annotationsFromSet);

            AnnotatedMethod<?> disposalAnnotated = null;
            GProcessProducerMethod processProducerMethodEvent = null;
            if(disposal != null)
            {
                disposalAnnotated = webBeansContext.getAnnotatedElementFactory().newAnnotatedMethod(disposal, annotatedType);
                processProducerMethodEvent = new GProcessProducerMethod(bean,annotatedMethod,
                                                                        disposalAnnotated.getParameters().get(0));
            }
            else
            {
                processProducerMethodEvent = new GProcessProducerMethod(bean,annotatedMethod,null);
            }


            //Fires ProcessProducer
            webBeansContext.getBeanManagerImpl().fireEvent(processProducerMethodEvent, AnnotationUtil.EMPTY_ANNOTATION_ARRAY);
        }
    }

    public void fireProcessObservableMethodBeanEvent(Map<ObserverMethod<?>,AnnotatedMethod<?>> annotatedMethods)
    {
        for(Map.Entry<ObserverMethod<?>, AnnotatedMethod<?>> observableMethodEntry : annotatedMethods.entrySet())
        {
            ObserverMethod<?> observableMethod = observableMethodEntry.getKey();
            AnnotatedMethod<?> annotatedMethod = observableMethodEntry.getValue();

            GProcessObservableMethod event = new GProcessObservableMethod(annotatedMethod, observableMethod);

            //Fires ProcessProducer
            webBeansContext.getBeanManagerImpl().fireEvent(event, AnnotationUtil.EMPTY_ANNOTATION_ARRAY);
        }
    }


    public void fireProcessProducerFieldBeanEvent(Map<ProducerFieldBean<?>,AnnotatedField<?>> annotatedFields)
    {
        for(Map.Entry<ProducerFieldBean<?>, AnnotatedField<?>> beanEntry : annotatedFields.entrySet())
        {
            ProducerFieldBean<?> bean = beanEntry.getKey();
            AnnotatedField<?> field = beanEntry.getValue();

            GProcessProducerField processProducerFieldEvent = new GProcessProducerField(bean,field);

            //Fire ProcessProducer
            webBeansContext.getBeanManagerImpl().fireEvent(processProducerFieldEvent, AnnotationUtil.EMPTY_ANNOTATION_ARRAY);
        }
    }

    public static void checkInjectionPointNamedQualifier(InjectionPoint injectionPoint)
    {
        Set<Annotation> qualifierset = injectionPoint.getQualifiers();
        Named namedQualifier = null;
        for(Annotation qualifier : qualifierset)
        {
            if(qualifier.annotationType().equals(Named.class))
            {
                namedQualifier = (Named)qualifier;
                break;
            }
        }

        if(namedQualifier != null)
        {
            String value = namedQualifier.value();

            if(value == null || value.equals(""))
            {
                Member member = injectionPoint.getMember();
                if(!(member instanceof Field))
                {
                    throw new WebBeansConfigurationException("Injection point type : " + injectionPoint
                                                             + " can not define @Named qualifier without value!");
                }
            }
        }

    }

    /**
     * Sets bean enabled flag.
     * @param bean bean instance
     */
    public void setInjectionTargetBeanEnableFlag(InjectionTargetBean<?> bean)
    {
        Asserts.assertNotNull(bean, "bean can not be null");
       
        boolean isAlternative = hasInjectionTargetBeanAnnotatedWithAlternative(bean);

        if(!isAlternative)
        {
            AnnotatedType at = bean.getAnnotatedType();
            if (at != null)
            {
                isAlternative =  at.getAnnotation(Alternative.class) != null;
            }
        }
       
        if(isAlternative && !webBeansContext.getAlternativesManager().isBeanHasAlternative(bean))
        {
            bean.setEnabled(false);
        }
    }


    public static boolean hasInjectionTargetBeanAnnotatedWithAlternative(InjectionTargetBean<?> bean)
    {
        Asserts.assertNotNull(bean, "bean can not be null");

        boolean alternative = false;

        if(AnnotationUtil.hasClassAnnotation(bean.getBeanClass(), Alternative.class))
        {
            alternative = true;
        }

        if(!alternative)
        {
            Set<Class<? extends Annotation>> stereotypes = bean.getStereotypes();
            for(Class<? extends Annotation> stereoType : stereotypes)
            {
                if(AnnotationUtil.hasClassAnnotation(stereoType, Alternative.class))
                {
                    alternative = true;
                    break;
                }
            }

        }

        return alternative;

    }

    public void setBeanEnableFlagForProducerBean(InjectionTargetBean<?> parent, AbstractProducerBean<?> producer, Annotation[] annotations)
    {
        Asserts.assertNotNull(parent, "parent can not be null");
        Asserts.assertNotNull(producer, "producer can not be null");

        boolean alternative = false;

        if(AnnotationUtil.hasAnnotation(annotations, Alternative.class))
        {
            alternative = true;
        }

        if(!alternative)
        {
            Set<Class<? extends Annotation>> stereotypes = producer.getStereotypes();
            for(Class<? extends Annotation> stereoType : stereotypes)
            {
                if(AnnotationUtil.hasClassAnnotation(stereoType, Alternative.class))
                {
                    alternative = true;
                    break;
                }
            }
        }

        if(alternative)
        {
            if(hasInjectionTargetBeanAnnotatedWithAlternative(parent) &&
                    webBeansContext.getAlternativesManager().isBeanHasAlternative(parent))
            {
                producer.setEnabled(true);
            }
            else
            {
                producer.setEnabled(false);
            }
        }
        else
        {
            producer.setEnabled(parent.isEnabled());
        }
    }

    public static boolean isExtensionEventType(Class<?> clazz)
    {
        if(clazz.equals(BeforeBeanDiscovery.class) ||
                clazz.equals(AfterBeanDiscovery.class) ||
                clazz.equals(AfterDeploymentValidation.class) ||
                clazz.equals(BeforeShutdown.class) ||
                clazz.equals(GProcessAnnotatedType.class) ||
                clazz.equals(GProcessInjectionTarget.class) ||
                clazz.equals(GProcessProducer.class) ||
                clazz.equals(GProcessProducerField.class) ||
                clazz.equals(GProcessProducerMethod.class) ||
                clazz.equals(GProcessManagedBean.class) ||
                clazz.equals(GProcessBean.class) ||
                clazz.equals(GProcessSessionBean.class) ||
                clazz.equals(GProcessObservableMethod.class)
                )
        {
            return true;
        }

        return false;
    }

    public static boolean isExtensionBeanEventType(Class<?> clazz)
    {
        if(clazz.equals(GProcessAnnotatedType.class) ||
                clazz.equals(GProcessInjectionTarget.class) ||
                clazz.equals(GProcessManagedBean.class) ||
                clazz.equals(GProcessSessionBean.class) ||
                clazz.equals(GProcessBean.class)
                )
        {
            return true;
        }

        return false;
    }

    public static boolean isDefaultExtensionBeanEventType(Class<?> clazz)
    {
        if(clazz.equals(ProcessAnnotatedType.class) ||
                clazz.equals(ProcessInjectionTarget.class) ||
                clazz.equals(ProcessManagedBean.class) ||
                clazz.equals(ProcessBean.class) ||
                clazz.equals(ProcessSessionBean.class)
                )
        {
            return true;
        }

        return false;
    }

    public static boolean isExtensionProducerOrObserverEventType(Class<?> clazz)
    {
        if(clazz.equals(GProcessProducer.class) ||
                clazz.equals(GProcessProducerField.class) ||
                clazz.equals(GProcessProducerMethod.class) ||
                clazz.equals(GProcessObservableMethod.class)
                )
        {
            return true;
        }

        return false;

    }

    public static boolean isDefaultExtensionProducerOrObserverEventType(Class<?> clazz)
    {
        if(clazz.equals(ProcessProducer.class) ||
                clazz.equals(ProcessProducerField.class) ||
                clazz.equals(ProcessProducerMethod.class) ||
                clazz.equals(ProcessObserverMethod.class)
                )
        {
            return true;
        }

        return false;

    }

    public static boolean isDependent(Bean<?> bean)
    {
        if(!(bean instanceof OwbBean))
        {
            if(bean.getScope().equals(Dependent.class))
            {
                return true;
            }

            return false;
        }

        return ((OwbBean) bean).isDependent();
    }

    public void inspectErrorStack(String logMessage)
    {
        BeanManagerImpl manager = webBeansContext.getBeanManagerImpl();
        //Looks for errors
        ErrorStack stack = manager.getErrorStack();
        try
        {
            if(stack.hasErrors())
            {
                stack.logErrors();
                throw new WebBeansConfigurationException(logMessage);
            }
        }
        finally
        {
            stack.clear();
        }
    }

    /**
     *
     * @param contextual the {@link Bean} to check
     * @return the uniqueId if it is {@link PassivationCapable} and enabled
     */
    public static String isPassivationCapable(Contextual<?> contextual)
    {
        if(contextual instanceof Bean)
        {
            if(contextual instanceof AbstractOwbBean)
            {
                if( ((AbstractOwbBean<?>)contextual).isPassivationCapable())
                {
                    return ((AbstractOwbBean<?>)contextual).getId();
                }
            }

            else if(contextual instanceof PassivationCapable)
            {
                PassivationCapable pc = (PassivationCapable)contextual;

                return pc.getId();
            }
        }
        else
        {
            if((contextual instanceof PassivationCapable) && (contextual instanceof Serializable))
            {
                PassivationCapable pc = (PassivationCapable)contextual;

                return pc.getId();
            }
        }

        return null;
    }

    public <T> ManagedBean<T> defineAbstractDecorator(ManagedBeanCreatorImpl<T> managedBeanCreator, ProcessInjectionTarget<T> processInjectionTargetEvent)
    {

        ManagedBean<T> bean = defineManagedBean(managedBeanCreator, processInjectionTargetEvent, false);
        if (bean == null)
        {
            // TODO could probably be a bit more descriptive
            throw new DeploymentException("Cannot create ManagedBean for class" + processInjectionTargetEvent.getAnnotatedType());
        }

        //X TODO move proxy instance creation into JavassistProxyFactory!
        Class clazz = webBeansContext.getJavassistProxyFactory().createAbstractDecoratorProxyClass(bean);

        bean.setConstructor(defineConstructor(clazz));
        bean.setIsAbstractDecorator(true);
        return bean;
    }


    public <T> ManagedBean<T> defineManagedBean(ManagedBeanCreatorImpl<T> managedBeanCreator, ProcessInjectionTarget<T> processInjectionTargetEvent, boolean allowLazyInit)
    {
        BeanManagerImpl manager = webBeansContext.getBeanManagerImpl();

        //Annotated type
        AnnotatedType<T> annotatedType = processInjectionTargetEvent.getAnnotatedType();
        ManagedBean<T> managedBean = managedBeanCreator.getBean();

        Class<T> clazz = annotatedType.getJavaClass();

        managedBeanCreator.defineApiType();

        //Define meta-data
        managedBeanCreator.defineStereoTypes();
        //Scope type
        managedBeanCreator.defineScopeType(WebBeansLoggerFacade.getTokenString(OWBLogConst.TEXT_MB_IMPL) + clazz.getName() +
                WebBeansLoggerFacade.getTokenString(OWBLogConst.TEXT_SAME_SCOPE), allowLazyInit);

        managedBeanCreator.defineSerializable();

        //Check for Enabled via Alternative
        setInjectionTargetBeanEnableFlag(managedBean);

        managedBeanCreator.checkCreateConditions();
        managedBeanCreator.defineQualifier();
        managedBeanCreator.defineName(WebBeansUtil.getManagedBeanDefaultName(clazz.getSimpleName()));

        if (managedBean.isFullInit())
        {
            managedBeanCreator.defineConstructor();
            Set<ProducerMethodBean<?>> producerMethods = managedBeanCreator.defineProducerMethods();
            Set<ProducerFieldBean<?>> producerFields = managedBeanCreator.defineProducerFields();
            managedBeanCreator.defineInjectedFields();
            managedBeanCreator.defineInjectedMethods();

            Set<ObserverMethod<?>> observerMethods = new HashSet<ObserverMethod<?>>();
            if(managedBean.isEnabled())
            {
                observerMethods = managedBeanCreator.defineObserverMethods();
            }

            //Put final InjectionTarget instance
            manager.putInjectionTargetWrapper(managedBean,
                    new InjectionTargetWrapper(processInjectionTargetEvent.getInjectionTarget()));

            Map<ProducerMethodBean<?>,AnnotatedMethod<?>> annotatedMethods =
                    new HashMap<ProducerMethodBean<?>, AnnotatedMethod<?>>();

            for(ProducerMethodBean<?> producerMethod : producerMethods)
            {
                AnnotatedMethod<?> method = webBeansContext.getAnnotatedElementFactory().newAnnotatedMethod(producerMethod.getCreatorMethod(),
                                                                                       annotatedType);
                ProcessProducerImpl<?, ?> producerEvent = fireProcessProducerEventForMethod(producerMethod,
                                                                                                        method);
                inspectErrorStack("There are errors that are added by ProcessProducer event observers for "
                                               + "ProducerMethods. Look at logs for further details");

                annotatedMethods.put(producerMethod, method);
                manager.putInjectionTargetWrapper(producerMethod, new InjectionTargetWrapper(producerEvent.getProducer()));
            }

            Map<ProducerFieldBean<?>,AnnotatedField<?>> annotatedFields =
                    new HashMap<ProducerFieldBean<?>, AnnotatedField<?>>();

            for(ProducerFieldBean<?> producerField : producerFields)
            {
                AnnotatedField<?> field = webBeansContext.getAnnotatedElementFactory().newAnnotatedField(producerField.getCreatorField(),
                                                                                    annotatedType);
                ProcessProducerImpl<?, ?> producerEvent = fireProcessProducerEventForField(producerField,
                                                                                                        field);
                inspectErrorStack("There are errors that are added by ProcessProducer event observers for"
                                               + " ProducerFields. Look at logs for further details");

                annotatedFields.put(producerField, field);
                manager.putInjectionTargetWrapper(producerField, new InjectionTargetWrapper(producerEvent.getProducer()));
            }

            Map<ObserverMethod<?>,AnnotatedMethod<?>> observerMethodsMap =
                    new HashMap<ObserverMethod<?>, AnnotatedMethod<?>>();

            for(ObserverMethod<?> observerMethod : observerMethods)
            {
                ObserverMethodImpl<?> impl = (ObserverMethodImpl<?>)observerMethod;
                AnnotatedMethod<?> method = webBeansContext.getAnnotatedElementFactory().newAnnotatedMethod(impl.getObserverMethod(),
                                                                                       annotatedType);

                observerMethodsMap.put(observerMethod, method);
            }

            BeanManagerImpl beanManager = webBeansContext.getBeanManagerImpl();

            //Fires ProcessManagedBean
            ProcessBeanImpl<T> processBeanEvent = new GProcessManagedBean(managedBean, annotatedType);
            beanManager.fireEvent(processBeanEvent);
            inspectErrorStack("There are errors that are added by ProcessManagedBean event observers for " +
                    "managed beans. Look at logs for further details");

            //Fires ProcessProducerMethod
            fireProcessProducerMethodBeanEvent(annotatedMethods, annotatedType);
            inspectErrorStack("There are errors that are added by ProcessProducerMethod event observers for " +
                    "producer method beans. Look at logs for further details");

            //Fires ProcessProducerField
            fireProcessProducerFieldBeanEvent(annotatedFields);
            inspectErrorStack("There are errors that are added by ProcessProducerField event observers for " +
                    "producer field beans. Look at logs for further details");

            //Fire ObservableMethods
            fireProcessObservableMethodBeanEvent(observerMethodsMap);
            inspectErrorStack("There are errors that are added by ProcessObserverMethod event observers for " +
                    "observer methods. Look at logs for further details");

            if(!isAnnotatedTypeDecoratorOrInterceptor(annotatedType))
            {
                beanManager.addBean(managedBean);
                for (ProducerMethodBean<?> producerMethod : producerMethods)
                {
                    // add them one after the other to enable serialization handling et al
                    beanManager.addBean(producerMethod);
                }
                managedBeanCreator.defineDisposalMethods();//Define disposal method after adding producers
                for (ProducerFieldBean<?> producerField : producerFields)
                {
                    // add them one after the other to enable serialization handling et al
                    beanManager.addBean(producerField);
                }
            }
        }
        else
        {
            // we still need to fire a ProcessManagedBean event, even for lazily initiated beans
            // (which most probably are no beans at all...)

            BeanManagerImpl beanManager = webBeansContext.getBeanManagerImpl();

            //Fires ProcessManagedBean
            ProcessBeanImpl<T> processBeanEvent = new GProcessManagedBean(managedBean, annotatedType);
            beanManager.fireEvent(processBeanEvent);
            inspectErrorStack("There are errors that are added by ProcessManagedBean event observers for " +
                    "managed beans. Look at logs for further details");
            if(!isAnnotatedTypeDecoratorOrInterceptor(annotatedType))
            {
                beanManager.addBean(managedBean);
            }
        }

        return managedBean;
    }

    /**
     * This method will be used in {@link AfterBeanDiscovery#addBean(javax.enterprise.inject.spi.Bean)}}
     */
    public <T> ManagedBean<T> defineManagedBeanWithoutFireEvents(AnnotatedType<T> type)
    {
        Class<T> clazz = type.getJavaClass();

        ManagedBean<T> managedBean = new ManagedBean<T>(clazz,WebBeansType.MANAGED, webBeansContext);
        managedBean.setAnnotatedType(type);
        ManagedBeanCreatorImpl<T> managedBeanCreator = new ManagedBeanCreatorImpl<T>(managedBean);
        managedBeanCreator.setAnnotatedType(type);

        managedBeanCreator.defineApiType();

        //Define meta-data
        managedBeanCreator.defineStereoTypes();

        //Scope type
        managedBeanCreator.defineScopeType(WebBeansLoggerFacade.getTokenString(OWBLogConst.TEXT_MB_IMPL) + clazz.getName() +
                WebBeansLoggerFacade.getTokenString(OWBLogConst.TEXT_SAME_SCOPE), false);

        managedBeanCreator.defineSerializable();

        //Check for Enabled via Alternative
        setInjectionTargetBeanEnableFlag(managedBean);
        managedBeanCreator.checkCreateConditions();
        managedBeanCreator.defineQualifier();
        managedBeanCreator.defineName(WebBeansUtil.getManagedBeanDefaultName(clazz.getSimpleName()));
        managedBeanCreator.defineConstructor();
        managedBeanCreator.defineProducerMethods();
        managedBeanCreator.defineProducerFields();
        managedBeanCreator.defineInjectedFields();
        managedBeanCreator.defineInjectedMethods();
        managedBeanCreator.defineObserverMethods();

        DefinitionUtil definitionUtil = webBeansContext.getDefinitionUtil();
        definitionUtil.defineDecoratorStack(managedBean);
        definitionUtil.defineBeanInterceptorStack(managedBean);

        managedBeanCreator.defineDisposalMethods();//Define disposal method after adding producers

        return managedBean;
    }


    /**
     * Determines if the injection is to be performed into a static field.
     *
     * @param injectionPoint
     * @return <code>true</code> if the injection is into a static field
     */
    public static boolean isStaticInjection(InjectionPoint injectionPoint)
    {
        if (injectionPoint != null)
        {
            Member member = injectionPoint.getMember();
            if (member != null && Modifier.isStatic(member.getModifiers()))
            {
                return true;
            }
        }

        return false;
    }

    public boolean isPassivationCapableDependency(InjectionPoint injectionPoint)
    {
        //Don't attempt to get an instance of the delegate injection point
        if (injectionPoint.isDelegate())
        {
            return true;
        }
        InjectionResolver instance = webBeansContext.getBeanManagerImpl().getInjectionResolver();

        Bean<?> bean = instance.getInjectionPointBean(injectionPoint);
        if((bean instanceof EnterpriseBeanMarker) ||
                (bean instanceof ResourceBean) ||
                (bean instanceof InstanceBean) ||
                (bean instanceof EventBean) ||
                (bean instanceof InjectionPointBean) ||
                (bean instanceof BeanManagerBean)
                )
        {
            return true;
        }

        else if(webBeansContext.getBeanManagerImpl().isNormalScope(bean.getScope()))
        {
            return true;
        }
        else
        {
            if(isPassivationCapable(bean) != null)
            {
                return true;
            }
        }
        return false;
    }

    public static void throwRuntimeExceptions(Exception e)
    {
        if(RuntimeException.class.isAssignableFrom(e.getClass()))
        {
            throw (RuntimeException)e;
        }

        throw new RuntimeException(e);
    }

    public static void initProxyFactoryClassLoaderProvider()
    {
        ProxyFactory.classLoaderProvider = new OpenWebBeansClassLoaderProvider();
    }

    /**
     * Return true if this annotated type represents a decorator.
     * @param annotatedType annotated type
     * @return true if decorator
     */
    public static boolean isAnnotatedTypeDecorator(AnnotatedType<?> annotatedType)
    {
        if(annotatedType.isAnnotationPresent(Decorator.class))
        {
            return true;
        }

        return false;
    }

    /**
     * Return true if this annotated type represents a decorator.
     * @param annotatedType annotated type
     * @return true if decorator
     */
    public boolean isAnnotatedTypeDecoratorOrInterceptor(AnnotatedType<?> annotatedType)
    {
        if(isAnnotatedTypeDecorator(annotatedType) ||
                isAnnotatedTypeInterceptor(annotatedType))
        {
            return true;
        }
        else if(webBeansContext.getInterceptorsManager().isInterceptorEnabled(annotatedType.getJavaClass()))
        {
            return true;
        }
        else if(webBeansContext.getDecoratorsManager().isDecoratorEnabled(annotatedType.getJavaClass()))
        {
            return true;
        }


        return false;
    }

    /**
     * Return true if this annotated type represents a decorator.
     * @param annotatedType annotated type
     * @return true if decorator
     */
    public static boolean isAnnotatedTypeInterceptor(AnnotatedType<?> annotatedType)
    {
        if(annotatedType.isAnnotationPresent(javax.interceptor.Interceptor.class))
        {
            return true;
        }

        return false;
    }

    public <T> ManagedBean<T> defineManagedBean(AnnotatedType<T> type)
    {
        Class<T> clazz = type.getJavaClass();

        ManagedBean<T> managedBean = new ManagedBean<T>(clazz,WebBeansType.MANAGED, webBeansContext);
        managedBean.setAnnotatedType(type);
        AnnotatedTypeBeanCreatorImpl<T> managedBeanCreator = new AnnotatedTypeBeanCreatorImpl<T>(managedBean);
        managedBeanCreator.setAnnotatedType(type);

        managedBeanCreator.defineApiType();

        //Define meta-data
        managedBeanCreator.defineStereoTypes();

        //Scope type
        managedBeanCreator.defineScopeType(WebBeansLoggerFacade.getTokenString(OWBLogConst.TEXT_MB_IMPL) + clazz.getName()
                                           + WebBeansLoggerFacade.getTokenString(OWBLogConst.TEXT_SAME_SCOPE), false);

        managedBeanCreator.defineSerializable();

        //Check for Enabled via Alternative
        setInjectionTargetBeanEnableFlag(managedBean);
        managedBeanCreator.checkCreateConditions();
        managedBeanCreator.defineQualifier();
        managedBeanCreator.defineName(getManagedBeanDefaultName(clazz.getSimpleName()));
        managedBeanCreator.defineConstructor();
        managedBeanCreator.defineProducerMethods();
        managedBeanCreator.defineProducerFields();
        managedBeanCreator.defineInjectedFields();
        managedBeanCreator.defineInjectedMethods();
        managedBeanCreator.defineObserverMethods();
        webBeansContext.getDefinitionUtil().defineDecoratorStack(managedBean);
        webBeansContext.getDefinitionUtil().defineBeanInterceptorStack(managedBean);

        managedBeanCreator.defineDisposalMethods(); //Define disposal method after adding producers

        return managedBean;
    }

    public void lazyInitializeManagedBean(Class<?> clazz, ManagedBean<?> managedBean, ManagedBeanCreatorImpl<?> managedBeanCreator)
    {
        managedBeanCreator.defineConstructor();
        managedBeanCreator.defineProducerMethods();
        managedBeanCreator.defineProducerFields();
        managedBeanCreator.defineInjectedFields();
        managedBeanCreator.defineInjectedMethods();
        managedBeanCreator.defineObserverMethods();
        webBeansContext.getDefinitionUtil().defineDecoratorStack(managedBean);
        webBeansContext.getDefinitionUtil().defineBeanInterceptorStack(managedBean);

        managedBeanCreator.defineDisposalMethods(); //Define disposal method after adding producers
    }

    @SuppressWarnings("unchecked")
    public <T> ManagedBean<T> defineAbstractDecorator(AnnotatedType<T> type)
    {

        ManagedBean<T> bean = defineManagedBean(type);

        //X TODO move proxy instance creation into JavassistProxyFactory!
        Class clazz = webBeansContext.getJavassistProxyFactory().createAbstractDecoratorProxyClass(bean);

        bean.setConstructor(defineConstructor(clazz));
        bean.setIsAbstractDecorator(true);
        return bean;
    }

    /**
     * Define decorator bean.
     * @param <T> type info
     * @param annotatedType decorator class
     */
    public <T> void defineDecorator(AnnotatedType<T> annotatedType)
    {
        if (webBeansContext.getDecoratorsManager().isDecoratorEnabled(annotatedType.getJavaClass()))
        {
            ManagedBean<T> delegate = null;

            Set<AnnotatedMethod<? super T>> methods = annotatedType.getMethods();
            for(AnnotatedMethod<? super T> methodA : methods)
            {
                Method method = methodA.getJavaMember();
                if(AnnotationUtil.hasMethodAnnotation(method, Produces.class))
                {
                    throw new WebBeansConfigurationException("Decorator class : " + annotatedType.getJavaClass() + " can not have producer methods but it has one with name : "
                                                             + method.getName());
                }

                if(AnnotationUtil.hasMethodParameterAnnotation(method, Observes.class))
                {
                    throw new WebBeansConfigurationException("Decorator class : " + annotatedType.getJavaClass() + " can not have observer methods but it has one with name : "
                                                             + method.getName());
                }

            }

            if(Modifier.isAbstract(annotatedType.getJavaClass().getModifiers()))
            {
                delegate = defineAbstractDecorator(annotatedType);
            }
            else
            {
                delegate = defineManagedBean(annotatedType);
            }

            if (delegate != null)
            {
                WebBeansDecoratorConfig.configureDecoratorClass(delegate);
            }
        }
    }

    public <T> void defineInterceptor(AnnotatedType<T> annotatedType)
    {
        Class<?> clazz = annotatedType.getJavaClass();
        if (webBeansContext.getInterceptorsManager().isInterceptorEnabled(clazz))
        {
            ManagedBean<T> delegate = null;

            webBeansContext.getInterceptorUtil().checkAnnotatedTypeInterceptorConditions(annotatedType);
            delegate = defineManagedBean(annotatedType);

            if (delegate != null)
            {
                Set<Annotation> annTypeSet = annotatedType.getAnnotations();
                Annotation[] anns = annTypeSet.toArray(new Annotation[annTypeSet.size()]);
                AnnotationManager annotationManager = webBeansContext.getAnnotationManager();
                webBeansContext.getWebBeansInterceptorConfig().configureInterceptorClass(delegate,
                                                               annotationManager.getInterceptorBindingMetaAnnotations(anns));
            }
        }

    }

    /**
     * Checks the implementation class for checking conditions.
     *
     * @param type implementation class
     * @throws org.apache.webbeans.exception.WebBeansConfigurationException if any configuration exception occurs
     */
    public <X> void checkManagedBeanCondition(AnnotatedType<X> type) throws WebBeansConfigurationException
    {
        int modifier = type.getJavaClass().getModifiers();

        if (type.isAnnotationPresent(Decorator.class) && type.isAnnotationPresent(javax.interceptor.Interceptor.class))
        {
            throw new WebBeansConfigurationException("Annotated type "+ type +  " may not annotated with both @Interceptor and @Decorator annotation");
        }

        if (!type.isAnnotationPresent(Decorator.class) && !type.isAnnotationPresent(javax.interceptor.Interceptor.class))
        {
            checkManagedWebBeansInterceptorConditions(type);
        }

        if (ClassUtil.isInterface(modifier))
        {
            throw new WebBeansConfigurationException("ManagedBean implementation class : " + type.getJavaClass().getName() + " may not defined as interface");
        }
    }

    private <X> void checkManagedWebBeansInterceptorConditions(AnnotatedType<X> type)
    {
        Annotation[] anns = AnnotationUtil.getAnnotationsFromSet(type.getAnnotations());

        Class<?> clazz = type.getJavaClass();
        boolean hasClassInterceptors = false;
        AnnotationManager annotationManager = webBeansContext.getAnnotationManager();
        if (annotationManager.getInterceptorBindingMetaAnnotations(anns).length > 0)
        {
            hasClassInterceptors = true;
        }
        else
        {
            Annotation[] stereoTypes = annotationManager.getStereotypeMetaAnnotations(anns);
            for (Annotation stero : stereoTypes)
            {
                if (annotationManager.hasInterceptorBindingMetaAnnotation(stero.annotationType().getDeclaredAnnotations()))
                {
                    hasClassInterceptors = true;
                    break;
                }
            }
        }

        if(ClassUtil.isFinal(clazz.getModifiers()) && hasClassInterceptors)
        {
            throw new WebBeansConfigurationException("Final managed bean class with name : " + clazz.getName() + " can not define any InterceptorBindings");
        }

        Set<AnnotatedMethod<? super X>> methods = type.getMethods();
        for(AnnotatedMethod<? super X> methodA : methods)
        {
            Method method = methodA.getJavaMember();
            int modifiers = method.getModifiers();
            if (!method.isSynthetic() && !method.isBridge() && !Modifier.isStatic(modifiers) && !Modifier.isPrivate(modifiers) && ClassUtil.isFinal(modifiers))
            {
                if (hasClassInterceptors)
                {
                    throw new WebBeansConfigurationException("Maanged bean class : " + clazz.getName()
                                                    + " can not define non-static, non-private final methods. Because it is annotated with at least one @InterceptorBinding");
                }

                if (annotationManager.hasInterceptorBindingMetaAnnotation(
                    AnnotationUtil.getAnnotationsFromSet(methodA.getAnnotations())))
                {
                    throw new WebBeansConfigurationException("Method : " + method.getName() + "in managed bean class : " + clazz.getName()
                                                    + " can not be defined as non-static, non-private and final . Because it is annotated with at least one @InterceptorBinding");
                }
            }

        }
    }

    // Note: following code for method 'format' is taken from google guava - apache 2.0 licenced library
    // com.google.common.base.Preconditions.format(String, Object...)
    /**
     * Substitutes each {@code %s} in {@code template} with an argument. These
     * are matched by position - the first {@code %s} gets {@code args[0]}, etc.
     * If there are more arguments than placeholders, the unmatched arguments will
     * be appended to the end of the formatted message in square braces.
     *
     * @param template a non-null string containing 0 or more {@code %s}
     *     placeholders.
     * @param args the arguments to be substituted into the message
     *     template. Arguments are converted to strings using
     *     {@link String#valueOf(Object)}. Arguments can be null.
     */
    private static String format(String template,
            Object... args)
    {
        template = String.valueOf(template); // null -> "null"

        // start substituting the arguments into the '%s' placeholders
        StringBuilder builder = new StringBuilder(
                template.length() + 16 * args.length);
        int templateStart = 0;
        int i = 0;
        while (i < args.length)
        {
            int placeholderStart = template.indexOf("%s", templateStart);
            if (placeholderStart == -1)
            {
                break;
            }
            builder.append(template.substring(templateStart, placeholderStart));
            builder.append(args[i++]);
            templateStart = placeholderStart + 2;
        }
        builder.append(template.substring(templateStart));

        // if we run out of placeholders, append the extra args in square braces
        if (i < args.length)
        {
            builder.append(" [");
            builder.append(args[i++]);
            while (i < args.length)
            {
                builder.append(", ");
                builder.append(args[i++]);
            }
            builder.append(']');
        }

        return builder.toString();
    }


}
TOP

Related Classes of org.apache.webbeans.util.WebBeansUtil

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.