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.lang.annotation.Annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.WildcardType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import javax.annotation.Named;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.context.ApplicationScoped;
import javax.context.Conversation;
import javax.context.ConversationScoped;
import javax.context.RequestScoped;
import javax.context.ScopeType;
import javax.context.SessionScoped;
import javax.decorator.Decorator;
import javax.ejb.EnterpriseBean;
import javax.event.Fires;
import javax.event.Observes;
import javax.faces.component.UIComponent;
import javax.inject.DeploymentType;
import javax.inject.Disposes;
import javax.inject.DuplicateBindingTypeException;
import javax.inject.InconsistentSpecializationException;
import javax.inject.Initializer;
import javax.inject.New;
import javax.inject.NullableDependencyException;
import javax.inject.Produces;
import javax.inject.UnproxyableDependencyException;
import javax.inject.manager.Bean;
import javax.inject.manager.Interceptor;
import javax.inject.manager.Manager;
import javax.interceptor.AroundInvoke;
import javax.interceptor.InvocationContext;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceContextType;
import javax.persistence.PersistenceUnit;
import javax.servlet.Filter;
import javax.servlet.Servlet;
import javax.servlet.ServletContextListener;
import javax.servlet.ServletRequestListener;
import javax.servlet.http.HttpSessionListener;

import org.apache.webbeans.annotation.CurrentLiteral;
import org.apache.webbeans.annotation.DependentScopeLiteral;
import org.apache.webbeans.annotation.NewLiteral;
import org.apache.webbeans.annotation.ProductionLiteral;
import org.apache.webbeans.annotation.RequestedScopeLiteral;
import org.apache.webbeans.annotation.StandardLiteral;
import org.apache.webbeans.component.AbstractComponent;
import org.apache.webbeans.component.Component;
import org.apache.webbeans.component.ComponentImpl;
import org.apache.webbeans.component.ConversationComponent;
import org.apache.webbeans.component.ManagerComponentImpl;
import org.apache.webbeans.component.NewComponentImpl;
import org.apache.webbeans.component.ObservableComponentImpl;
import org.apache.webbeans.component.WebBeansType;
import org.apache.webbeans.config.DefinitionUtil;
import org.apache.webbeans.config.EJBWebBeansConfigurator;
import org.apache.webbeans.config.SimpleWebBeansConfigurator;
import org.apache.webbeans.container.ManagerImpl;
import org.apache.webbeans.decorator.DecoratorUtil;
import org.apache.webbeans.decorator.DecoratorsManager;
import org.apache.webbeans.decorator.WebBeansDecoratorConfig;
import org.apache.webbeans.deployment.DeploymentTypeManager;
import org.apache.webbeans.deployment.StereoTypeManager;
import org.apache.webbeans.deployment.stereotype.IStereoTypeModel;
import org.apache.webbeans.ejb.EJBUtil;
import org.apache.webbeans.ejb.orm.ORMUtil;
import org.apache.webbeans.event.EventUtil;
import org.apache.webbeans.exception.WebBeansConfigurationException;
import org.apache.webbeans.exception.WebBeansException;
import org.apache.webbeans.intercept.InterceptorData;
import org.apache.webbeans.intercept.InterceptorDataImpl;
import org.apache.webbeans.intercept.InterceptorType;
import org.apache.webbeans.intercept.InterceptorUtil;
import org.apache.webbeans.intercept.InterceptorsManager;
import org.apache.webbeans.intercept.WebBeansInterceptorConfig;
import org.apache.webbeans.intercept.webbeans.WebBeansInterceptor;
import org.apache.webbeans.jsf.ConversationImpl;

/**
* Contains some utility methods used in the all project.
*
* @author <a href="mailto:gurkanerdogdu@yahoo.com">Gurkan Erdogdu</a>
* @since 1.0
*/
public final class WebBeansUtil
{
    // No instantiate
    private WebBeansUtil()
    {
        throw new UnsupportedOperationException();
    }

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

