001package org.eclipse.aether.resolution;
002
003/*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements.  See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership.  The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License.  You may obtain a copy of the License at
011 * 
012 *  http://www.apache.org/licenses/LICENSE-2.0
013 * 
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied.  See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022import java.util.Collections;
023import java.util.List;
024
025import org.eclipse.aether.RepositoryException;
026import org.eclipse.aether.transfer.ArtifactNotFoundException;
027import org.eclipse.aether.transfer.RepositoryOfflineException;
028
029/**
030 * Thrown in case of a unresolvable artifacts.
031 */
032public class ArtifactResolutionException
033    extends RepositoryException
034{
035
036    private final transient List<ArtifactResult> results;
037
038    /**
039     * Creates a new exception with the specified results.
040     * 
041     * @param results The resolution results at the point the exception occurred, may be {@code null}.
042     */
043    public ArtifactResolutionException( List<ArtifactResult> results )
044    {
045        super( getMessage( results ), getCause( results ) );
046        this.results = ( results != null ) ? results : Collections.<ArtifactResult>emptyList();
047    }
048
049    /**
050     * Creates a new exception with the specified results and detail message.
051     * 
052     * @param results The resolution results at the point the exception occurred, may be {@code null}.
053     * @param message The detail message, may be {@code null}.
054     */
055    public ArtifactResolutionException( List<ArtifactResult> results, String message )
056    {
057        super( message, getCause( results ) );
058        this.results = ( results != null ) ? results : Collections.<ArtifactResult>emptyList();
059    }
060
061    /**
062     * Creates a new exception with the specified results, detail message and cause.
063     * 
064     * @param results The resolution results at the point the exception occurred, may be {@code null}.
065     * @param message The detail message, may be {@code null}.
066     * @param cause The exception that caused this one, may be {@code null}.
067     */
068    public ArtifactResolutionException( List<ArtifactResult> results, String message, Throwable cause )
069    {
070        super( message, cause );
071        this.results = ( results != null ) ? results : Collections.<ArtifactResult>emptyList();
072    }
073
074    /**
075     * Gets the resolution results at the point the exception occurred. Despite being incomplete, callers might want to
076     * use these results to fail gracefully and continue their operation with whatever interim data has been gathered.
077     * 
078     * @return The resolution results or {@code null} if unknown.
079     */
080    public List<ArtifactResult> getResults()
081    {
082        return results;
083    }
084
085    /**
086     * Gets the first result from {@link #getResults()}. This is a convenience method for cases where callers know only
087     * a single result/request is involved.
088     * 
089     * @return The (first) resolution result or {@code null} if none.
090     */
091    public ArtifactResult getResult()
092    {
093        return ( results != null && !results.isEmpty() ) ? results.get( 0 ) : null;
094    }
095
096    private static String getMessage( List<? extends ArtifactResult> results )
097    {
098        StringBuilder buffer = new StringBuilder( 256 );
099
100        buffer.append( "The following artifacts could not be resolved: " );
101
102        int unresolved = 0;
103
104        String sep = "";
105        for ( ArtifactResult result : results )
106        {
107            if ( !result.isResolved() )
108            {
109                unresolved++;
110
111                buffer.append( sep );
112                buffer.append( result.getRequest().getArtifact() );
113                sep = ", ";
114            }
115        }
116
117        Throwable cause = getCause( results );
118        if ( cause != null )
119        {
120            if ( unresolved == 1 )
121            {
122                buffer.setLength( 0 );
123                buffer.append( cause.getMessage() );
124            }
125            else
126            {
127                buffer.append( ": " ).append( cause.getMessage() );
128            }
129        }
130
131        return buffer.toString();
132    }
133
134    private static Throwable getCause( List<? extends ArtifactResult> results )
135    {
136        for ( ArtifactResult result : results )
137        {
138            if ( !result.isResolved() )
139            {
140                Throwable notFound = null, offline = null;
141                for ( Throwable t : result.getExceptions() )
142                {
143                    if ( t instanceof ArtifactNotFoundException )
144                    {
145                        if ( notFound == null )
146                        {
147                            notFound = t;
148                        }
149                        if ( offline == null && t.getCause() instanceof RepositoryOfflineException )
150                        {
151                            offline = t;
152                        }
153                    }
154                    else
155                    {
156                        return t;
157                    }
158
159                }
160                if ( offline != null )
161                {
162                    return offline;
163                }
164                if ( notFound != null )
165                {
166                    return notFound;
167                }
168            }
169        }
170        return null;
171    }
172
173}