Java tutorial
/* * Copyright 2015 Jose Carrizo * Licensed under the Apache License, Version 2.0 * See accompanying file LICENSE or get a copy at http://www.apache.org/licenses/LICENSE-2.0 */ package org.automagic.deps.doctor.spy; import java.io.BufferedReader; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.maven.artifact.Artifact; import org.apache.maven.artifact.factory.ArtifactFactory; import org.apache.maven.artifact.metadata.ArtifactMetadataSource; import org.apache.maven.artifact.repository.ArtifactRepository; import org.apache.maven.artifact.resolver.ArtifactCollector; import org.apache.maven.artifact.resolver.filter.ArtifactFilter; import org.apache.maven.artifact.versioning.ArtifactVersion; import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException; import org.apache.maven.artifact.versioning.OverConstrainedVersionException; import org.apache.maven.artifact.versioning.VersionRange; import org.apache.maven.project.MavenProject; import org.apache.maven.shared.dependency.tree.DependencyNode; import org.apache.maven.shared.dependency.tree.DependencyTreeBuilder; import org.apache.maven.shared.dependency.tree.DependencyTreeBuilderException; import org.automagic.deps.doctor.TransitiveDependency; import org.automagic.deps.doctor.TransitiveDepsGroup; import org.automagic.deps.doctor.Utils; import org.w3c.dom.Document; import org.w3c.dom.Node; import com.google.common.base.Optional; public class PomSpyImpl implements PomSpy { private final MavenProject project; private final ArtifactRepository repository; private final ArtifactFactory factory; private final ArtifactMetadataSource metadataSource; private final ArtifactCollector collector; private final DependencyTreeBuilder treeBuilder; private final Document document; private final boolean useParent; public PomSpyImpl(MavenProject project, ArtifactRepository repository, ArtifactFactory factory, ArtifactMetadataSource metadataSource, ArtifactCollector collector, DependencyTreeBuilder treeBuilder, boolean useParent) { this.project = project; this.repository = repository; this.factory = factory; this.metadataSource = metadataSource; this.collector = collector; this.treeBuilder = treeBuilder; this.useParent = useParent; this.document = Utils.getDocument(project.getFile()); } @Override public List<TransitiveDepsGroup> getTransitiveDepsGroups() { try { ArtifactFilter filter = null; // evaluate all scopes DependencyNode rootNode = treeBuilder.buildDependencyTree(project, repository, factory, metadataSource, filter, collector); ForceUpperBoundsDepsVisitor visitor = new ForceUpperBoundsDepsVisitor(); rootNode.accept(visitor); List<List<DependencyNodeHopCountPair>> dependenciesList = visitor.getAllDependencies(); if (dependenciesList.isEmpty()) { return Collections.emptyList(); } List<TransitiveDepsGroup> groupsList = new ArrayList<>(); for (List<DependencyNodeHopCountPair> pairsList : dependenciesList) { TransitiveDepsGroup group = new TransitiveDepsGroup(); groupsList.add(group); for (DependencyNodeHopCountPair pair : pairsList) { Artifact artifact = pair.getNode().getArtifact(); ArtifactVersion version = pair.extractArtifactVersion(true); ArtifactVersion managedVersion = pair.extractArtifactVersion(false); int hopCount = pair.getHopCount(); boolean wasAddedByPlugin = Utils.getPluginComment("/project", artifact, document).isPresent(); TransitiveDependency dependency = new TransitiveDependency(artifact, version, managedVersion, hopCount, pair.getNode(), wasAddedByPlugin); group.add(dependency); } } return groupsList; } catch (DependencyTreeBuilderException e) { throw new RuntimeException(e); } } @Override public boolean isBrandNew(TransitiveDependency dependency) { return !Utils.getDependencyNode(dependency.getArtifact(), document, "/project/dependencies").isPresent(); } @Override public Optional<String> getVersion(TransitiveDependency dependency) { Optional<Node> dependencyNode = Utils.getDependencyNode(dependency.getArtifact(), document, "/project/dependencies"); if (!dependencyNode.isPresent()) { return Optional.absent(); } Optional<Node> versionNode = Utils.getNode("./version", dependencyNode.get()); if (versionNode.isPresent()) { return Optional.of(versionNode.get().getTextContent().trim()); } return Optional.absent(); } @Override public Optional<String> getVersionPropertyName(String version) { Matcher matcher = Pattern.compile("\\s*\\$\\{([^}]+)\\}\\s*").matcher(version); if (matcher.matches()) { String name = matcher.group(1); return Optional.of(name); } return Optional.absent(); } @Override public boolean hasXmlDeclaration() { try (InputStream fileInput = new FileInputStream(project.getFile()); Reader streamReader = new InputStreamReader(fileInput); BufferedReader reader = new BufferedReader(streamReader)) { for (int i = 0; i < 3; i++) { String line = reader.readLine(); if (line == null) { break; } if (line.trim().startsWith("<?xml")) { return true; } } return false; } catch (IOException e) { throw new RuntimeException(e); } } @Override public boolean isParentAvailable() { if (!useParent) { return false; } boolean parentPomIsAvailable = project.getParent() != null && project.getParent().getFile() != null && project.getParent().getFile().exists(); return parentPomIsAvailable; } @Override public PomSpy getParentSpy() { return new PomSpyImpl(project.getParent(), repository, factory, metadataSource, collector, treeBuilder, useParent); } @Override public boolean hasDepsManagement() { return Utils.getNode("/project/dependencyManagement", document).isPresent(); } @Override public boolean isManaged(TransitiveDependency dependency) { if (project.getDependencyManagement() == null || project.getDependencyManagement().getDependencies() == null) { return false; } return Utils .getDependencyNode(dependency.getArtifact(), document, "/project/dependencyManagement/dependencies") .isPresent(); } @Override public String getManagedVersion(TransitiveDependency dependency) { Optional<Node> dependencyNode = Utils.getDependencyNode(dependency.getArtifact(), document, "/project/dependencyManagement/dependencies"); Optional<Node> versionNode = Utils.getNode("./version", dependencyNode.get()); return versionNode.get().getTextContent().trim(); } @Override public boolean isLowerThanCurrent(TransitiveDependency dependency) { try { Optional<Node> dependencyNode = Utils.getDependencyNode(dependency.getArtifact(), document, "/project/dependencies"); if (dependencyNode.isPresent()) { Optional<Node> currentVersionNode = Utils.getNode("./version", dependencyNode.get()); if (currentVersionNode.isPresent()) { return isLowerThanCurrent(dependency, currentVersionNode); } } Optional<Node> managedDependencyNode = Utils.getDependencyNode(dependency.getArtifact(), document, "/project/dependencyManagement/dependencies"); if (managedDependencyNode.isPresent()) { Optional<Node> currentVersionNode = Utils.getNode("./version", managedDependencyNode.get()); if (currentVersionNode.isPresent()) { return isLowerThanCurrent(dependency, currentVersionNode); } } return false; } catch (InvalidVersionSpecificationException | OverConstrainedVersionException e) { throw new RuntimeException(e); } } @SuppressWarnings("unchecked") private boolean isLowerThanCurrent(TransitiveDependency newDependency, Optional<Node> currentVersionNode) throws InvalidVersionSpecificationException, OverConstrainedVersionException { String version = currentVersionNode.get().getTextContent().trim(); Optional<String> propertyName = getVersionPropertyName(version); if (propertyName.isPresent()) { Optional<Node> propertyNode = Utils.getNode("/project/properties/" + propertyName.get(), document); if (!propertyNode.isPresent()) { return false; } version = propertyNode.get().getTextContent().trim(); } VersionRange versionRange = VersionRange.createFromVersionSpec(version); ArtifactVersion currentVersion = versionRange.getSelectedVersion(newDependency.getArtifact()); int result = newDependency.getVersion().compareTo(currentVersion); return result < 0; } MavenProject getProject() { return project; } }