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 repository The repository the exception occurred with, may be {@code null}.
163 * @param exception The exception to record, may be {@code null}.
164 * @return This result for chaining, never {@code null}.
165 * @since 2.0.0
166 */
167 public ArtifactResult addException(ArtifactRepository repository, Exception exception) {
168 if (repository != null && exception != null) {
169 exceptions
170 .computeIfAbsent(repository, k -> new CopyOnWriteArrayList<>())
171 .add(exception);
172 }
173 return this;
174 }
175
176 /**
177 * Gets the repository from which the artifact was eventually resolved. Note that successive resolutions of the same
178 * artifact might yield different results if the employed local repository does not track the origin of an artifact.
179 *
180 * @return The repository from which the artifact was resolved or {@code null} if unknown.
181 */
182 public ArtifactRepository getRepository() {
183 return repository;
184 }
185
186 /**
187 * Sets the repository from which the artifact was resolved.
188 *
189 * @param repository The repository from which the artifact was resolved, may be {@code null}.
190 * @return This result for chaining, never {@code null}.
191 */
192 public ArtifactResult setRepository(ArtifactRepository repository) {
193 this.repository = repository;
194 return this;
195 }
196
197 /**
198 * Gets the {@link LocalArtifactResult} received during artifact resolution.
199 *
200 * @return The {@link LocalArtifactResult} or {@code null}.
201 * @since 1.9.6
202 */
203 public LocalArtifactResult getLocalArtifactResult() {
204 return localArtifactResult;
205 }
206
207 /**
208 * Sets the {@link LocalArtifactResult} that is received during artifact resolution.
209 *
210 * @param localArtifactResult The local artifact result.
211 * @since 1.9.6
212 */
213 public void setLocalArtifactResult(LocalArtifactResult localArtifactResult) {
214 this.localArtifactResult = localArtifactResult;
215 }
216
217 /**
218 * Indicates whether the requested artifact was resolved. Note that the artifact might have been successfully
219 * resolved despite {@link #getExceptions()} indicating transfer errors while trying to fetch the artifact from some
220 * of the specified remote repositories.
221 *
222 * @return {@code true} if the artifact was resolved, {@code false} otherwise.
223 * @see Artifact#getPath()
224 */
225 public boolean isResolved() {
226 return getArtifact() != null && getArtifact().getPath() != null;
227 }
228
229 /**
230 * Indicates whether the requested artifact is not present in any of the specified repositories.
231 *
232 * @return {@code true} if the artifact is not present in any repository, {@code false} otherwise.
233 */
234 public boolean isMissing() {
235 for (Exception e : getExceptions()) {
236 if (!(e instanceof ArtifactNotFoundException)) {
237 return false;
238 }
239 }
240 return !isResolved();
241 }
242
243 @Override
244 public String toString() {
245 return getArtifact() + " < " + getRepository();
246 }
247 }