001package org.eclipse.aether.collection;
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.Collection;
023import java.util.Collections;
024import java.util.Iterator;
025import java.util.LinkedHashSet;
026import java.util.List;
027
028import org.eclipse.aether.RepositoryException;
029import org.eclipse.aether.artifact.Artifact;
030import org.eclipse.aether.graph.DependencyNode;
031import org.eclipse.aether.version.VersionConstraint;
032
033/**
034 * Thrown in case of an unsolvable conflict between different version constraints for a dependency.
035 */
036public class UnsolvableVersionConflictException
037    extends RepositoryException
038{
039
040    private final transient Collection<String> versions;
041
042    private final transient Collection<? extends List<? extends DependencyNode>> paths;
043
044    /**
045     * Creates a new exception with the specified paths to conflicting nodes in the dependency graph.
046     * 
047     * @param paths The paths to the dependency nodes that participate in the version conflict, may be {@code null}.
048     */
049    public UnsolvableVersionConflictException( Collection<? extends List<? extends DependencyNode>> paths )
050    {
051        super( "Could not resolve version conflict among " + toPaths( paths ) );
052        if ( paths == null )
053        {
054            this.paths = Collections.emptyList();
055            this.versions = Collections.emptyList();
056        }
057        else
058        {
059            this.paths = paths;
060            this.versions = new LinkedHashSet<String>();
061            for ( List<? extends DependencyNode> path : paths )
062            {
063                VersionConstraint constraint = path.get( path.size() - 1 ).getVersionConstraint();
064                if ( constraint != null && constraint.getRange() != null )
065                {
066                    versions.add( constraint.toString() );
067                }
068            }
069        }
070    }
071
072    private static String toPaths( Collection<? extends List<? extends DependencyNode>> paths )
073    {
074        String result = "";
075
076        if ( paths != null )
077        {
078            Collection<String> strings = new LinkedHashSet<String>();
079
080            for ( List<? extends DependencyNode> path : paths )
081            {
082                strings.add( toPath( path ) );
083            }
084
085            result = strings.toString();
086        }
087
088        return result;
089    }
090
091    private static String toPath( List<? extends DependencyNode> path )
092    {
093        StringBuilder buffer = new StringBuilder( 256 );
094
095        for ( Iterator<? extends DependencyNode> it = path.iterator(); it.hasNext(); )
096        {
097            DependencyNode node = it.next();
098            if ( node.getDependency() == null )
099            {
100                continue;
101            }
102
103            Artifact artifact = node.getDependency().getArtifact();
104            buffer.append( artifact.getGroupId() );
105            buffer.append( ':' ).append( artifact.getArtifactId() );
106            buffer.append( ':' ).append( artifact.getExtension() );
107            if ( artifact.getClassifier().length() > 0 )
108            {
109                buffer.append( ':' ).append( artifact.getClassifier() );
110            }
111            buffer.append( ':' ).append( node.getVersionConstraint() );
112
113            if ( it.hasNext() )
114            {
115                buffer.append( " -> " );
116            }
117        }
118
119        return buffer.toString();
120    }
121
122    /**
123     * Gets the paths leading to the conflicting dependencies.
124     * 
125     * @return The (read-only) paths leading to the conflicting dependencies, never {@code null}.
126     */
127    public Collection<? extends List<? extends DependencyNode>> getPaths()
128    {
129        return paths;
130    }
131
132    /**
133     * Gets the conflicting version constraints of the dependency.
134     * 
135     * @return The (read-only) conflicting version constraints, never {@code null}.
136     */
137    public Collection<String> getVersions()
138    {
139        return versions;
140    }
141
142}