001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.apache.maven.resolver.examples.util; 020 021import java.io.IOException; 022import java.io.UncheckedIOException; 023import java.nio.charset.StandardCharsets; 024import java.nio.file.Files; 025import java.nio.file.Path; 026import java.util.ListIterator; 027import java.util.Objects; 028 029import org.eclipse.aether.AbstractRepositoryListener; 030import org.eclipse.aether.RepositoryEvent; 031import org.eclipse.aether.RequestTrace; 032import org.eclipse.aether.artifact.Artifact; 033import org.eclipse.aether.collection.CollectStepData; 034import org.eclipse.aether.graph.Dependency; 035import org.eclipse.aether.graph.DependencyNode; 036 037import static java.util.Objects.requireNonNull; 038 039/** 040 * A demo class building reverse tree using {@link CollectStepData} trace data provided in {@link RepositoryEvent} 041 * events fired during collection. 042 */ 043public class ReverseTreeRepositoryListener extends AbstractRepositoryListener { 044 private static final String EOL = System.lineSeparator(); 045 046 @Override 047 public void artifactResolved(RepositoryEvent event) { 048 requireNonNull(event, "event cannot be null"); 049 050 RequestTrace trace = event.getTrace(); 051 CollectStepData collectStepTrace = null; 052 while (trace != null) { 053 if (trace.getData() instanceof CollectStepData) { 054 collectStepTrace = (CollectStepData) trace.getData(); 055 break; 056 } 057 trace = trace.getParent(); 058 } 059 060 if (collectStepTrace == null) { 061 return; 062 } 063 064 Artifact resolvedArtifact = event.getArtifact(); 065 Artifact nodeArtifact = collectStepTrace.getNode().getArtifact(); 066 067 if (isInScope(resolvedArtifact, nodeArtifact)) { 068 Dependency node = collectStepTrace.getNode(); 069 String trackingData = node + " (" + collectStepTrace.getContext() + ")" + EOL; 070 String indent = ""; 071 ListIterator<DependencyNode> iter = collectStepTrace 072 .getPath() 073 .listIterator(collectStepTrace.getPath().size()); 074 while (iter.hasPrevious()) { 075 DependencyNode curr = iter.previous(); 076 indent += " "; 077 trackingData += indent + curr + " (" + collectStepTrace.getContext() + ")" + EOL; 078 } 079 try { 080 Path trackingDir = 081 resolvedArtifact.getFile().getParentFile().toPath().resolve(".tracking"); 082 Files.createDirectories(trackingDir); 083 Path trackingFile = trackingDir.resolve(collectStepTrace 084 .getPath() 085 .get(0) 086 .getArtifact() 087 .toString() 088 .replace(":", "_")); 089 Files.write(trackingFile, trackingData.getBytes(StandardCharsets.UTF_8)); 090 System.out.println(trackingData); 091 } catch (IOException e) { 092 throw new UncheckedIOException(e); 093 } 094 } 095 } 096 097 /** 098 * The event "artifact resolved" if fired WHENEVER an artifact is resolved, BUT it happens also when an artifact 099 * descriptor (model, the POM) is being built, and parent (and parent of parent...) is being asked for. Hence, this 100 * method "filters" out in WHICH artifact are we interested in, but it intentionally neglects extension as 101 * ArtifactDescriptorReader modifies extension to "pom" during collect. So all we have to rely on is GAV only. 102 */ 103 private boolean isInScope(Artifact artifact, Artifact nodeArtifact) { 104 return Objects.equals(artifact.getGroupId(), nodeArtifact.getGroupId()) 105 && Objects.equals(artifact.getArtifactId(), nodeArtifact.getArtifactId()) 106 && Objects.equals(artifact.getVersion(), nodeArtifact.getVersion()); 107 } 108}