Package org.apache.webbeans.annotation

Source Code of org.apache.webbeans.annotation.AnnotationManager

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

import org.apache.webbeans.component.AbstractOwbBean;
import org.apache.webbeans.component.OwbBean;
import org.apache.webbeans.config.WebBeansContext;
import org.apache.webbeans.container.BeanManagerImpl;
import org.apache.webbeans.exception.WebBeansConfigurationException;
import org.apache.webbeans.exception.inject.DefinitionException;
import org.apache.webbeans.util.AnnotationUtil;
import org.apache.webbeans.util.ArrayUtil;
import org.apache.webbeans.util.Asserts;
import org.apache.webbeans.util.WebBeansUtil;

import javax.enterprise.context.NormalScope;
import javax.enterprise.inject.Default;
import javax.enterprise.inject.Disposes;
import javax.enterprise.inject.New;
import javax.enterprise.inject.Stereotype;
import javax.enterprise.inject.spi.AnnotatedMethod;
import javax.enterprise.inject.spi.AnnotatedParameter;
import javax.enterprise.inject.spi.AnnotatedType;
import javax.enterprise.inject.spi.InjectionPoint;
import javax.enterprise.util.Nonbinding;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Qualifier;
import javax.inject.Scope;
import javax.interceptor.InterceptorBinding;

import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
* Manages annotation usage by classes in this application.
*/
public final class AnnotationManager
{

    private final BeanManagerImpl beanManagerImpl;
    private final WebBeansContext webBeansContext;

    // No instantiate

    public AnnotationManager(WebBeansContext context)
    {
        webBeansContext = context;
        beanManagerImpl = context.getBeanManagerImpl();
    }

    /**
     * Returns true if the annotation is defined in xml or annotated with
     * {@link javax.interceptor.InterceptorBinding} or an InterceptorBinding
     * registered via {@link javax.enterprise.inject.spi.BeforeBeanDiscovery}.
     * False otherwise.
     *
     * @param clazz type of the annotation
     * @return true if the annotation is defined in xml or annotated with
     *         {@link javax.interceptor.InterceptorBinding}, false otherwise
     */
    public boolean isInterceptorBindingAnnotation(Class<? extends Annotation> clazz)
    {
        Asserts.nullCheckForClass(clazz);

        return clazz.isAnnotationPresent(InterceptorBinding.class)
               || beanManagerImpl.hasInterceptorBindingType(clazz);
    }



    /**
     * If any Annotations in the input is an interceptor binding annotation type then return
     * true, false otherwise.
     *
     * @param anns array of Annotations to check
     * @return true if one or moe of the input annotations are an interceptor binding annotation
     *         type false otherwise
     */
    public boolean hasInterceptorBindingMetaAnnotation(Annotation[] anns)
    {
        Asserts.assertNotNull(anns, "anns parameter can not be null");

        for (Annotation ann : anns)
        {
            if (isInterceptorBindingAnnotation(ann.annotationType()))
            {
                return true;
            }
            else
            {
                continue;
            }
        }

        return false;
    }

    /**
     * Collect the interceptor bindings from an array of annotations, including
     * transitively defined interceptor bindings.
     * @param anns An array of annotations
     * @return an array of interceptor binding annotations, including the input and any transitively declared annotations
     */
    public Annotation[] getInterceptorBindingMetaAnnotations(Annotation[] anns)
    {
        Asserts.assertNotNull(anns, "anns parameter can not be null");
        List<Annotation> interAnns = new ArrayList<Annotation>();

        for (Annotation ann : anns)
        {
            if (isInterceptorBindingAnnotation(ann.annotationType()))
            {
                interAnns.add(ann);

                //check for transitive
                Annotation[] transitives = getTransitiveInterceptorBindings(ann.annotationType().getDeclaredAnnotations());

                for(Annotation transitive : transitives)
                {
                    interAnns.add(transitive);
                }

            }
        }

        Annotation[] ret = new Annotation[interAnns.size()];
        ret = interAnns.toArray(ret);

        return ret;
    }

    private Annotation[] getTransitiveInterceptorBindings(Annotation[] anns)
    {
        return getInterceptorBindingMetaAnnotations(anns);
    }

