/*
 * 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.logging.log4j.core.config.plugins.validation;

import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Collection;

import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.status.StatusLogger;

/**
 * Utility class to locate an appropriate {@link ConstraintValidator} implementation for an annotation.
 *
 * @since 2.1
 */
public final class ConstraintValidators {

    private static final Logger LOGGER = StatusLogger.getLogger();

    private ConstraintValidators() {
    }

    /**
     * Finds all relevant {@link ConstraintValidator} objects from an array of annotations. All validators will be
     * {@link ConstraintValidator#initialize(java.lang.annotation.Annotation) initialized} before being returned.
     *
     * @param annotations the annotations to find constraint validators for
     * @return a collection of ConstraintValidators for the given annotations
     */
    public static Collection<ConstraintValidator<Annotation, Object>> findValidators(
        final Annotation... annotations) {
        final Collection<ConstraintValidator<Annotation, Object>> validators =
            new ArrayList<ConstraintValidator<Annotation, Object>>();
        for (final Annotation annotation : annotations) {
            final Constraint constraint = annotation.annotationType().getAnnotation(Constraint.class);
            if (constraint != null) {
                final ConstraintValidator<Annotation, Object> validator = getValidatorFor(annotation, constraint);
                if (validator != null) {
                    validators.add(validator);
                }
            }
        }
        return validators;
    }

    private static ConstraintValidator<Annotation, Object> getValidatorFor(final Annotation annotation,
                                                                           final Constraint constraint) {
        try {
            // TODO: may want to cache these validator instances
            @SuppressWarnings("unchecked")
            final ConstraintValidator<Annotation, Object> validator =
                (ConstraintValidator<Annotation, Object>) constraint.value().newInstance();
            validator.initialize(annotation);
            return validator;
        } catch (final Exception e) {
            LOGGER.error("Error loading ConstraintValidator [{}].", constraint.value(), e);
            return null;
        }
    }
}

@@ -900,16 +900,91 @@
 tation;%0A
+import java.lang.reflect.ParameterizedType;%0Aimport java.lang.reflect.Type;%0A
 import j
@@ -1069,67 +1069,32 @@
 g4j.
-Logger;%0Aimport org.apache.logging.log4j.status.StatusLogger
+core.util.ReflectionUtil
 ;%0A%0A/
@@ -1268,76 +1268,8 @@
  %7B%0A%0A
-    private static final Logger LOGGER = StatusLogger.getLogger();%0A%0A
     
@@ -1763,34 +1763,17 @@
 lidator%3C
-Annotation, Object
+?
 %3E%3E findV
@@ -1782,25 +1782,16 @@
 idators(
-%0A        
 final An
@@ -1862,34 +1862,17 @@
 lidator%3C
-Annotation, Object
+?
 %3E%3E valid
@@ -1925,34 +1925,17 @@
 lidator%3C
-Annotation, Object
+?
 %3E%3E();%0A  
@@ -2009,36 +2009,47 @@
  final C
-onstraint constraint
+lass%3C? extends Annotation%3E type
  = annot
@@ -2074,12 +2074,33 @@
 pe()
-.get
+;%0A            if (type.is
 Anno
@@ -2105,16 +2105,23 @@
 notation
+Present
 (Constra
@@ -2134,44 +2134,8 @@
 ass)
-;%0A            if (constraint != null
 ) %7B%0A
@@ -2176,34 +2176,17 @@
 lidator%3C
-Annotation, Object
+?
 %3E valida
@@ -2203,19 +2203,16 @@
 alidator
-For
 (annotat
@@ -2216,26 +2216,20 @@
 tation, 
-constraint
+type
 );%0A     
@@ -2405,16 +2405,39 @@
 e static
+ %3CA extends Annotation%3E
  Constra
@@ -2450,33 +2450,16 @@
 idator%3CA
-nnotation, Object
 %3E getVal
@@ -2468,19 +2468,16 @@
 ator
-For
 (final A
 nnot
@@ -2468,33 +2468,24 @@
 ator(final A
-nnotation
  annotation,
@@ -2564,563 +2564,1216 @@
     
-final Constraint constraint) %7B%0A        try %7B%0A            // TODO: may want to cache these validator instances%0A            @SuppressWarnings(%22unchecked%22)%0A            final ConstraintValidator%3CAnnotation, Object%3E validator =%0A                (ConstraintValidator%3CAnnotation, Object%3E) constraint.value().newInstance();%0A            validator.initialize(annotation);%0A            return validator;%0A        %7D catch (final Exception e) %7B%0A            LOGGER.error(%22Error loading ConstraintValidator %5B%7B%7D%5D.%22, constraint.value(), e);%0A            return null;%0A        %7D
+   final Class%3C? extends A%3E type) %7B%0A        final Constraint constraint = type.getAnnotation(Constraint.class);%0A        final Class%3C? extends ConstraintValidator%3C?%3E%3E validatorClass = constraint.value();%0A        if (type.equals(getConstraintValidatorAnnotationType(validatorClass))) %7B%0A            @SuppressWarnings(%22unchecked%22) // I don't think we could be any more thorough in validation here%0A            final ConstraintValidator%3CA%3E validator = (ConstraintValidator%3CA%3E)%0A                ReflectionUtil.instantiate(validatorClass);%0A            validator.initialize(annotation);%0A            return validator;%0A        %7D%0A        return null;%0A    %7D%0A%0A    private static Type getConstraintValidatorAnnotationType(final Class%3C? extends ConstraintValidator%3C?%3E%3E type) %7B%0A        for (final Type parentType : type.getGenericInterfaces()) %7B%0A            if (parentType instanceof ParameterizedType) %7B%0A                final ParameterizedType parameterizedType = (ParameterizedType) parentType;%0A                if (ConstraintValidator.class.equals(parameterizedType.getRawType())) %7B%0A                    return parameterizedType.getActualTypeArguments()%5B0%5D;%0A                %7D%0A            %7D%0A        %7D%0A        return Void.TYPE;
 %0A   

Drop unnecessary type param and improve type safety.