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.eclipse.aether.resolution;
020
021import java.util.Collections;
022import java.util.List;
023
024import org.eclipse.aether.RepositoryException;
025import org.eclipse.aether.repository.LocalArtifactResult;
026import org.eclipse.aether.transfer.ArtifactFilteredOutException;
027import org.eclipse.aether.transfer.ArtifactNotFoundException;
028import org.eclipse.aether.transfer.RepositoryOfflineException;
029
030/**
031 * Thrown in case of a unresolvable artifacts.
032 */
033public class ArtifactResolutionException extends RepositoryException {
034
035    private final transient List<ArtifactResult> results;
036
037    /**
038     * Creates a new exception with the specified results.
039     *
040     * @param results The resolution results at the point the exception occurred, may be {@code null}.
041     */
042    public ArtifactResolutionException(List<ArtifactResult> results) {
043        super(getMessage(results), getCause(results));
044        this.results = (results != null) ? results : Collections.<ArtifactResult>emptyList();
045    }
046
047    /**
048     * Creates a new exception with the specified results and detail message.
049     *
050     * @param results The resolution results at the point the exception occurred, may be {@code null}.
051     * @param message The detail message, may be {@code null}.
052     */
053    public ArtifactResolutionException(List<ArtifactResult> results, String message) {
054        super(message, getCause(results));
055        this.results = (results != null) ? results : Collections.<ArtifactResult>emptyList();
056    }
057
058    /**
059     * Creates a new exception with the specified results, detail message and cause.
060     *
061     * @param results The resolution results at the point the exception occurred, may be {@code null}.
062     * @param message The detail message, may be {@code null}.
063     * @param cause The exception that caused this one, may be {@code null}.
064     */
065    public ArtifactResolutionException(List<ArtifactResult> results, String message, Throwable cause) {
066        super(message, cause);
067        this.results = (results != null) ? results : Collections.<ArtifactResult>emptyList();
068    }
069
070    /**
071     * Gets the resolution results at the point the exception occurred. Despite being incomplete, callers might want to
072     * use these results to fail gracefully and continue their operation with whatever interim data has been gathered.
073     *
074     * @return The resolution results or {@code null} if unknown.
075     */
076    public List<ArtifactResult> getResults() {
077        return results;
078    }
079
080    /**
081     * Gets the first result from {@link #getResults()}. This is a convenience method for cases where callers know only
082     * a single result/request is involved.
083     *
084     * @return The (first) resolution result or {@code null} if none.
085     */
086    public ArtifactResult getResult() {
087        return (results != null && !results.isEmpty()) ? results.get(0) : null;
088    }
089
090    private static String getMessage(List<? extends ArtifactResult> results) {
091        StringBuilder buffer = new StringBuilder(256);
092
093        buffer.append("The following artifacts could not be resolved: ");
094
095        String sep = "";
096        for (ArtifactResult result : results) {
097            if (!result.isResolved()) {
098                buffer.append(sep);
099                buffer.append(result.getRequest().getArtifact());
100                LocalArtifactResult localResult = result.getLocalArtifactResult();
101                if (localResult != null) {
102                    buffer.append(" (");
103                    if (localResult.getFile() != null) {
104                        buffer.append("present");
105                        if (!localResult.isAvailable()) {
106                            buffer.append(", but unavailable");
107                        }
108                    } else {
109                        buffer.append("absent");
110                    }
111                    buffer.append(")");
112                }
113                sep = ", ";
114            }
115        }
116
117        Throwable cause = getCause(results);
118        if (cause != null) {
119            buffer.append(": ").append(cause.getMessage());
120        }
121
122        return buffer.toString();
123    }
124
125    private static Throwable getCause(List<? extends ArtifactResult> results) {
126        for (ArtifactResult result : results) {
127            if (!result.isResolved()) {
128                Throwable notFound = null, offline = null;
129                for (Throwable t : result.getExceptions()) {
130                    if (t instanceof ArtifactNotFoundException) {
131                        if (notFound == null || notFound instanceof ArtifactFilteredOutException) {
132                            notFound = t;
133                        }
134                        if (offline == null && t.getCause() instanceof RepositoryOfflineException) {
135                            offline = t;
136                        }
137                    } else {
138                        return t;
139                    }
140                }
141                if (offline != null) {
142                    return offline;
143                }
144                if (notFound != null) {
145                    return notFound;
146                }
147            }
148        }
149        return null;
150    }
151}