001package ball.util.ant.taskdefs;
002/*-
003 * ##########################################################################
004 * Utilities
005 * %%
006 * Copyright (C) 2008 - 2022 Allen D. Ball
007 * %%
008 * Licensed under the Apache License, Version 2.0 (the "License");
009 * you may not use this file except in compliance with the License.
010 * You may obtain a copy of the License at
011 *
012 *      http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing, software
015 * distributed under the License is distributed on an "AS IS" BASIS,
016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017 * See the License for the specific language governing permissions and
018 * limitations under the License.
019 * ##########################################################################
020 */
021import java.lang.annotation.Annotation;
022import java.lang.reflect.AnnotatedElement;
023import java.lang.reflect.Field;
024import java.lang.reflect.Method;
025import java.util.ArrayList;
026import java.util.Collections;
027import java.util.HashSet;
028import org.apache.commons.lang3.ClassUtils;
029import org.apache.commons.lang3.reflect.FieldUtils;
030import org.apache.commons.lang3.reflect.MethodUtils;
031import org.apache.tools.ant.Task;
032import org.apache.tools.ant.TaskConfigurationChecker;
033import lombok.ToString;
034
035import static ball.beans.PropertyMethodEnum.getPropertyName;
036
037/**
038 * {@link TaskConfigurationChecker} implmentation to check
039 * {@link AnnotatedAntTask} annotations.
040 *
041 * @author {@link.uri mailto:ball@hcf.dev Allen D. Ball}
042 */
043@ToString
044public class AnnotatedAntTaskConfigurationChecker extends TaskConfigurationChecker {
045    private final Task task;
046
047    /**
048     * Sole constructor.
049     *
050     * @param   task            The Ant {@link Task}.
051     */
052    public AnnotatedAntTaskConfigurationChecker(Task task) {
053        super(task);
054
055        this.task = task;
056
057        HashSet<Class<?>> set = new HashSet<>();
058
059        set.add(task.getClass());
060        set.addAll(ClassUtils.getAllSuperclasses(task.getClass()));
061        set.addAll(ClassUtils.getAllInterfaces(task.getClass()));
062
063        for (Class<?> type : set) {
064            ArrayList<AnnotatedElement> list = new ArrayList<>();
065
066            Collections.addAll(list, type.getDeclaredFields());
067            Collections.addAll(list, type.getDeclaredMethods());
068
069            for (AnnotatedElement element : list) {
070                for (Annotation annotation : element.getAnnotations()) {
071                    AntTaskAttributeConstraint constraint =
072                        annotation.annotationType().getAnnotation(AntTaskAttributeConstraint.class);
073
074                    if (constraint != null) {
075                        assertConfig(constraint, element);
076                    }
077                }
078            }
079        }
080    }
081
082    private void assertConfig(AntTaskAttributeConstraint constraint, AnnotatedElement element) {
083        try {
084            String name = null;
085            Object value = null;
086
087            if (element instanceof Field) {
088                name = ((Field) element).getName();
089                value = FieldUtils.readField((Field) element, task, true);
090            } else if (element instanceof Method) {
091                name = getPropertyName((Method) element);
092                value = MethodUtils.invokeMethod(task, true, ((Method) element).getName(), new Object[] {  });
093            } else {
094                throw new IllegalStateException(String.valueOf(element));
095            }
096
097            constraint.value()
098                .getDeclaredConstructor().newInstance()
099                .check(task, this, name, value);
100        } catch (Exception exception) {
101            fail(exception.toString());
102        }
103    }
104}