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