All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.revelc.code.warbucks.maven.plugin.RuleProcessor Maven / Gradle / Ivy

/*
 * 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 net.revelc.code.warbucks.maven.plugin;

import java.io.File;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Collection;
import java.util.function.Predicate;
import java.util.regex.Pattern;

import org.apache.maven.artifact.DependencyResolutionRequiredException;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.logging.Log;

import com.google.common.reflect.ClassPath;
import com.google.common.reflect.ClassPath.ClassInfo;

class RuleProcessor {

  private final Rule rule;
  private final String logPrefix;
  private final Log log;
  private final CheckMojo mojo;

  RuleProcessor(CheckMojo mojo, Rule rule, int n) {
    this.mojo = mojo;
    this.rule = rule;

    this.log = mojo.getLog();
    this.logPrefix = "Rule " + n + ": ";
  }

  private void debug(String s) {
    log.debug(logPrefix + s);
  }

  private void error(String s) {
    log.error(logPrefix + s);
  }

  private void warn(String s) {
    log.warn(logPrefix + s);
  }

  private void info(String s) {
    log.info(logPrefix + s);
  }

  // returns the number of rule failures
  long process() throws MojoExecutionException {
    debug("Begin processing");
    try (URLClassLoader cl = new URLClassLoader(getURLs(mojo.project.getTestClasspathElements()))) {
      long failures = ClassPath.from(cl).getAllClasses().stream().filter(isProjectClass()).filter(matchesClassPattern())
          .filter(hasRequiredAnnotation().negate()).count();
      info("Class Failures: " + failures);
      return failures;
    } catch (IOException | DependencyResolutionRequiredException e) {
      throw new MojoExecutionException("Problem loading classes", e);
    }
  }

  // verifies that the class is part of this project, and not included in the classloader as a dependency
  private Predicate isProjectClass() {
    String mainDir = mojo.project.getBuild().getOutputDirectory();
    String testDir = mojo.project.getBuild().getTestOutputDirectory();
    return x -> {
      boolean foundMainClass = rule.getIncludeMainClasses() && new File(mainDir, x.getResourceName()).exists();
      boolean foundTestClass = !foundMainClass && rule.getIncludeTestClasses() && new File(testDir, x.getResourceName()).exists();
      if (foundMainClass) {
        debug("Found '" + x.getName() + "' in " + mainDir);
      } else if (foundTestClass) {
        debug("Found '" + x.getName() + "' in " + testDir);
      }
      return foundMainClass || foundTestClass;
    };
  }

  // only check classes which match the specified pattern
  private Predicate matchesClassPattern() {
    Pattern classPattern = Pattern.compile(rule.getClassPattern());
    return x -> classPattern.matcher(x.getName()).matches();
  }

  // check class for required annotations
  private Predicate hasRequiredAnnotation() {
    Pattern classAnnotationPattern = Pattern.compile(rule.getClassAnnotationPattern());
    return x -> {
      boolean foundMatch = false;
      for (Annotation s : x.load().getAnnotations()) {
        debug("Found annotation class '" + s.annotationType().getName() + "' on class '" + x.getName() + "'");
        if (classAnnotationPattern.matcher(s.annotationType().getName()).matches()) {
          foundMatch = true;
          break;
        }
      }
      if (!foundMatch) {
        String failMessage = String.format("Class '%s' did not have an annotation matching the pattern '%s'", x.getName(), rule.getClassAnnotationPattern());
        if (mojo.ignoreRuleFailures) {
          warn(failMessage);
        } else {
          error(failMessage);
        }
      }
      return foundMatch;
    };
  }

  private static URL[] getURLs(Collection classPathElements) {
    return classPathElements.stream().distinct().map(element -> {
      try {
        return new File(element).toURI().toURL();
      } catch (MalformedURLException e) {
        throw new AssertionError("Could not convert class path element to URL", e);
      }
    }).toArray(URL[]::new);
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy