001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements. See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache license, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License. You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the license for the specific language governing permissions and
015     * limitations under the license.
016     */
017    package org.apache.logging.log4j.core.config.plugins.validation;
018    
019    import java.lang.annotation.Annotation;
020    import java.lang.reflect.ParameterizedType;
021    import java.lang.reflect.Type;
022    import java.util.ArrayList;
023    import java.util.Collection;
024    
025    import org.apache.logging.log4j.core.util.ReflectionUtil;
026    
027    /**
028     * Utility class to locate an appropriate {@link ConstraintValidator} implementation for an annotation.
029     *
030     * @since 2.1
031     */
032    public final class ConstraintValidators {
033    
034        private ConstraintValidators() {
035        }
036    
037        /**
038         * Finds all relevant {@link ConstraintValidator} objects from an array of annotations. All validators will be
039         * {@link ConstraintValidator#initialize(java.lang.annotation.Annotation) initialized} before being returned.
040         *
041         * @param annotations the annotations to find constraint validators for
042         * @return a collection of ConstraintValidators for the given annotations
043         */
044        public static Collection<ConstraintValidator<?>> findValidators(final Annotation... annotations) {
045            final Collection<ConstraintValidator<?>> validators =
046                new ArrayList<ConstraintValidator<?>>();
047            for (final Annotation annotation : annotations) {
048                final Class<? extends Annotation> type = annotation.annotationType();
049                if (type.isAnnotationPresent(Constraint.class)) {
050                    final ConstraintValidator<?> validator = getValidator(annotation, type);
051                    if (validator != null) {
052                        validators.add(validator);
053                    }
054                }
055            }
056            return validators;
057        }
058    
059        private static <A extends Annotation> ConstraintValidator<A> getValidator(final A annotation,
060                                                                                  final Class<? extends A> type) {
061            final Constraint constraint = type.getAnnotation(Constraint.class);
062            final Class<? extends ConstraintValidator<?>> validatorClass = constraint.value();
063            if (type.equals(getConstraintValidatorAnnotationType(validatorClass))) {
064                @SuppressWarnings("unchecked") // I don't think we could be any more thorough in validation here
065                final ConstraintValidator<A> validator = (ConstraintValidator<A>)
066                    ReflectionUtil.instantiate(validatorClass);
067                validator.initialize(annotation);
068                return validator;
069            }
070            return null;
071        }
072    
073        private static Type getConstraintValidatorAnnotationType(final Class<? extends ConstraintValidator<?>> type) {
074            for (final Type parentType : type.getGenericInterfaces()) {
075                if (parentType instanceof ParameterizedType) {
076                    final ParameterizedType parameterizedType = (ParameterizedType) parentType;
077                    if (ConstraintValidator.class.equals(parameterizedType.getRawType())) {
078                        return parameterizedType.getActualTypeArguments()[0];
079                    }
080                }
081            }
082            return Void.TYPE;
083        }
084    }