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