/atlassian-spring-scanner-maven-plugin/src/main/java/com/atlassian/plugin/spring/scanner/maven/AtlassianSpringScannerMojo.java
Java | 287 lines | 213 code | 38 blank | 36 comment | 14 complexity | 418dfc5323d3aef74c69a25b5aca6e0c MD5 | raw file
- package com.atlassian.plugin.spring.scanner.maven;
- import com.atlassian.plugin.spring.scanner.core.AtlassianSpringByteCodeScanner;
- import com.atlassian.plugin.spring.scanner.core.ByteCodeScannerConfiguration;
- import com.google.common.base.Function;
- import com.google.common.base.Predicate;
- import com.google.common.collect.Iterables;
- import com.google.common.collect.Lists;
- import com.google.common.collect.Sets;
- import org.apache.maven.artifact.Artifact;
- import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
- import org.apache.maven.model.Dependency;
- import org.apache.maven.plugin.AbstractMojo;
- import org.apache.maven.plugin.MojoExecutionException;
- import org.apache.maven.plugin.MojoFailureException;
- import org.apache.maven.plugins.annotations.Component;
- import org.apache.maven.plugins.annotations.LifecyclePhase;
- import org.apache.maven.plugins.annotations.Mojo;
- import org.apache.maven.plugins.annotations.Parameter;
- import org.apache.maven.plugins.annotations.ResolutionScope;
- import org.apache.maven.project.MavenProject;
- import org.apache.maven.shared.dependency.graph.DependencyGraphBuilder;
- import org.apache.maven.shared.dependency.graph.DependencyGraphBuilderException;
- import org.apache.maven.shared.dependency.graph.DependencyNode;
- import org.reflections.util.ClasspathHelper;
- import javax.annotation.Nullable;
- import java.io.File;
- import java.net.MalformedURLException;
- import java.net.URL;
- import java.util.ArrayList;
- import java.util.Collections;
- import java.util.List;
- import java.util.NoSuchElementException;
- import java.util.Set;
- import java.util.stream.Collectors;
- import static java.lang.String.format;
- import static org.reflections.util.Utils.isEmpty;
- /**
- * Maven plugin for atlassian-spring-scanning.
- * <p>
- * Use it by configuring the pom with:
- * <pre><code>
- * <build>
- * <plugins>
- * <plugin>
- * <groupId>com.atlassian.plugins</groupId>
- * <artifactId>atlassian-spring-scanner-maven-plugin</artifactId>
- * <version>${project.version}#60;/version>
- * <executions>
- * <execution>
- * <goals>
- * <goal>atlassian-spring-scanner</goal>
- * </goals>
- * <phase>process-classes</phase>
- * </execution>
- * </executions>
- * <configuration>
- * <... optional configuration here>
- * </configuration>
- * </plugin>
- * </plugins>
- * </build>
- * </code></pre>
- */
- @Mojo(
- name = "atlassian-spring-scanner",
- defaultPhase = LifecyclePhase.PREPARE_PACKAGE,
- requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME
- )
- public class AtlassianSpringScannerMojo extends AbstractMojo {
- private static final String OUR_NAME = "Atlassian Spring Byte Code Scanner";
- private static final String DEFAULT_INCLUDE_EXCLUDE = "-java\\..*, -javax\\..*, -sun\\..*, -com\\.sun\\..*";
- @Parameter(defaultValue = "${project}", readonly = true)
- private MavenProject project;
- @Parameter(defaultValue = DEFAULT_INCLUDE_EXCLUDE)
- private String includeExclude;
- @Parameter(defaultValue = "false")
- private Boolean parallel;
- @Parameter(defaultValue = "false")
- private Boolean verbose;
- @Parameter()
- private List<Dependency> scannedDependencies = new ArrayList<Dependency>();
- @Component(hint = "default")
- private DependencyGraphBuilder dependencyGraphBuilder;
- public void execute() throws MojoExecutionException, MojoFailureException {
- getLog().info("Starting " + OUR_NAME + "...");
- getLog().info("");
- long then = System.currentTimeMillis();
- String outputDirectory = resolveOutputDirectory();
- if (!new File(outputDirectory).exists()) {
- getLog().warn(format("Skipping because %s was not found", outputDirectory));
- return;
- }
- warnInvalidScannedDependencies();
- ByteCodeScannerConfiguration.Builder config = ByteCodeScannerConfiguration.builder()
- .setOutputDirectory(outputDirectory)
- .setClassPathUrls(parseUrls())
- .setIncludeExclude(includeExclude)
- .setLog(makeLogger())
- .setVerbose(verbose);
- // go!
- AtlassianSpringByteCodeScanner scanner = new AtlassianSpringByteCodeScanner(config.build());
- long ms = System.currentTimeMillis() - then;
- getLog().info("");
- getLog().info(format("\tAnalysis ran in %d ms.", ms));
- getLog().info(format("\tEncountered %d total classes", scanner.getStats().getClassesEncountered()));
- getLog().info(format("\tProcessed %d annotated classes", scanner.getStats().getComponentClassesEncountered()));
- if (!scanner.getErrors().getErrorsEncountered().isEmpty()) {
- final String error = format("\t %d errors encountered during class analysis: \n\t %s",
- scanner.getErrors().getErrorsEncountered().size(),
- scanner.getErrors().getErrorsEncountered().stream().collect(Collectors.joining("\n\t")));
- getLog().error(error);
- throw new IllegalStateException(error);
- }
- }
- private org.slf4j.Logger makeLogger() {
- return new MavenLogAdapter(getLog());
- }
- private Set<URL> parseUrls() throws MojoExecutionException {
- final Set<URL> urls = Sets.newHashSet();
- URL outputDirUrl = parseOutputDirUrl();
- urls.add(outputDirUrl);
- if (!isEmpty(includeExclude)) {
- for (String string : includeExclude.split(",")) {
- String trimmed = string.trim();
- char prefix = trimmed.charAt(0);
- String pattern = trimmed.substring(1);
- if (prefix == '+') {
- logVerbose(format("\tAdding include / exclude %s", prefix));
- urls.addAll(ClasspathHelper.forPackage(pattern));
- }
- }
- }
- final Set<URL> dependencyJars = Sets.newLinkedHashSet();
- final Iterable<Artifact> projectArtifacts = getProjectArtifacts();
- final Iterable<Artifact> scannedArtifacts = resolveArtifacts(getScannedArtifacts(), projectArtifacts);
- final Iterable<Artifact> ignoredArtifacts = Iterables.filter(projectArtifacts, new Predicate<Artifact>() {
- @Override
- public boolean apply(@Nullable Artifact input) {
- return !Iterables.any(scannedArtifacts, artifactMatchesGAV(input));
- }
- });
- for (Artifact artifact : scannedArtifacts) {
- logVerbose(format("\t(/) Including dependency for scanning %s:%s:%s", artifact.getGroupId(), artifact.getArtifactId(), artifact.getScope()));
- File file = artifact.getFile();
- try {
- URL url = file.toURI().toURL();
- dependencyJars.add(url);
- } catch (MalformedURLException e) {
- getLog().warn(format("Enable to create URL from plugin artifact : %s", file), e);
- }
- }
- for (Artifact artifact : ignoredArtifacts) {
- logVerbose(format("\t(X) Ignoring dependency for scanning %s:%s:%s", artifact.getGroupId(), artifact.getArtifactId(), artifact.getScope()));
- }
- urls.addAll(dependencyJars);
- getLog().info("\t(/) The following directory will be scanned for annotations :");
- getLog().info(format("\t\t%s", outputDirUrl));
- if (dependencyJars.size() > 0) {
- getLog().info("");
- getLog().info("\t(/) The following dependencies will also be scanned for annotations : ");
- getLog().info("");
- for (URL jar : dependencyJars) {
- getLog().info(format("\t\t%s", jar));
- }
- }
- return urls;
- }
- private void logVerbose(String message) {
- if (verbose) {
- getLog().info(message);
- }
- }
- private boolean isSensibleScope(final Artifact artifact) {
- return !Artifact.SCOPE_TEST.equals(artifact.getScope());
- }
- private URL parseOutputDirUrl() throws MojoExecutionException {
- try {
- File outputDirectoryFile = new File(resolveOutputDirectory() + '/');
- return outputDirectoryFile.toURI().toURL();
- } catch (MalformedURLException e) {
- throw new MojoExecutionException(e.getMessage(), e);
- }
- }
- private String resolveOutputDirectory() {
- return getProject().getBuild().getOutputDirectory();
- }
- private MavenProject getProject() {
- return project;
- }
- private Predicate<Artifact> artifactMatchesGAV(final Artifact artifact) {
- return new Predicate<Artifact>() {
- @Override
- public boolean apply(final Artifact input) {
- return artifact.getGroupId().equals(input.getGroupId()) &&
- artifact.getArtifactId().equals(input.getArtifactId()) &&
- artifact.getVersion().equals(input.getVersion()
- );
- }
- };
- }
- /**
- * The artifacts in the project list are resolved, the scanned ones are not but rather are logical and hence we
- * have to make them real
- *
- * @param scannedArtifacts the GA artifacts we want scanned
- * @param projectArtifacts the resolved list including the above
- * @return resolved versions of the artifacts
- */
- private Iterable<Artifact> resolveArtifacts(List<Artifact> scannedArtifacts, final Iterable<Artifact> projectArtifacts) {
- return Iterables.transform(scannedArtifacts, new Function<Artifact, Artifact>() {
- @Override
- public Artifact apply(Artifact input) {
- try {
- return Iterables.find(projectArtifacts, artifactMatchesGAV(input));
- } catch (NoSuchElementException e) {
- throw new RuntimeException("Unable to find " + input, e);
- }
- }
- });
- }
- private DependencyNode getDependencyGraph(MavenProject project) {
- try {
- return dependencyGraphBuilder.buildDependencyGraph(project, new ArtifactFilter() {
- @Override
- public boolean include(Artifact artifact) {
- return isSensibleScope(artifact);
- }
- });
- } catch (DependencyGraphBuilderException e) {
- throw new RuntimeException(e);
- }
- }
- private List<Artifact> getProjectArtifacts() {
- ArrayList<Artifact> artifacts = Lists.newArrayList(project.getArtifacts());
- Collections.sort(artifacts);
- return artifacts;
- }
- private List<Artifact> getScannedArtifacts() {
- DependencyNode dependencyGraph = getDependencyGraph(project);
- return ScannedDependencyArtifactBuilder.buildScannedArtifacts(dependencyGraph, scannedDependencies);
- }
- private void warnInvalidScannedDependencies() {
- for (Dependency dependency : scannedDependencies) {
- if ((dependency.getArtifactId().contains("*")) && (!"*".equals(dependency.getArtifactId()))) {
- getLog().warn(format("Invalid artifact ID %s in scannedDependencies. Partial wildcards are not currently supported.", dependency.getArtifactId()));
- }
- }
- }
- }