1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, 13 * software distributed under the License is distributed on an 14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 * KIND, either express or implied. See the License for the 16 * specific language governing permissions and limitations 17 * under the License. 18 */ 19 package org.eclipse.aether.resolution; 20 21 import java.util.*; 22 import java.util.concurrent.ConcurrentHashMap; 23 import java.util.concurrent.CopyOnWriteArrayList; 24 25 import org.eclipse.aether.RepositorySystem; 26 import org.eclipse.aether.artifact.Artifact; 27 import org.eclipse.aether.repository.ArtifactRepository; 28 import org.eclipse.aether.repository.LocalArtifactResult; 29 import org.eclipse.aether.transfer.ArtifactNotFoundException; 30 31 import static java.util.Objects.requireNonNull; 32 33 /** 34 * The result of an artifact resolution request. 35 * 36 * @see RepositorySystem#resolveArtifacts(org.eclipse.aether.RepositorySystemSession, java.util.Collection) 37 * @see Artifact#getFile() 38 */ 39 public final class ArtifactResult { 40 41 /** 42 * A sentinel object, that is used as key for exceptions that had no related repository during resolution. 43 * 44 * @since 2.0.0 45 */ 46 public static final ArtifactRepository NO_REPOSITORY = new NoRepository(); 47 48 private static final class NoRepository implements ArtifactRepository { 49 50 private NoRepository() {} 51 52 public String getContentType() { 53 return "unknown"; 54 } 55 56 public String getId() { 57 return "unknown"; 58 } 59 60 @Override 61 public String toString() { 62 return getId(); 63 } 64 } 65 66 private final ArtifactRequest request; 67 68 private final Map<ArtifactRepository, List<Exception>> exceptions; 69 70 private Artifact artifact; 71 72 private ArtifactRepository repository; 73 74 private LocalArtifactResult localArtifactResult; 75 76 /** 77 * Creates a new result for the specified request. 78 * 79 * @param request The resolution request, must not be {@code null}. 80 */ 81 public ArtifactResult(ArtifactRequest request) { 82 this.request = requireNonNull(request, "artifact request cannot be null"); 83 this.exceptions = new ConcurrentHashMap<>(); 84 } 85 86 /** 87 * Gets the resolution request that was made. 88 * 89 * @return The resolution request, never {@code null}. 90 */ 91 public ArtifactRequest getRequest() { 92 return request; 93 } 94 95 /** 96 * Gets the resolved artifact (if any). Use {@link #getExceptions()} to query the errors that occurred while trying 97 * to resolve the artifact. 98 * 99 * @return The resolved artifact or {@code null} if the resolution failed. 100 */ 101 public Artifact getArtifact() { 102 return artifact; 103 } 104 105 /** 106 * Sets the resolved artifact. 107 * 108 * @param artifact The resolved artifact, may be {@code null} if the resolution failed. 109 * @return This result for chaining, never {@code null}. 110 */ 111 public ArtifactResult setArtifact(Artifact artifact) { 112 this.artifact = artifact; 113 return this; 114 } 115 116 /** 117 * Gets the exceptions that occurred while resolving the artifact. Note that this list can be non-empty even if the 118 * artifact was successfully resolved, e.g. when one of the contacted remote repositories didn't contain the 119 * artifact but a later repository eventually contained it. 120 * 121 * @return The exceptions that occurred, never {@code null}. 122 * @see #isResolved() 123 * @see #isMissing() 124 */ 125 public List<Exception> getExceptions() { 126 ArrayList<Exception> result = new ArrayList<>(); 127 exceptions.values().forEach(result::addAll); 128 return result; 129 } 130 131 /** 132 * Gets the exceptions that occurred while resolving the artifact. Note that this map can be non-empty even if the 133 * artifact was successfully resolved, e.g. when one of the contacted remote repositories didn't contain the 134 * artifact but a later repository eventually contained it. 135 * 136 * @return Map of exceptions per repository, that occurred during resolution, never {@code null}. 137 * @see #isResolved() 138 * @see #isMissing() 139 * @since 2.0.0 140 */ 141 public Map<ArtifactRepository, List<Exception>> getMappedExceptions() { 142 return exceptions; 143 } 144 145 /** 146 * Records the specified exception while resolving the artifact. 147 * 148 * @param exception The exception to record, may be {@code null}. 149 * @return This result for chaining, never {@code null}. 150 * @deprecated Use {@link #addException(ArtifactRepository, Exception)} method instead. 151 */ 152 @Deprecated 153 public ArtifactResult addException(Exception exception) { 154 return addException(NO_REPOSITORY, exception); 155 } 156 157 /** 158 * Records the specified exception while resolving the artifact. 159 * 160 * @param exception The exception to record, may be {@code null}. 161 * @return This result for chaining, never {@code null}. 162 * @since 2.0.0 163 */ 164 public ArtifactResult addException(ArtifactRepository repository, Exception exception) { 165 if (repository != null && exception != null) { 166 exceptions 167 .computeIfAbsent(repository, k -> new CopyOnWriteArrayList<>()) 168 .add(exception); 169 } 170 return this; 171 } 172 173 /** 174 * Gets the repository from which the artifact was eventually resolved. Note that successive resolutions of the same 175 * artifact might yield different results if the employed local repository does not track the origin of an artifact. 176 * 177 * @return The repository from which the artifact was resolved or {@code null} if unknown. 178 */ 179 public ArtifactRepository getRepository() { 180 return repository; 181 } 182 183 /** 184 * Sets the repository from which the artifact was resolved. 185 * 186 * @param repository The repository from which the artifact was resolved, may be {@code null}. 187 * @return This result for chaining, never {@code null}. 188 */ 189 public ArtifactResult setRepository(ArtifactRepository repository) { 190 this.repository = repository; 191 return this; 192 } 193 194 /** 195 * Gets the {@link LocalArtifactResult} received during artifact resolution. 196 * 197 * @return The {@link LocalArtifactResult} or {@code null}. 198 * @since 1.9.6 199 */ 200 public LocalArtifactResult getLocalArtifactResult() { 201 return localArtifactResult; 202 } 203 204 /** 205 * Sets the {@link LocalArtifactResult} that is received during artifact resolution. 206 * 207 * @param localArtifactResult The local artifact result. 208 * @since 1.9.6 209 */ 210 public void setLocalArtifactResult(LocalArtifactResult localArtifactResult) { 211 this.localArtifactResult = localArtifactResult; 212 } 213 214 /** 215 * Indicates whether the requested artifact was resolved. Note that the artifact might have been successfully 216 * resolved despite {@link #getExceptions()} indicating transfer errors while trying to fetch the artifact from some 217 * of the specified remote repositories. 218 * 219 * @return {@code true} if the artifact was resolved, {@code false} otherwise. 220 * @see Artifact#getFile() 221 */ 222 public boolean isResolved() { 223 return getArtifact() != null && getArtifact().getFile() != null; 224 } 225 226 /** 227 * Indicates whether the requested artifact is not present in any of the specified repositories. 228 * 229 * @return {@code true} if the artifact is not present in any repository, {@code false} otherwise. 230 */ 231 public boolean isMissing() { 232 for (Exception e : getExceptions()) { 233 if (!(e instanceof ArtifactNotFoundException)) { 234 return false; 235 } 236 } 237 return !isResolved(); 238 } 239 240 @Override 241 public String toString() { 242 return getArtifact() + " < " + getRepository(); 243 } 244 }