    /**
     * Returns true if the annotation is defined in xml or annotated with
     * {@link javax.inject.Qualifier} false otherwise.
     *
     * @param clazz type of the annotation
     * @return true if the annotation is defined in xml or annotated with
     *         {@link javax.inject.Qualifier} false otherwise
     */
    public boolean isQualifierAnnotation(Class<? extends Annotation> clazz)
    {
        Asserts.nullCheckForClass(clazz);
        if (clazz.isAnnotationPresent(Qualifier.class))
        {
            return true;
        }
        else if(beanManagerImpl.getAdditionalQualifiers().contains(clazz))
        {
            return true;
        }

        return false;
    }

    public <X> Annotation[] getAnnotatedMethodFirstParameterQualifierWithGivenAnnotation(
            AnnotatedMethod<X> annotatedMethod, Class<? extends Annotation> clazz)
    {
        Asserts.assertNotNull(annotatedMethod, "annotatedMethod argument can not be null");
        Asserts.nullCheckForClass(clazz);

        List<Annotation> list = new ArrayList<Annotation>();
        List<AnnotatedParameter<X>> parameters = annotatedMethod.getParameters();
        for(AnnotatedParameter<X> parameter : parameters)
        {
            if(parameter.isAnnotationPresent(clazz))
            {
                Annotation[] anns = AnnotationUtil.getAnnotationsFromSet(parameter.getAnnotations());
                for(Annotation ann : anns)
                {
                    if(isQualifierAnnotation(ann.annotationType()))
                    {
                        list.add(ann);
                    }
                }
            }
        }

        Annotation[] finalAnns = new Annotation[list.size()];
        finalAnns = list.toArray(finalAnns);

        return finalAnns;
    }


    /**
     * Gets the method first found parameter qualifiers.
     *
     * @param method method
     * @param clazz checking annotation
     * @return annotation array
     */
    public Annotation[] getMethodFirstParameterQualifierWithGivenAnnotation(Method method, Class<? extends Annotation> clazz)
    {
        Asserts.assertNotNull(method, "Method argument can not be null");
        Asserts.nullCheckForClass(clazz);

        Annotation[][] parameterAnns = method.getParameterAnnotations();
        List<Annotation> list = new ArrayList<Annotation>();
        Annotation[] result;

        for (Annotation[] parameters : parameterAnns)
        {
            boolean found = false;
            for (Annotation param : parameters)
            {
                Class<? extends Annotation> btype = param.annotationType();
                if (btype.equals(clazz))
                {
                    found = true;
                    continue;
                }

                if (isQualifierAnnotation(btype))
                {
                    list.add(param);
                }

            }

            if (found)
            {
                result = new Annotation[list.size()];
                result = list.toArray(result);
                return result;
            }
        }
        result = new Annotation[0];
        return result;
    }

    /**
     * Gets the array of qualifier annotations on the given array.
     *
     * @param annotations annotation array
     * @return array containing qualifier anns
     */
    public Annotation[] getQualifierAnnotations(Annotation... annotations)
    {
        Asserts.assertNotNull(annotations, "Annotations argument can not be null");

        Set<Annotation> set = new HashSet<Annotation>();

        for (Annotation annot : annotations)
        {
            if (isQualifierAnnotation(annot.annotationType()))
            {
                set.add(annot);
            }
        }

        //Add the default qualifier if no others exist.  Section 3.10, OWB-142///
        if(set.size() == 0)
        {
            set.add(new DefaultLiteral());
        }
        ////////////////////////////////////////////////////////////////////////

        Annotation[] a = new Annotation[set.size()];
        a = set.toArray(a);

        return a;
    }