    /**
     * Return true if the given class is ok for simple web bean conditions,
     * falase otherwise.
     *
     * @param clazz class in hand
     * @return true if the given class is ok for simple web bean conditions.
     */
    public static void isSimpleWebBeanClass(Class<?> clazz)
    {
        try
        {
            Asserts.nullCheckForClass(clazz);
            int modifier = clazz.getModifiers();

            if (ClassUtil.isParametrized(clazz))
                throw new WebBeansConfigurationException("Web Beans component implementation class : " + clazz.getName() + " can not be parametrized type");

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

            if (!ClassUtil.isConcrete(clazz) && !AnnotationUtil.isAnnotationExistOnClass(clazz, Decorator.class))
                throw new WebBeansConfigurationException("Web Beans component implementation class : " + clazz.getName() + " have to be concrete if not defines as @Decorator");

            if (AnnotationUtil.isAnnotationExistOnClass(clazz, Entity.class))
                throw new WebBeansConfigurationException("Web Beans component implementation class : " + clazz.getName() + " can not be JPA Entity class");

            if (EJBUtil.isEJBClass(clazz))
                throw new WebBeansConfigurationException("Web Beans component implementation class : " + clazz.getName() + " can not be EJB class");

            if (ClassUtil.isAssignable(Servlet.class, clazz))
                throw new WebBeansConfigurationException("Web Beans component implementation class : " + clazz.getName() + " can not implement Servlet interface");

            if (ClassUtil.isAssignable(Filter.class, clazz))
                throw new WebBeansConfigurationException("Web Beans component implementation class : " + clazz.getName() + " can not implement Filter interface");

            if (ClassUtil.isAssignable(ServletContextListener.class, clazz))
                throw new WebBeansConfigurationException("Web Beans component implementation class : " + clazz.getName() + " can not implement ServletContextListener");

            if (ClassUtil.isAssignable(HttpSessionListener.class, clazz))
                throw new WebBeansConfigurationException("Web Beans component implementation class : " + clazz.getName() + " can not implement HttpSessionListener");

            if (ClassUtil.isAssignable(ServletRequestListener.class, clazz))
                throw new WebBeansConfigurationException("Web Beans component implementation class : " + clazz.getName() + " can notimplement ServletRequestListener");

            if (ClassUtil.isAssignable(EnterpriseBean.class, clazz))
                throw new WebBeansConfigurationException("Web Beans component implementation class : " + clazz.getName() + " can not implement EnterpriseBean");

            if (ClassUtil.isAssignable(UIComponent.class, clazz))
                throw new WebBeansConfigurationException("Web Beans component implementation class : " + clazz.getName() + " can not implement JSF UIComponent");

            // TODO ejb-jar.xml check
            if (EJBUtil.isDefinedInXML(clazz.getName()))
                throw new WebBeansConfigurationException("Web Beans component implementation class : " + clazz.getName() + " can not defined in the ejb-jar.xml");

            // TODO orm.xml check
            if (ORMUtil.isDefinedInXML(clazz.getName()))
                throw new WebBeansConfigurationException("Web Beans component implementation class : " + clazz.getName() + " can not defined in orm.xml");

            if (!isConstructureOk(clazz))
                throw new WebBeansConfigurationException("Web Beans component implementation class : " + clazz.getName() + " must define at least one Constructor");

        }
        catch (WebBeansConfigurationException e)
        {
            throw e;
        }
    }

