View Javadoc
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 }