    /**
     * If the bean extends generic class via Realizes
     * annotation, realized based producer methods, fields and observer
     * methods qualifier is
     *
     * <ul>
     <li>Qualifiers on the definitions</li>
     <li>Plus class qualifiers</li>
     <li>Minus generic class qualifiers</li>
     * </ul>
     *
     * @param clazz realized definition class
     * @param anns binding annotations array
     */
    public Annotation[] getRealizesGenericAnnotations(Class<?> clazz, Annotation[] anns)
    {
       Set<Annotation> setAnnots = new HashSet<Annotation>();

        for(Annotation definedAnn : anns)
        {
            setAnnots.add(definedAnn);
        }

        Annotation[] genericReliazesAnns = getQualifierAnnotations(clazz.getSuperclass().getDeclaredAnnotations());

        for(Annotation generic : genericReliazesAnns)
        {
            setAnnots.remove(generic);
        }

        genericReliazesAnns = getQualifierAnnotations(clazz.getDeclaredAnnotations());

        for(Annotation generic : genericReliazesAnns)
        {
            setAnnots.add(generic);
        }

        Annotation[] annots = new Annotation[setAnnots.size()];
        annots = setAnnots.toArray(annots);

        return annots;
    }

    public void checkQualifierConditions(Annotation... qualifierAnnots)
    {
        Set<Annotation> annSet = ArrayUtil.asSet(qualifierAnnots);

        //check for duplicate annotations
        if (qualifierAnnots.length != annSet.size())
        {
            throw new IllegalArgumentException("Qualifier annotations can not contain duplicate qualifiers:"
                                               + Arrays.toString(qualifierAnnots));
        }

        checkQualifierConditions(annSet);
    }

    /**
     * This function obviously cannot check for duplicate annotations.
     * So this must have been done before!
     * @param qualifierAnnots
     */
    public void checkQualifierConditions(Set<Annotation> qualifierAnnots)
    {
        for (Annotation ann : qualifierAnnots)
        {
            checkQualifierConditions(ann);
        }
    }

    private void checkQualifierConditions(Annotation ann)
    {
        Method[] methods = webBeansContext.getSecurityService().doPrivilegedGetDeclaredMethods(ann.annotationType());

        for (Method method : methods)
        {
            Class<?> clazz = method.getReturnType();
            if (clazz.isArray() || clazz.isAnnotation())
            {
                if (!AnnotationUtil.hasAnnotation(method.getDeclaredAnnotations(), Nonbinding.class))
                {
                    throw new WebBeansConfigurationException("@Qualifier : " + ann.annotationType().getName()
                                                             + " must have @NonBinding valued members for its array-valued and annotation valued members");
                }
            }
        }

        if (!isQualifierAnnotation(ann.annotationType()))
        {
            throw new IllegalArgumentException("Qualifier annotations must be annotated with @Qualifier");
        }
    }

    /**
     * Returns true if the annotation is defined in xml or annotated with
     * {@link javax.enterprise.inject.Stereotype} false otherwise.
     *
     * @param clazz type of the annotation
     * @return true if the annotation is defined in xml or annotated with
     *         {@link javax.enterprise.inject.Stereotype} false otherwise
     */
    public boolean isStereoTypeAnnotation(Class<? extends Annotation> clazz)
    {
        Asserts.nullCheckForClass(clazz);

        return clazz.isAnnotationPresent(Stereotype.class);
    }

    public boolean hasStereoTypeMetaAnnotation(Annotation[] anns)
    {
        Asserts.assertNotNull(anns, "anns parameter can not be null");

        for (Annotation ann : anns)
        {
            if (isStereoTypeAnnotation(ann.annotationType()))
            {
                return true;
            }
            else
            {
                continue;
            }
        }

        return false;
    }

    public Annotation[] getStereotypeMetaAnnotations(Annotation[] anns)
    {
        Asserts.assertNotNull(anns, "anns parameter can not be null");
        List<Annotation> interAnns = new ArrayList<Annotation>();

        for (Annotation ann : anns)
        {
            if (isStereoTypeAnnotation(ann.annotationType()))
            {
                interAnns.add(ann);

                //check for transitive
                Annotation[] transitives = getTransitiveStereoTypes(ann.annotationType().getDeclaredAnnotations());

                for(Annotation transitive : transitives)
                {
                    interAnns.add(transitive);
                }
            }
        }

        Annotation[] ret = new Annotation[interAnns.size()];
        ret = interAnns.toArray(ret);

        return ret;
    }

    private Annotation[] getTransitiveStereoTypes(Annotation[] anns)
    {
        return getStereotypeMetaAnnotations(anns);
    }

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