    public static <T> Constructor<T> defineConstructor(Class<T> clazz) throws WebBeansConfigurationException
    {
        Asserts.nullCheckForClass(clazz);
        Constructor<T> result = null;
        Constructor<T>[] constructors = ClassUtil.getConstructors(clazz);

        boolean inAnnotation = false;
        int j = 0;

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

        if (result != null)
        {
            Type[] observableTypes = AnnotationUtil.getConstructorParameterGenericTypesWithGivenAnnotation(result, Fires.class);
            EventUtil.checkObservableMethodParameterConditions(observableTypes, "constructor parameter", "constructor : " + result.getName() + "in class : " + clazz.getName());

            Annotation[][] parameterAnns = result.getParameterAnnotations();
            for (Annotation[] parameters : parameterAnns)
            {
                for (Annotation param : parameters)
                {
                    Annotation btype = param.annotationType().getAnnotation(Disposes.class);
                    if (btype != null)
                    {
                        throw new WebBeansConfigurationException("Constructor parameter binding type annotation can not be @Disposes annotation in class " + clazz.getName());
                    }
                    else
                    {
                        btype = param.annotationType().getAnnotation(Observes.class);
                        if (btype != null)
                        {
                            throw new WebBeansConfigurationException("Constructor parameter binding type annotation can not be @Observes annotation in class " + clazz.getName());
                        }
                    }
                }

            }
        }

        if (result == null)
        {
            if ((result = ClassUtil.isContaintNoArgConstructor(clazz)) != null)
            {
                return result;
            }
            else
            {
                throw new WebBeansConfigurationException("No constructor is found for the 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 static boolean isConstructureOk(Class<?> clazz) throws WebBeansConfigurationException
    {
        Asserts.nullCheckForClass(clazz);

        if (ClassUtil.isContaintNoArgConstructor(clazz) != null)
        {
            return true;
        }

        Constructor<?>[] constructors = ClassUtil.getConstructors(clazz);

        int j = 0;

        for (Constructor<?> constructor : constructors)
        {
            j++;
            if (constructor.getAnnotation(Initializer.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");

        Type returnType = method.getGenericReturnType();
        if (returnType instanceof ParameterizedType)
        {
            ParameterizedType pType = (ParameterizedType) returnType;

            Type[] actualArguments = pType.getActualTypeArguments();

            for (Type actualType : actualArguments)
            {
                if ((actualType instanceof TypeVariable) || (actualType instanceof WildcardType))
                {
                    throw new WebBeansConfigurationException("Producer method  : " + method.getName() + " in the class : " + parentImplClazzName + " can not return TypeVariable or WildcardType return type arguments.");
                }
            }
        }

        if (AnnotationUtil.isMethodHasAnnotation(method, Initializer.class) || AnnotationUtil.isMethodParameterAnnotationExist(method, Disposes.class) || AnnotationUtil.isMethodParameterAnnotationExist(method, Observes.class))
        {
            throw new WebBeansConfigurationException("Producer method : " + method.getName() + " in the class : " + parentImplClazzName + " can not be annotated with" + " @Initializer/@Destructor annotation or has a parameter annotated with @Disposes/@Observes");
        }
    }

    public static void checkProducerMethodDisposal(Method disposalMethod, String parentImplClazzName)
    {
        Type[] observableTypes = AnnotationUtil.getMethodParameterGenericTypesWithGivenAnnotation(disposalMethod, Fires.class);
        EventUtil.checkObservableMethodParameterConditions(observableTypes, "method parameter", "method : " + disposalMethod.getName() + "in class : " + parentImplClazzName);

        if (AnnotationUtil.isMethodMultipleParameterAnnotationExist(disposalMethod, Disposes.class))
        {
            throw new WebBeansConfigurationException("Disposal method : " + disposalMethod.getName() + " in class " + parentImplClazzName + " has multiple @Disposes annotation parameter");
        }

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

    }

    /**
     * Check conditions for the new binding.
     *
     * @param annotations annotations
     * @return Annotation[] with all binding annotations
     * @throws WebBeansConfigurationException if &x0040;New plus any other binding annotation is set or
     *         if &x0040;New is used for an Interface or an abstract class.
     */
    public static Annotation[] checkForNewBindingForDeployment(Type type, Class<?> clazz, String name, Annotation[] annotations)
    {
        Asserts.assertNotNull(type, "Type argument can not be null");
        Asserts.assertNotNull(clazz, "Clazz argument can not be null");
        Asserts.assertNotNull(annotations, "Annotations argument can not be null");

        Annotation[] as = AnnotationUtil.getBindingAnnotations(annotations);
        for (Annotation a : annotations)
        {
            if (a.annotationType().equals(New.class))
            {
                if (as.length > 1)
                {
                    throw new WebBeansConfigurationException("@New binding annotation can not have any binding annotation in class : " + clazz.getName() + " in field/method : " + name);
                }

                if (ClassUtil.isAbstract(ClassUtil.getClass(type).getModifiers()) || ClassUtil.isInterface(ClassUtil.getClass(type).getModifiers()))
                {
                    throw new WebBeansConfigurationException("@New binding annotation field can not have interface or abstract type in class : " + clazz.getName() + " in field/method : " + name);
                }
            }
        }
       
        return as;
    }

    /**
     * Check conditions for the resources.
     *
     * @param annotations annotations
     * @return Annotation[] with all binding annotations
     * @throws WebBeansConfigurationException if resource annotations exists and do not fit to the fields type, etc.
     * @see AnnotationUtil#isResourceAnnotation(Class)
     */
    public static Annotation[] checkForValidResources(Type type, Class<?> clazz, String name, Annotation[] annotations)
    {
        Asserts.assertNotNull(type, "Type argument can not be null");
        Asserts.assertNotNull(clazz, "Clazz argument can not be null");
        Asserts.assertNotNull(annotations, "Annotations argument can not be null");

        Annotation[] as = AnnotationUtil.getResourceAnnotations(annotations);
        for (Annotation a : annotations)
        {
            if (a.annotationType().equals(PersistenceUnit.class))
            {
                if (!type.equals(EntityManagerFactory.class))
                {
                    throw new WebBeansConfigurationException("@PersistenceUnit must only be injected into field with type EntityManagerFactory! class : " 
                                                             + clazz.getName() + " in field/method : " + name);
                }
            }
           
            if (a.annotationType().equals(PersistenceContext.class))
            {
                PersistenceContext pc = (PersistenceContext) a;
               
                if (!type.equals(EntityManager.class))
                {
                    throw new WebBeansConfigurationException("@PersistenceContext must only be injected into field with type EntityManager! class : " 
                                                             + clazz.getName() + " in field/method : " + name);
                }
            
                if (pc.type().equals(PersistenceContextType.EXTENDED))
                {
                    throw new WebBeansConfigurationException("type of @PersistenceContext must not be 'EXTENDED'! class : " 
                            + clazz.getName() + " in field/method : " + name);
                   
                }
            }
        }
               
        //X TODO add checks for other resources
        return as;
    }
   
    /**
     * Returns true if src scope encloses the target.
     *
     * @param src src scope
     * @param target target scope
     * @return true if src scope encloses the target
     */
    public static boolean isScopeEncloseOther(Class<? extends Annotation> src, Class<? extends Annotation> target)
    {
        Asserts.assertNotNull(src, "Src argument can not be null");
        Asserts.assertNotNull(target, "Target argument can not be null");

        if (src.equals(ConversationScoped.class))
        {
            return true;
        }
        else if (src.equals(ApplicationScoped.class))
        {
            if (target.equals(ConversationScoped.class) || (target.equals(ApplicationScoped.class)))
            {
                return false;
            }
            else
            {
                return true;
            }

        }
        else if (src.equals(SessionScoped.class))
        {
            if (target.equals(ConversationScoped.class) || target.equals(ApplicationScoped.class) || target.equals(SessionScoped.class))
            {
                return false;
            }
            else
            {
                return true;
            }

        }
        else if (src.equals(RequestScoped.class))
        {
            return false;
        }
        else
        {
            throw new WebBeansException("Scope is not correct");
        }

    }

    /**
     * New WebBeans component class.
     *
     * @param <T>
     * @param clazz impl. class
     * @return the new component
     */
    public static <T> NewComponentImpl<T> createNewComponent(Class<T> clazz)
    {
        Asserts.assertNotNull(clazz, "Clazz argument can not be null");

        NewComponentImpl<T> comp = null;

        if (SimpleWebBeansConfigurator.isSimpleWebBean(clazz))
        {
            comp = new NewComponentImpl<T>(clazz, WebBeansType.SIMPLE);
            comp.setConstructor(WebBeansUtil.defineConstructor(clazz));

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

        comp.setImplScopeType(new DependentScopeLiteral());
        comp.addBindingType(new NewLiteral());
        comp.setName(null);
        comp.addApiType(clazz);
        comp.addApiType(Object.class);
        comp.setType(new ProductionLiteral());

        return comp;
    }

    public static <T, K> ObservableComponentImpl<T, K> createObservableImplicitComponent(Class<T> returnType, Class<K> eventType, Annotation... annotations)
    {
        ObservableComponentImpl<T, K> component = new ObservableComponentImpl<T, K>(returnType, eventType, WebBeansType.OBSERVABLE);

        DefinitionUtil.defineApiTypes(component, returnType);
        DefinitionUtil.defineBindingTypes(component, annotations);

        Constructor<T> constructor = null;

        try
        {
            constructor = returnType.getConstructor(new Class<?>[] { Annotation[].class, Class.class });

        }
        catch (SecurityException e)
        {
            throw new WebBeansException("Security exception for getting EventImpl class constructor", e);

        }
        catch (NoSuchMethodException e)
        {
            throw new WebBeansException("No constructor found in EventImpl class", e);
        }

        component.setConstructor(constructor);
        component.setType(new StandardLiteral());
        component.setImplScopeType(new DependentScopeLiteral());

        return component;
    }

    public static ManagerComponentImpl getManagerComponent()
    {
        ManagerComponentImpl managerComponent = new ManagerComponentImpl();

        managerComponent.setImplScopeType(new DependentScopeLiteral());
        managerComponent.setType(new StandardLiteral());
        managerComponent.addBindingType(new CurrentLiteral());
        managerComponent.addApiType(Manager.class);
        managerComponent.addApiType(Object.class);

        return managerComponent;
    }

    public static ConversationComponent getConversationComponent()
    {
        ConversationComponent conversationComp = new ConversationComponent();

        conversationComp.addApiType(Conversation.class);
        conversationComp.addApiType(ConversationImpl.class);
        conversationComp.addApiType(Object.class);
        conversationComp.setImplScopeType(new RequestedScopeLiteral());
        conversationComp.setType(new StandardLiteral());
        conversationComp.addBindingType(new CurrentLiteral());

        return conversationComp;
    }

    /**
     * Check the {@link PostConstruct} or {@link PreDestroy} annotated method
     * criterias, and return post construct or pre destroy method.
     * <p>
     * Web Beans container is responsible for setting the post construct or pre
     * destroy 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
     * @return post construct or predestroy method
     */
    public static Method checkCommonAnnotationCriterias(Class<?> clazz, Class<? extends Annotation> commonAnnotation, boolean invocationContext)
    {
        Asserts.assertNotNull(clazz, "Clazz argument can not be null");

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

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

                    // Check method criterias
                    if (ClassUtil.isMethodHasParameter(method))
                    {
                        if (!invocationContext)
                            throw new WebBeansConfigurationException("@" + commonAnnotation.getSimpleName() + " annotated method : " + method.getName() + " in class : " + clazz.getName() + " can not take any formal arguments");
                        else
                        {
                            // 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");

                        }
                    }

                    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 (ClassUtil.isMethodHasCheckedException(method))
                    {
                        throw new WebBeansConfigurationException("@" + commonAnnotation.getSimpleName() + " annotated method : " + method.getName() + " in class : " + clazz.getName() + " can not throw any checked exception");
                    }

                    if (ClassUtil.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)
    {
        Asserts.assertNotNull(clazz, "Clazz argument can not be null");

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

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

                    // Check method criterias
                    Class<?>[] params = ClassUtil.getMethodParameterTypes(method);
                    if (params.length != 1 || !params[0].equals(InvocationContext.class))
                        throw new WebBeansConfigurationException("@" + AroundInvoke.class.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("@" + AroundInvoke.class.getSimpleName() + " annotated method : " + method.getName() + " in class : " + clazz.getName() + " must return Object type");
                    }

                    if (!ClassUtil.isMethodHasException(method))
                    {
                        throw new WebBeansConfigurationException("@" + AroundInvoke.class.getSimpleName() + " annotated method : " + method.getName() + " in class : " + clazz.getName() + " must throw Exception");
                    }

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

        return result;
    }

    /**
     * Configures the interceptor stack of the web beans component.
     *
     * @param clazz interceptor class
     * @param annotation annotation type
     * @param definedInInterceptorClass check if annotation is defined in
     *            interceptor 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 isDefinedWithWebBeans if interceptor is defined with WebBeans
     *            spec, not EJB spec
     */
    public static void configureInterceptorMethods(Interceptor webBeansInterceptor, Class<?> clazz, Class<? extends Annotation> annotation, boolean definedInInterceptorClass, boolean definedInMethod, List<InterceptorData> stack, Method annotatedInterceptorClassMethod, boolean isDefinedWithWebBeans)
    {
        InterceptorData intData = null;
        Method method = null;

        if (annotation.equals(AroundInvoke.class))
        {
            method = WebBeansUtil.checkAroundInvokeAnnotationCriterias(clazz);
        }
        else if (annotation.equals(PostConstruct.class))
        {
            if (definedInInterceptorClass)
            {
                method = WebBeansUtil.checkCommonAnnotationCriterias(clazz, PostConstruct.class, true);
            }
            else
            {
                method = WebBeansUtil.checkCommonAnnotationCriterias(clazz, PostConstruct.class, false);
            }
        }
        else if (annotation.equals(PreDestroy.class))
        {
            if (definedInInterceptorClass)
            {
                method = WebBeansUtil.checkCommonAnnotationCriterias(clazz, PreDestroy.class, true);
            }
            else
            {
                method = WebBeansUtil.checkCommonAnnotationCriterias(clazz, PreDestroy.class, false);
            }
        }

        if (method != null)
        {
            intData = new InterceptorDataImpl(isDefinedWithWebBeans);
            intData.setDefinedInInterceptorClass(definedInInterceptorClass);
            intData.setDefinedInMethod(definedInMethod);
            intData.setAnnotatedMethod(annotatedInterceptorClassMethod);
            intData.setWebBeansInterceptor(webBeansInterceptor);

            if (definedInInterceptorClass)
            {
                try
                {
                    if (isDefinedWithWebBeans)
                    {
                        Object interceptorProxy = ManagerImpl.getManager().getInstance(webBeansInterceptor);
                        WebBeansInterceptor interceptor = (WebBeansInterceptor) webBeansInterceptor;
                        interceptor.setInjections(interceptorProxy);

                        intData.setInterceptorInstance(interceptorProxy);
                    }
                    else
                    {
                        if (ClassUtil.isContaintNoArgConstructor(clazz) == null)
                        {
                            throw new WebBeansConfigurationException("Interceptor class : " + clazz.getName() + " must have no-arg constructor");
                        }

                        intData.setInterceptorInstance(clazz.newInstance());
                    }

                }
                catch (WebBeansConfigurationException e1)
                {
                    throw e1;
                }
                catch (Exception e)
                {
                    throw new WebBeansException(e);
                }
            }

            intData.setInterceptor(method, annotation);

            stack.add(intData);
        }
    }

    /**
     * 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, InterceptorType type)
    {
        Iterator<InterceptorData> it = stack.iterator();
        while (it.hasNext())
        {
            Method m = null;
            InterceptorData data = it.next();

            if (type.equals(InterceptorType.AROUND_INVOKE))
            {
                m = data.getAroundInvoke();
            }
            else if (type.equals(InterceptorType.POST_CONSTRUCT))
            {
                m = data.getPostConstruct();

            }
            else if (type.equals(InterceptorType.PRE_DESTROY))
            {
                m = data.getPreDestroy();
            }

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

        }

        return false;
    }

    /**
     * Gets list of interceptors with the given type.
     *
     * @param stack interceptor stack
     * @param type interceptor type
     * @return list of interceptor
     */
    @SuppressWarnings("unchecked")
    public static List<InterceptorData> getInterceptorMethods(List<InterceptorData> stack, InterceptorType type)
    {
        List<InterceptorData> ai = new ArrayList<InterceptorData>();
        List<InterceptorData> pc = new ArrayList<InterceptorData>();
        List<InterceptorData> pd = new ArrayList<InterceptorData>();

        Iterator<InterceptorData> it = stack.iterator();
        while (it.hasNext())
        {
            Method m = null;
            InterceptorData data = it.next();

            if (type.equals(InterceptorType.AROUND_INVOKE))
            {
                m = data.getAroundInvoke();
                if (m != null)
                {
                    ai.add(data);
                }

            }
            else if (type.equals(InterceptorType.POST_CONSTRUCT))
            {
                m = data.getPostConstruct();
                if (m != null)
                {
                    pc.add(data);
                }

            }
            else if (type.equals(InterceptorType.PRE_DESTROY))
            {
                m = data.getPreDestroy();
                if (m != null)
                {
                    pd.add(data);
                }

            }

        }

        if (type.equals(InterceptorType.AROUND_INVOKE))
        {
            return ai;
        }
        else if (type.equals(InterceptorType.POST_CONSTRUCT))
        {
            return pc;

        }
        else if (type.equals(InterceptorType.PRE_DESTROY))
        {
            return pd;
        }

        return Collections.EMPTY_LIST;
    }

    /**
     * Returns true if array contains the StereoType meta annotation
     *
     * @param anns annotation array
     * @return true if array contains the StereoType meta annotation
     */
    public static boolean isComponentHasStereoType(Component<?> component)
    {
        Asserts.assertNotNull(component, "component parameter can not be null");

        Set<Annotation> set = component.getStereotypes();
        Annotation[] anns = new Annotation[set.size()];
        anns = set.toArray(anns);
        if (AnnotationUtil.isStereoTypeMetaAnnotationExist(anns))
        {
            return true;
        }

        return false;
    }

    public static Annotation[] getComponentStereoTypes(Component<?> component)
    {
        Asserts.assertNotNull(component, "component parameter can not be null");
        if (isComponentHasStereoType(component))
        {
            Set<Annotation> set = component.getStereotypes();
            Annotation[] anns = new Annotation[set.size()];
            anns = set.toArray(anns);

            return AnnotationUtil.getStereotypeMetaAnnotations(anns);
        }

        return new Annotation[] {};
    }

    public static boolean isNamedExistOnStereoTypes(Component<?> component)
    {
        Annotation[] types = getComponentStereoTypes(component);

        for (Annotation ann : types)
        {
            if (AnnotationUtil.isAnnotationExistOnClass(ann.annotationType(), Named.class))
            {
                return true;
            }
        }

        return false;
    }

    public static Annotation getMaxPrecedenceSteroTypeDeploymentType(Component<?> component)
    {
        Annotation[] deploymentTypes = getComponentStereoTypes(component);
        Class<? extends Annotation> maxPrecedDeploymentType = null;
        Annotation result = null;
        if (deploymentTypes.length > 0)
        {
            for (Annotation dt : deploymentTypes)
            {
                if (AnnotationUtil.isMetaAnnotationExist(dt.annotationType().getAnnotations(), DeploymentType.class))
                {
                    Annotation result2[] = AnnotationUtil.getMetaAnnotations(dt.annotationType().getAnnotations(), DeploymentType.class);

                    Class<? extends Annotation> dtAnnot = result2[0].getClass();
                    if (maxPrecedDeploymentType == null)
                    {
                        maxPrecedDeploymentType = dtAnnot;
                        result = result2[0];
                    }
                    else
                    {
                        if (DeploymentTypeManager.getInstance().comparePrecedences(maxPrecedDeploymentType, dtAnnot) < 0)
                        {
                            maxPrecedDeploymentType = dtAnnot;
                            result = result2[0];
                        }
                    }
                }

            }
        }

        if (result == null)
        {
            return new ProductionLiteral();

        }

        return result;
    }

    public static String getSimpleWebBeanDefaultName(String clazzName)
    {
        StringBuffer name = new StringBuffer(clazzName);
        name.setCharAt(0, Character.toLowerCase(name.charAt(0)));

        return name.toString();
    }

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

        if (buffer.substring(0, 3).equals("get"))
        {
            buffer.setCharAt(3, Character.toLowerCase(buffer.charAt(3)));

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

    public static void checkStereoTypeClass(Class<?> clazz)
    {
        Asserts.nullCheckForClass(clazz);

        Annotation[] annotations = clazz.getAnnotations();

        boolean deploymentTypeFound = false;
        boolean scopeTypeFound = false;
        for (Annotation annotation : annotations)
        {
            Class<? extends Annotation> annotType = annotation.annotationType();

            if (annotType.isAnnotationPresent(DeploymentType.class))
            {
                if (deploymentTypeFound == true)
                {
                    throw new WebBeansConfigurationException("@StereoType annotation can not contain more than one @DeploymentType annotation");
                }
                else
                {
                    deploymentTypeFound = true;
                }
            }
            else if (annotType.isAnnotationPresent(ScopeType.class))
            {
                if (scopeTypeFound == true)
                {
                    throw new WebBeansConfigurationException("@StereoType annotation can not contain more than one @ScopeType annotation");
                }
                else
                {
                    scopeTypeFound = true;
                }
            }
            else if (annotType.equals(Named.class))
            {
                Named name = (Named) annotation;
                if (!name.value().equals(""))
                {
                    throw new WebBeansConfigurationException("@StereoType annotation can not define @Named annotation with value");
                }
            }
            else if (AnnotationUtil.isBindingAnnotation(annotType))
            {
                throw new WebBeansConfigurationException("@StereoType annotation can not define @BindingType annotation");
            }
            else if (AnnotationUtil.isInterceptorBindingAnnotation(annotType))
            {
                Target target = clazz.getAnnotation(Target.class);
                ElementType[] type = target.value();

                if (type.length != 1 && !type[0].equals(ElementType.TYPE))
                {
                    throw new WebBeansConfigurationException("Stereotype with @InterceptorBindingType must be defined as @Target{TYPE}");
                }

            }
        }
    }

    public static void configureSpecializations(Class<?> clazz)
    {
        Asserts.nullCheckForClass(clazz);

        Bean<?> parent = null;
        Bean<?> child = null;
        if ((parent = isConfiguredWebBeans(clazz)) != null)
        {
            Class<?> superClass = clazz.getSuperclass();
            if ((child = isConfiguredWebBeans(superClass)) != null)
            {
                int res = DeploymentTypeManager.getInstance().comparePrecedences(parent.getDeploymentType(), child.getDeploymentType());
                if (res <= 0)
                {
                    throw new InconsistentSpecializationException("@Specializes exception. Class : " + clazz.getName() + " must have higher deployment type precedence from the class : " + superClass.getName());
                }
                parent.getBindings().addAll(child.getBindings());
            }
            else
            {
                throw new WebBeansConfigurationException("@Specializes exception. WebBean component class : " + clazz.getName() + " does not extends other WebBeans it specialize");
            }
        }

    }

    public static Bean<?> isConfiguredWebBeans(Class<?> clazz)
    {
        Asserts.nullCheckForClass(clazz);

        Set<Bean<?>> components = ManagerImpl.getManager().getComponents();
        Iterator<Bean<?>> it = components.iterator();

        while (it.hasNext())
        {
            Bean<?> bean = it.next();
            if (bean.getTypes().contains(clazz))
            {
                return bean;
            }
        }

        return null;
    }

    public static void checkSteroTypeRequirements(Component<?> component, Annotation[] anns, String errorMessage)
    {
        Annotation[] stereoTypes = getComponentStereoTypes(component);
        for (Annotation stereoType : stereoTypes)
        {
            IStereoTypeModel model = StereoTypeManager.getInstance().getStereoTypeModel(stereoType.annotationType().getName());
            Set<Class<?>> rtypes = model.getRestrictedTypes();

            if (rtypes != null)
            {
                Iterator<Class<?>> itTypes = rtypes.iterator();
                while (itTypes.hasNext())
                {
                    if (!component.getTypes().contains(itTypes.next()))
                    {
                        throw new WebBeansConfigurationException(errorMessage + " must contains all supported api types in the @Stereotype annotation " + model.getName());

                    }
                }
            }

            Set<Class<? extends Annotation>> suppScopes = model.getSupportedScopes();
            if (suppScopes != null)
            {
                if (!suppScopes.isEmpty())
                {
                    if (!suppScopes.contains(component.getScopeType()))
                    {
                        throw new WebBeansConfigurationException(errorMessage + " must contains all required scope types in the @Stereotype annotation " + model.getName());
                    }
                }
            }
        }
    }

    public static void checkUnproxiableApiType(Bean<?> bean, ScopeType scopeType)
    {
        Asserts.assertNotNull("bean", "bean parameter can not be null");
        Asserts.assertNotNull(scopeType, "scopeType parameter can not be null");

        Set<Class<?>> types = bean.getTypes();
        Class<?> superClass = null;
        for (Class<?> type : types)
        {
            if (!type.isInterface())
            {
                if ((superClass == null) || (superClass.isAssignableFrom(type) && type != Object.class))
                {
                    superClass = type;
                }

            }
        }

        if (superClass != null)
        {
            Constructor<?> cons = ClassUtil.isContaintNoArgConstructor(superClass);

            if (ClassUtil.isPrimitive(superClass) || ClassUtil.isArray(superClass) || ClassUtil.isFinal(superClass.getModifiers()) || ClassUtil.hasFinalMethod(superClass) || (cons == null || ClassUtil.isPrivate(cons.getModifiers())))
            {
                if (scopeType.normal())
                {
                    throw new UnproxyableDependencyException("WebBeans with api type with normal scope must be proxiable to inject, but class : " + superClass.getName() + " is not proxiable type");
                }
            }

        }

    }

    public static void checkNullable(Class<?> type, AbstractComponent<?> component)
    {
        Asserts.assertNotNull(type, "type parameter can not be null");
        Asserts.assertNotNull(component, "component parameter can not be null");

        if (type.isPrimitive())
        {
            if (component.isNullable())
            {
                throw new NullableDependencyException("Injection point for primitive type resolves webbeans component with return type : " + component.getReturnType().getName() + " with nullable");
            }
        }
    }

    public static void configureProducerSpecialization(AbstractComponent<?> 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.isAnnotationExist(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");
        }

        Annotation[] anns = AnnotationUtil.getBindingAnnotations(superMethod.getAnnotations());

        for (Annotation ann : anns)
        {
            component.addBindingType(ann);
        }
    }

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

        Type[] observableTypes = AnnotationUtil.getMethodParameterGenericTypesWithGivenAnnotation(method, Fires.class);
        EventUtil.checkObservableMethodParameterConditions(observableTypes, "method parameter", "method : " + method.getName() + "in class : " + clazz.getName());

        if (AnnotationUtil.isMethodParameterAnnotationExist(method, Disposes.class) || AnnotationUtil.isMethodParameterAnnotationExist(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");

        }

    }

    public static void checkInterceptorResolverParams(Annotation... interceptorBindingTypes)
    {
        if (interceptorBindingTypes == null || interceptorBindingTypes.length == 0)
        {
            throw new IllegalArgumentException("Manager.resolveInterceptors() method parameter interceptor binding types array argument can not be empty");
        }

        Annotation old = null;
        for (Annotation interceptorBindingType : interceptorBindingTypes)
        {
            if (old == null)
            {
                old = interceptorBindingType;
            }
            else
            {
                if (old.equals(interceptorBindingType))
                {
                    throw new DuplicateBindingTypeException("Manager.resolveInterceptors() method parameter interceptor binding types array argument can not define duplicate binding annotation with name : @" + old.getClass().getName());
                }

                if (!AnnotationUtil.isInterceptorBindingAnnotation(interceptorBindingType.annotationType()))
                {
                    throw new IllegalArgumentException("Manager.resolveInterceptors() method parameter interceptor binding types array can not contain other annotation that is not @InterceptorBindingType");
                }

                old = interceptorBindingType;
            }
        }
    }

    public static void checkDecoratorResolverParams(Set<Class<?>> apiTypes, Annotation... bindingTypes)
    {
        if (apiTypes == null || apiTypes.size() == 0)
        {
            throw new IllegalArgumentException("Manager.resolveDecorators() method parameter api types argument can not be empty");
        }

        Annotation old = null;
        for (Annotation bindingType : bindingTypes)
        {
            if (old == null)
            {
                old = bindingType;
            }
            else
            {
                if (old.annotationType().equals(bindingType.annotationType()))
                {
                    throw new DuplicateBindingTypeException("Manager.resolveDecorators() method parameter binding types array argument can not define duplicate binding annotation with name : @" + old.getClass().getName());
                }

                if (!AnnotationUtil.isBindingAnnotation(bindingType.annotationType()))
                {
                    throw new IllegalArgumentException("Manager.resolveDecorators() method parameter binding types array can not contain other annotation that is not @BindingType");
                }

                old = bindingType;
            }
        }

    }

    public static <T> void checkObservableFieldsConditions(Class<T> clazz)
    {
        Asserts.nullCheckForClass(clazz);

        Field[] candidateFields = AnnotationUtil.getClazzFieldsWithGivenAnnotation(clazz, Fires.class);

        for (Field candidateField : candidateFields)
        {
            EventUtil.checkObservableFieldConditions(candidateField.getGenericType(), candidateField.getName(), clazz.getName());
        }

    }

    public static <T> void checkPassivationScope(AbstractComponent<T> component, ScopeType scope)
    {
        Asserts.assertNotNull(component, "component parameter can not be null");
        Asserts.assertNotNull(scope, "scope type parameter can not be null");

        boolean passivating = scope.passivating();
        Class<T> clazz = component.getReturnType();

        if (passivating)
        {
            if (!component.isSerializable())
            {
                throw new WebBeansConfigurationException("WebBeans component implementation class : " + clazz.getName() + " with passivating scope @" + scope.annotationType().getName() + " must be Serializable");
            }
        }
    }

    @SuppressWarnings("unchecked")
    public static <T> void defineSimpleWebBeansInterceptors(Class<T> clazz)
    {
        if (InterceptorsManager.getInstance().isInterceptorEnabled(clazz))
        {
            ComponentImpl<T> component = null;

            InterceptorUtil.checkInterceptorConditions(clazz);
            component = SimpleWebBeansConfigurator.define(clazz, WebBeansType.INTERCEPTOR);

            if (component != null)
            {
                WebBeansInterceptorConfig.configureInterceptorClass((ComponentImpl<Object>) component, clazz.getDeclaredAnnotations());
            }
        }

    }

    @SuppressWarnings("unchecked")
    public static <T> void defineSimpleWebBeansDecorators(Class<T> clazz)
    {
        if (DecoratorsManager.getInstance().isDecoratorEnabled(clazz))
        {
            ComponentImpl<T> component = null;

            DecoratorUtil.checkDecoratorConditions(clazz);
            component = SimpleWebBeansConfigurator.define(clazz, WebBeansType.DECORATOR);

            if (component != null)
            {
                WebBeansDecoratorConfig.configureDecoratorClass((ComponentImpl<Object>) component);
            }
        }
    }

    public static boolean isScopeTypeNormal(Class<? extends Annotation> scopeType)
    {
        Asserts.assertNotNull(scopeType, "scopeType argument can not be null");

        if (scopeType.isAnnotationPresent(ScopeType.class))
        {
            ScopeType scope = scopeType.getAnnotation(ScopeType.class);
            if (scope.normal())
            {
                return true;
            }

            else
            {
                return false;
            }
        }
        else
        {
            throw new IllegalArgumentException("scopeType argument must be annotated with @ScopeType");
        }
    }
   
}
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.