001////////////////////////////////////////////////////////////////////////////////
002// checkstyle: Checks Java source code for adherence to a set of rules.
003// Copyright (C) 2001-2017 the original author or authors.
004//
005// This library is free software; you can redistribute it and/or
006// modify it under the terms of the GNU Lesser General Public
007// License as published by the Free Software Foundation; either
008// version 2.1 of the License, or (at your option) any later version.
009//
010// This library is distributed in the hope that it will be useful,
011// but WITHOUT ANY WARRANTY; without even the implied warranty of
012// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013// Lesser General Public License for more details.
014//
015// You should have received a copy of the GNU Lesser General Public
016// License along with this library; if not, write to the Free Software
017// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
018////////////////////////////////////////////////////////////////////////////////
019
020package com.puppycrawl.tools.checkstyle.utils;
021
022import java.io.IOException;
023import java.lang.reflect.Modifier;
024import java.util.Collection;
025import java.util.Set;
026import java.util.stream.Collectors;
027
028import com.google.common.reflect.ClassPath;
029import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
030import com.puppycrawl.tools.checkstyle.api.AbstractFileSetCheck;
031import com.puppycrawl.tools.checkstyle.api.AutomaticBean;
032import com.puppycrawl.tools.checkstyle.api.BeforeExecutionFileFilter;
033import com.puppycrawl.tools.checkstyle.api.Filter;
034import com.puppycrawl.tools.checkstyle.api.RootModule;
035
036/**
037 * Contains utility methods for module reflection.
038 * @author LuoLiangchen
039 */
040public final class ModuleReflectionUtils {
041
042    /** Prevent instantiation. */
043    private ModuleReflectionUtils() {
044    }
045
046    /**
047     * Gets checkstyle's modules (directly, not recursively) in the given packages.
048     * @param packages the collection of package names to use
049     * @param loader the class loader used to load Checkstyle package names
050     * @return the set of checkstyle's module classes
051     * @throws IOException if the attempt to read class path resources failed
052     * @see #isCheckstyleModule(Class)
053     */
054    public static Set<Class<?>> getCheckstyleModules(
055            Collection<String> packages, ClassLoader loader) throws IOException {
056        final ClassPath classPath = ClassPath.from(loader);
057        return packages.stream()
058                .flatMap(pkg -> classPath.getTopLevelClasses(pkg).stream())
059                .map(ClassPath.ClassInfo::load)
060                .filter(ModuleReflectionUtils::isCheckstyleModule)
061                .collect(Collectors.toSet());
062    }
063
064    /**
065     * Checks whether a class may be considered as a checkstyle module. Checkstyle's modules are
066     * non-abstract classes, which are either checkstyle's checks, file sets, filters, file filters,
067     * or root module.
068     * @param clazz class to check.
069     * @return true if the class may be considered as the checkstyle module.
070     */
071    public static boolean isCheckstyleModule(Class<?> clazz) {
072        return isValidCheckstyleClass(clazz)
073            && (isCheckstyleCheck(clazz)
074                    || isFileSetModule(clazz)
075                    || isFilterModule(clazz)
076                    || isFileFilterModule(clazz)
077                    || isRootModule(clazz));
078    }
079
080    /**
081     * Checks whether a class extends 'AutomaticBean' and is non-abstract.
082     * @param clazz class to check.
083     * @return true if a class may be considered a valid production class.
084     */
085    public static boolean isValidCheckstyleClass(Class<?> clazz) {
086        return AutomaticBean.class.isAssignableFrom(clazz)
087                && !Modifier.isAbstract(clazz.getModifiers());
088    }
089
090    /**
091     * Checks whether a class may be considered as the checkstyle check.
092     * Checkstyle's checks are classes which implement 'AbstractCheck' interface.
093     * @param clazz class to check.
094     * @return true if a class may be considered as the checkstyle check.
095     */
096    public static boolean isCheckstyleCheck(Class<?> clazz) {
097        return AbstractCheck.class.isAssignableFrom(clazz);
098    }
099
100    /**
101     * Checks whether a class may be considered as the checkstyle file set.
102     * Checkstyle's file sets are classes which implement 'AbstractFileSetCheck' interface.
103     * @param clazz class to check.
104     * @return true if a class may be considered as the checkstyle file set.
105     */
106    public static boolean isFileSetModule(Class<?> clazz) {
107        return AbstractFileSetCheck.class.isAssignableFrom(clazz);
108    }
109
110    /**
111     * Checks whether a class may be considered as the checkstyle filter.
112     * Checkstyle's filters are classes which implement 'Filter' interface.
113     * @param clazz class to check.
114     * @return true if a class may be considered as the checkstyle filter.
115     */
116    public static boolean isFilterModule(Class<?> clazz) {
117        return Filter.class.isAssignableFrom(clazz);
118    }
119
120    /**
121     * Checks whether a class may be considered as the checkstyle file filter.
122     * Checkstyle's file filters are classes which implement 'BeforeExecutionFileFilter' interface.
123     * @param clazz class to check.
124     * @return true if a class may be considered as the checkstyle file filter.
125     */
126    public static boolean isFileFilterModule(Class<?> clazz) {
127        return BeforeExecutionFileFilter.class.isAssignableFrom(clazz);
128    }
129
130    /**
131     * Checks whether a class may be considered as the checkstyle root module.
132     * Checkstyle's root modules are classes which implement 'RootModule' interface.
133     * @param clazz class to check.
134     * @return true if a class may be considered as the checkstyle root module.
135     */
136    public static boolean isRootModule(Class<?> clazz) {
137        return RootModule.class.isAssignableFrom(clazz);
138    }
139}