        Set<Annotation> set = component.getOwbStereotypes();
        Annotation[] anns = new Annotation[set.size()];
        anns = set.toArray(anns);
        return hasStereoTypeMetaAnnotation(anns);
    }

    /**
     * Returns bean stereotypes.
     * @param bean bean instance
     * @return bean stereotypes
     */
    public Annotation[] getComponentStereoTypes(OwbBean<?> bean)
    {
        Asserts.assertNotNull(bean, "bean parameter can not be null");
        if (isComponentHasStereoType(bean))
        {
            Set<Annotation> set = bean.getOwbStereotypes();
            Annotation[] anns = new Annotation[set.size()];
            anns = set.toArray(anns);

            return getStereotypeMetaAnnotations(anns);
        }

        return new Annotation[] {};
    }

    /**
     * Returns true if name exists,false otherwise.
     * @param bean bean instance
     * @return true if name exists
     */
    public boolean hasNamedOnStereoTypes(OwbBean<?> bean)
    {
        Annotation[] types = getComponentStereoTypes(bean);

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

        return false;
    }

    /**
     * Validates that given class obeys stereotype model
     * defined by the specification.
     * @param clazz stereotype class
     */
    public void checkStereoTypeClass(Class<? extends Annotation> clazz)
    {
        checkStereoTypeClass(clazz, clazz.getDeclaredAnnotations());
    }

    /**
     * Validates that given class obeys stereotype model
     * defined by the specification.
     * @param clazz stereotype class
     */
    public void checkStereoTypeClass(Class<? extends Annotation> clazz, Annotation...annotations)
    {
        Asserts.nullCheckForClass(clazz);

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

            if (annotType.isAnnotationPresent(NormalScope.class) || annotType.isAnnotationPresent(Scope.class))
            {
                if (scopeTypeFound)
                {
                    throw new WebBeansConfigurationException("@StereoType annotation can not contain more " +
                            "than one @Scope/@NormalScope 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 (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 @InterceptorBinding must be " +
                            "defined as @Target{TYPE}");
                }

            }
        }
    }

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

        Annotation old = null;
        for (Annotation interceptorBinding : interceptorBindings)
        {
            if (!isInterceptorBindingAnnotation(interceptorBinding.annotationType()))
            {
                throw new IllegalArgumentException("Manager.resolveInterceptors() method parameter interceptor" +
                        " bindings array can not contain other annotation that is not @InterceptorBinding");
            }

            if (old == null)
            {
                old = interceptorBinding;
            }
            else
            {
                if (old.equals(interceptorBinding))
                {
                    throw new IllegalArgumentException("Manager.resolveInterceptors() method parameter interceptor " +
                            "bindings array argument can not define duplicate binding annotation with name : @" +
                            old.getClass().getName());
                }

                old = interceptorBinding;
            }
        }
    }

    public void checkDecoratorResolverParams(Set<Type> apiTypes, Annotation... qualifiers)
    {
        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 qualifier : qualifiers)
        {
            if (!isQualifierAnnotation(qualifier.annotationType()))
            {
                throw new IllegalArgumentException("Manager.resolveDecorators() method parameter qualifiers array " +
                        "can not contain other annotation that is not @Qualifier");
            }
            if (old == null)
            {
                old = qualifier;
            }
            else
            {
                if (old.annotationType().equals(qualifier.annotationType()))
                {
                    throw new IllegalArgumentException("Manager.resolveDecorators() method parameter qualifiers " +
                            "array argument can not define duplicate qualifier annotation with name : @" +
                            old.annotationType().getName());
                }

                old = qualifier;
            }
        }

    }


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

        Annotation[] as = getQualifierAnnotations(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);
                }
            }
        }

        return as;
    }

    /**
     * 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)
    {
        Asserts.assertNotNull(component,"component parameter can not be null");
        Asserts.assertNotNull(method,"method parameter can not be null");
        Asserts.assertNotNull(superMethod,"superMethod parameter can not be null");

        String name = null;
        boolean hasName = false;
        if(AnnotationUtil.hasMethodAnnotation(superMethod, Named.class))
        {
            Named named =  superMethod.getAnnotation(Named.class);
            hasName = true;
            if(!named.value().equals(""))
            {
                name = named.value();
            }
            else
            {
                name = WebBeansUtil.getProducerDefaultName(superMethod.getName());
            }
        }
        else
        {
            Annotation[] anns = getStereotypeMetaAnnotations(superMethod.getAnnotations());
            for(Annotation ann : anns)
            {
                if(ann.annotationType().isAnnotationPresent(Stereotype.class))
                {
                    hasName = true;
                    name = WebBeansUtil.getProducerDefaultName(superMethod.getName());
                    break;
                }
            }
        }

        if(hasName)
        {
            if(AnnotationUtil.hasMethodAnnotation(method, Named.class))
            {
                throw new DefinitionException("Specialized method : " + method.getName() + " in class : "
                        + component.getReturnType().getName() + " may not define @Named annotation");
            }

            component.setName(name);
        }

        return hasName;
//        else
//        {
//            component.setName(name);
//        }

    }

    @SuppressWarnings("unchecked")
    public <X> Method getDisposalWithGivenAnnotatedMethod(AnnotatedType<X> annotatedType, Type beanType, Annotation[] qualifiers)
    {
        Set<AnnotatedMethod<? super X>> annotatedMethods = annotatedType.getMethods();

        if(annotatedMethods != null)
        {
            for (AnnotatedMethod<? super X> annotatedMethod : annotatedMethods)
            {
                AnnotatedMethod<X> annt = (AnnotatedMethod<X>)annotatedMethod;
                List<AnnotatedParameter<X>> parameters = annt.getParameters();
                if(parameters != null)
                {
                    boolean found = false;
                    for(AnnotatedParameter<X> parameter : parameters)
                    {
                        if(parameter.isAnnotationPresent(Disposes.class))
                        {
                            found = true;
                            break;
                        }
                    }

                    if(found)
                    {
                        Type type = AnnotationUtil.getAnnotatedMethodFirstParameterWithAnnotation(annotatedMethod, Disposes.class);
                        Annotation[] annots = getAnnotatedMethodFirstParameterQualifierWithGivenAnnotation(annotatedMethod, Disposes.class);

                        if(type.equals(beanType))
                        {
                            for(Annotation qualifier : qualifiers)
                            {
                                if(qualifier.annotationType() != Default.class)
                                {
                                    for(Annotation ann :annots)
                                    {
                                        if(!AnnotationUtil.isQualifierEqual(qualifier, ann))
                                        {
                                            return null;
                                        }
                                        else
                                        {
                                            break;
                                        }
                                    }
                                }
                            }

                            return annotatedMethod.getJavaMember();
                        }
                    }
                }
            }
        }
        return null;

    }

    /**
     * JavaEE components can not inject {@link javax.enterprise.inject.spi.InjectionPoint}.
     * @param clazz javaee component class info
     * @throws WebBeansConfigurationException exception if condition is not applied
     */
    public void checkInjectionPointForInjectInjectionPoint(Class<?> clazz)
    {
        Asserts.nullCheckForClass(clazz);
        Field[] fields = webBeansContext.getSecurityService().doPrivilegedGetDeclaredFields(clazz);
        for(Field field : fields)
        {
            if(field.getAnnotation(Inject.class) != null)
            {
                if(field.getType() == InjectionPoint.class)
                {
                    Annotation[] anns = getQualifierAnnotations(field.getDeclaredAnnotations());
                    if (AnnotationUtil.hasAnnotation(anns, Default.class))
                    {
                        throw new WebBeansConfigurationException("Java EE Component class :  " + clazz + " can not inject InjectionPoint");
                    }
                }
            }
        }
    }

    /**
     * Returns trur for serializable types.
     * @param clazz class info
     * @return true if class is serializable
     */
    public boolean checkInjectionPointForInterceptorPassivation(Class<?> clazz)
    {
        Asserts.nullCheckForClass(clazz);
        Field[] fields = webBeansContext.getSecurityService().doPrivilegedGetDeclaredFields(clazz);
        for(Field field : fields)
        {
            if(field.getAnnotation(Inject.class) != null)
            {
                Class<?> type = field.getType();
                if(!Serializable.class.isAssignableFrom(type))
                {
                    return false;
                }
            }
        }

        return true;
    }
}
TOP

Related Classes of org.apache.webbeans.annotation.AnnotationManager

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.